Merge git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth
This commit is contained in:
Коммит
53730107b2
|
@ -90,7 +90,6 @@ static const struct usb_device_id ath3k_table[] = {
|
||||||
{ USB_DEVICE(0x0b05, 0x17d0) },
|
{ USB_DEVICE(0x0b05, 0x17d0) },
|
||||||
{ USB_DEVICE(0x0CF3, 0x0036) },
|
{ USB_DEVICE(0x0CF3, 0x0036) },
|
||||||
{ USB_DEVICE(0x0CF3, 0x3004) },
|
{ USB_DEVICE(0x0CF3, 0x3004) },
|
||||||
{ USB_DEVICE(0x0CF3, 0x3005) },
|
|
||||||
{ USB_DEVICE(0x0CF3, 0x3008) },
|
{ USB_DEVICE(0x0CF3, 0x3008) },
|
||||||
{ USB_DEVICE(0x0CF3, 0x311D) },
|
{ USB_DEVICE(0x0CF3, 0x311D) },
|
||||||
{ USB_DEVICE(0x0CF3, 0x311E) },
|
{ USB_DEVICE(0x0CF3, 0x311E) },
|
||||||
|
@ -140,7 +139,6 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
|
||||||
{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
|
||||||
{ USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 },
|
||||||
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
|
||||||
{ USB_DEVICE(0x0cf3, 0x3005), .driver_info = BTUSB_ATH3012 },
|
|
||||||
{ USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
|
||||||
{ USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 },
|
||||||
{ USB_DEVICE(0x0cf3, 0x311E), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x0cf3, 0x311E), .driver_info = BTUSB_ATH3012 },
|
||||||
|
|
|
@ -162,7 +162,6 @@ static const struct usb_device_id blacklist_table[] = {
|
||||||
{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
|
||||||
{ USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
|
||||||
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
|
||||||
{ USB_DEVICE(0x0cf3, 0x3005), .driver_info = BTUSB_ATH3012 },
|
|
||||||
{ USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
|
||||||
{ USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
|
||||||
{ USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 },
|
{ USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 },
|
||||||
|
|
|
@ -406,6 +406,7 @@ static int h5_rx_3wire_hdr(struct hci_uart *hu, unsigned char c)
|
||||||
H5_HDR_PKT_TYPE(hdr) != HCI_3WIRE_LINK_PKT) {
|
H5_HDR_PKT_TYPE(hdr) != HCI_3WIRE_LINK_PKT) {
|
||||||
BT_ERR("Non-link packet received in non-active state");
|
BT_ERR("Non-link packet received in non-active state");
|
||||||
h5_reset_rx(h5);
|
h5_reset_rx(h5);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
h5->rx_func = h5_rx_payload;
|
h5->rx_func = h5_rx_payload;
|
||||||
|
|
|
@ -36,7 +36,7 @@ config B43_SSB
|
||||||
choice
|
choice
|
||||||
prompt "Supported bus types"
|
prompt "Supported bus types"
|
||||||
depends on B43
|
depends on B43
|
||||||
default B43_BCMA_AND_SSB
|
default B43_BUSES_BCMA_AND_SSB
|
||||||
|
|
||||||
config B43_BUSES_BCMA_AND_SSB
|
config B43_BUSES_BCMA_AND_SSB
|
||||||
bool "BCMA and SSB"
|
bool "BCMA and SSB"
|
||||||
|
|
|
@ -5241,6 +5241,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
|
||||||
/* We don't support 5 GHz on some PHYs yet */
|
/* We don't support 5 GHz on some PHYs yet */
|
||||||
switch (dev->phy.type) {
|
switch (dev->phy.type) {
|
||||||
case B43_PHYTYPE_A:
|
case B43_PHYTYPE_A:
|
||||||
|
case B43_PHYTYPE_G:
|
||||||
case B43_PHYTYPE_N:
|
case B43_PHYTYPE_N:
|
||||||
case B43_PHYTYPE_LP:
|
case B43_PHYTYPE_LP:
|
||||||
case B43_PHYTYPE_HT:
|
case B43_PHYTYPE_HT:
|
||||||
|
|
|
@ -811,9 +811,13 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
|
||||||
break;
|
break;
|
||||||
case B43_PHYTYPE_G:
|
case B43_PHYTYPE_G:
|
||||||
status.band = IEEE80211_BAND_2GHZ;
|
status.band = IEEE80211_BAND_2GHZ;
|
||||||
/* chanid is the radio channel cookie value as used
|
/* Somewhere between 478.104 and 508.1084 firmware for G-PHY
|
||||||
* to tune the radio. */
|
* has been modified to be compatible with N-PHY and others.
|
||||||
status.freq = chanid + 2400;
|
*/
|
||||||
|
if (dev->fw.rev >= 508)
|
||||||
|
status.freq = ieee80211_channel_to_frequency(chanid, status.band);
|
||||||
|
else
|
||||||
|
status.freq = chanid + 2400;
|
||||||
break;
|
break;
|
||||||
case B43_PHYTYPE_N:
|
case B43_PHYTYPE_N:
|
||||||
case B43_PHYTYPE_LP:
|
case B43_PHYTYPE_LP:
|
||||||
|
|
|
@ -57,7 +57,7 @@ mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
mapping.len = size;
|
mapping.len = size;
|
||||||
memcpy(skb->cb, &mapping, sizeof(mapping));
|
mwifiex_store_mapping(skb, &mapping);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ static void mwifiex_unmap_pci_memory(struct mwifiex_adapter *adapter,
|
||||||
struct pcie_service_card *card = adapter->card;
|
struct pcie_service_card *card = adapter->card;
|
||||||
struct mwifiex_dma_mapping mapping;
|
struct mwifiex_dma_mapping mapping;
|
||||||
|
|
||||||
MWIFIEX_SKB_PACB(skb, &mapping);
|
mwifiex_get_mapping(skb, &mapping);
|
||||||
pci_unmap_single(card->dev, mapping.addr, mapping.len, flags);
|
pci_unmap_single(card->dev, mapping.addr, mapping.len, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,32 +20,55 @@
|
||||||
#ifndef _MWIFIEX_UTIL_H_
|
#ifndef _MWIFIEX_UTIL_H_
|
||||||
#define _MWIFIEX_UTIL_H_
|
#define _MWIFIEX_UTIL_H_
|
||||||
|
|
||||||
static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb)
|
|
||||||
{
|
|
||||||
return (struct mwifiex_rxinfo *)(skb->cb + sizeof(dma_addr_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb)
|
|
||||||
{
|
|
||||||
return (struct mwifiex_txinfo *)(skb->cb + sizeof(dma_addr_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct mwifiex_dma_mapping {
|
struct mwifiex_dma_mapping {
|
||||||
dma_addr_t addr;
|
dma_addr_t addr;
|
||||||
size_t len;
|
size_t len;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void MWIFIEX_SKB_PACB(struct sk_buff *skb,
|
struct mwifiex_cb {
|
||||||
struct mwifiex_dma_mapping *mapping)
|
struct mwifiex_dma_mapping dma_mapping;
|
||||||
|
union {
|
||||||
|
struct mwifiex_rxinfo rx_info;
|
||||||
|
struct mwifiex_txinfo tx_info;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
memcpy(mapping, skb->cb, sizeof(*mapping));
|
struct mwifiex_cb *cb = (struct mwifiex_cb *)skb->cb;
|
||||||
|
|
||||||
|
BUILD_BUG_ON(sizeof(struct mwifiex_cb) > sizeof(skb->cb));
|
||||||
|
return &cb->rx_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
struct mwifiex_cb *cb = (struct mwifiex_cb *)skb->cb;
|
||||||
|
|
||||||
|
return &cb->tx_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mwifiex_store_mapping(struct sk_buff *skb,
|
||||||
|
struct mwifiex_dma_mapping *mapping)
|
||||||
|
{
|
||||||
|
struct mwifiex_cb *cb = (struct mwifiex_cb *)skb->cb;
|
||||||
|
|
||||||
|
memcpy(&cb->dma_mapping, mapping, sizeof(*mapping));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mwifiex_get_mapping(struct sk_buff *skb,
|
||||||
|
struct mwifiex_dma_mapping *mapping)
|
||||||
|
{
|
||||||
|
struct mwifiex_cb *cb = (struct mwifiex_cb *)skb->cb;
|
||||||
|
|
||||||
|
memcpy(mapping, &cb->dma_mapping, sizeof(*mapping));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline dma_addr_t MWIFIEX_SKB_DMA_ADDR(struct sk_buff *skb)
|
static inline dma_addr_t MWIFIEX_SKB_DMA_ADDR(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct mwifiex_dma_mapping mapping;
|
struct mwifiex_dma_mapping mapping;
|
||||||
|
|
||||||
MWIFIEX_SKB_PACB(skb, &mapping);
|
mwifiex_get_mapping(skb, &mapping);
|
||||||
|
|
||||||
return mapping.addr;
|
return mapping.addr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1681,8 +1681,13 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
|
||||||
/*
|
/*
|
||||||
* Detect if this device has an hardware controlled radio.
|
* Detect if this device has an hardware controlled radio.
|
||||||
*/
|
*/
|
||||||
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
|
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO)) {
|
||||||
__set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
|
__set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
|
||||||
|
/*
|
||||||
|
* On this device RFKILL initialized during probe does not work.
|
||||||
|
*/
|
||||||
|
__set_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if the BBP tuning should be enabled.
|
* Check if the BBP tuning should be enabled.
|
||||||
|
|
|
@ -229,6 +229,27 @@ static enum hrtimer_restart rt2800usb_tx_sta_fifo_timeout(struct hrtimer *timer)
|
||||||
/*
|
/*
|
||||||
* Firmware functions
|
* Firmware functions
|
||||||
*/
|
*/
|
||||||
|
static int rt2800usb_autorun_detect(struct rt2x00_dev *rt2x00dev)
|
||||||
|
{
|
||||||
|
__le32 reg;
|
||||||
|
u32 fw_mode;
|
||||||
|
|
||||||
|
/* cannot use rt2x00usb_register_read here as it uses different
|
||||||
|
* mode (MULTI_READ vs. DEVICE_MODE) and does not pass the
|
||||||
|
* magic value USB_MODE_AUTORUN (0x11) to the device, thus the
|
||||||
|
* returned value would be invalid.
|
||||||
|
*/
|
||||||
|
rt2x00usb_vendor_request(rt2x00dev, USB_DEVICE_MODE,
|
||||||
|
USB_VENDOR_REQUEST_IN, 0, USB_MODE_AUTORUN,
|
||||||
|
®, sizeof(reg), REGISTER_TIMEOUT_FIRMWARE);
|
||||||
|
fw_mode = le32_to_cpu(reg);
|
||||||
|
|
||||||
|
if ((fw_mode & 0x00000003) == 2)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static char *rt2800usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
|
static char *rt2800usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
|
||||||
{
|
{
|
||||||
return FIRMWARE_RT2870;
|
return FIRMWARE_RT2870;
|
||||||
|
@ -257,8 +278,13 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
|
||||||
/*
|
/*
|
||||||
* Write firmware to device.
|
* Write firmware to device.
|
||||||
*/
|
*/
|
||||||
rt2x00usb_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
|
if (rt2800usb_autorun_detect(rt2x00dev)) {
|
||||||
data + offset, length);
|
rt2x00_info(rt2x00dev,
|
||||||
|
"Firmware loading not required - NIC in AutoRun mode\n");
|
||||||
|
} else {
|
||||||
|
rt2x00usb_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
|
||||||
|
data + offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
|
rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
|
||||||
rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
|
rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
|
||||||
|
@ -735,11 +761,18 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
|
||||||
/*
|
/*
|
||||||
* Device probe functions.
|
* Device probe functions.
|
||||||
*/
|
*/
|
||||||
|
static int rt2800usb_efuse_detect(struct rt2x00_dev *rt2x00dev)
|
||||||
|
{
|
||||||
|
if (rt2800usb_autorun_detect(rt2x00dev))
|
||||||
|
return 1;
|
||||||
|
return rt2800_efuse_detect(rt2x00dev);
|
||||||
|
}
|
||||||
|
|
||||||
static int rt2800usb_read_eeprom(struct rt2x00_dev *rt2x00dev)
|
static int rt2800usb_read_eeprom(struct rt2x00_dev *rt2x00dev)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (rt2800_efuse_detect(rt2x00dev))
|
if (rt2800usb_efuse_detect(rt2x00dev))
|
||||||
retval = rt2800_read_eeprom_efuse(rt2x00dev);
|
retval = rt2800_read_eeprom_efuse(rt2x00dev);
|
||||||
else
|
else
|
||||||
retval = rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom,
|
retval = rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom,
|
||||||
|
|
|
@ -693,6 +693,7 @@ enum rt2x00_capability_flags {
|
||||||
REQUIRE_SW_SEQNO,
|
REQUIRE_SW_SEQNO,
|
||||||
REQUIRE_HT_TX_DESC,
|
REQUIRE_HT_TX_DESC,
|
||||||
REQUIRE_PS_AUTOWAKE,
|
REQUIRE_PS_AUTOWAKE,
|
||||||
|
REQUIRE_DELAYED_RFKILL,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Capabilities
|
* Capabilities
|
||||||
|
|
|
@ -1129,9 +1129,10 @@ static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unregister extra components.
|
* Stop rfkill polling.
|
||||||
*/
|
*/
|
||||||
rt2x00rfkill_unregister(rt2x00dev);
|
if (test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags))
|
||||||
|
rt2x00rfkill_unregister(rt2x00dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allow the HW to uninitialize.
|
* Allow the HW to uninitialize.
|
||||||
|
@ -1169,6 +1170,12 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev)
|
||||||
|
|
||||||
set_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags);
|
set_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start rfkill polling.
|
||||||
|
*/
|
||||||
|
if (test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags))
|
||||||
|
rt2x00rfkill_register(rt2x00dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1378,7 +1385,12 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
|
||||||
rt2x00link_register(rt2x00dev);
|
rt2x00link_register(rt2x00dev);
|
||||||
rt2x00leds_register(rt2x00dev);
|
rt2x00leds_register(rt2x00dev);
|
||||||
rt2x00debug_register(rt2x00dev);
|
rt2x00debug_register(rt2x00dev);
|
||||||
rt2x00rfkill_register(rt2x00dev);
|
|
||||||
|
/*
|
||||||
|
* Start rfkill polling.
|
||||||
|
*/
|
||||||
|
if (!test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags))
|
||||||
|
rt2x00rfkill_register(rt2x00dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1393,6 +1405,12 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
|
||||||
{
|
{
|
||||||
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
|
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop rfkill polling.
|
||||||
|
*/
|
||||||
|
if (!test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags))
|
||||||
|
rt2x00rfkill_unregister(rt2x00dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disable radio.
|
* Disable radio.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -487,6 +487,8 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||||
crypto.cipher = rt2x00crypto_key_to_cipher(key);
|
crypto.cipher = rt2x00crypto_key_to_cipher(key);
|
||||||
if (crypto.cipher == CIPHER_NONE)
|
if (crypto.cipher == CIPHER_NONE)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
if (crypto.cipher == CIPHER_TKIP && rt2x00_is_usb(rt2x00dev))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
crypto.cmd = cmd;
|
crypto.cmd = cmd;
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,7 @@ enum rt2x00usb_mode_offset {
|
||||||
USB_MODE_SLEEP = 7, /* RT73USB */
|
USB_MODE_SLEEP = 7, /* RT73USB */
|
||||||
USB_MODE_FIRMWARE = 8, /* RT73USB */
|
USB_MODE_FIRMWARE = 8, /* RT73USB */
|
||||||
USB_MODE_WAKEUP = 9, /* RT73USB */
|
USB_MODE_WAKEUP = 9, /* RT73USB */
|
||||||
|
USB_MODE_AUTORUN = 17, /* RT2800USB */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -289,10 +289,20 @@ static void hci_conn_timeout(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct hci_conn *conn = container_of(work, struct hci_conn,
|
struct hci_conn *conn = container_of(work, struct hci_conn,
|
||||||
disc_work.work);
|
disc_work.work);
|
||||||
|
int refcnt = atomic_read(&conn->refcnt);
|
||||||
|
|
||||||
BT_DBG("hcon %p state %s", conn, state_to_string(conn->state));
|
BT_DBG("hcon %p state %s", conn, state_to_string(conn->state));
|
||||||
|
|
||||||
if (atomic_read(&conn->refcnt))
|
WARN_ON(refcnt < 0);
|
||||||
|
|
||||||
|
/* FIXME: It was observed that in pairing failed scenario, refcnt
|
||||||
|
* drops below 0. Probably this is because l2cap_conn_del calls
|
||||||
|
* l2cap_chan_del for each channel, and inside l2cap_chan_del conn is
|
||||||
|
* dropped. After that loop hci_chan_del is called which also drops
|
||||||
|
* conn. For now make sure that ACL is alive if refcnt is higher then 0,
|
||||||
|
* otherwise drop it.
|
||||||
|
*/
|
||||||
|
if (refcnt > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (conn->state) {
|
switch (conn->state) {
|
||||||
|
@ -610,11 +620,6 @@ static void hci_req_add_le_create_conn(struct hci_request *req,
|
||||||
if (hci_update_random_address(req, false, &own_addr_type))
|
if (hci_update_random_address(req, false, &own_addr_type))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Save the address type used for this connnection attempt so we able
|
|
||||||
* to retrieve this information if we need it.
|
|
||||||
*/
|
|
||||||
conn->src_type = own_addr_type;
|
|
||||||
|
|
||||||
cp.scan_interval = cpu_to_le16(hdev->le_scan_interval);
|
cp.scan_interval = cpu_to_le16(hdev->le_scan_interval);
|
||||||
cp.scan_window = cpu_to_le16(hdev->le_scan_window);
|
cp.scan_window = cpu_to_le16(hdev->le_scan_window);
|
||||||
bacpy(&cp.peer_addr, &conn->dst);
|
bacpy(&cp.peer_addr, &conn->dst);
|
||||||
|
@ -894,7 +899,7 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
|
||||||
/* If we're already encrypted set the REAUTH_PEND flag,
|
/* If we're already encrypted set the REAUTH_PEND flag,
|
||||||
* otherwise set the ENCRYPT_PEND.
|
* otherwise set the ENCRYPT_PEND.
|
||||||
*/
|
*/
|
||||||
if (conn->key_type != 0xff)
|
if (conn->link_mode & HCI_LM_ENCRYPT)
|
||||||
set_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
|
set_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
|
||||||
else
|
else
|
||||||
set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
|
set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
|
||||||
|
|
|
@ -48,6 +48,10 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
smp_mb__after_atomic(); /* wake_up_bit advises about this barrier */
|
smp_mb__after_atomic(); /* wake_up_bit advises about this barrier */
|
||||||
wake_up_bit(&hdev->flags, HCI_INQUIRY);
|
wake_up_bit(&hdev->flags, HCI_INQUIRY);
|
||||||
|
|
||||||
|
hci_dev_lock(hdev);
|
||||||
|
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
||||||
|
hci_dev_unlock(hdev);
|
||||||
|
|
||||||
hci_conn_check_pending(hdev);
|
hci_conn_check_pending(hdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3537,7 +3541,11 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
cp.authentication = conn->auth_type;
|
cp.authentication = conn->auth_type;
|
||||||
|
|
||||||
/* Request MITM protection if our IO caps allow it
|
/* Request MITM protection if our IO caps allow it
|
||||||
* except for the no-bonding case
|
* except for the no-bonding case.
|
||||||
|
* conn->auth_type is not updated here since
|
||||||
|
* that might cause the user confirmation to be
|
||||||
|
* rejected in case the remote doesn't have the
|
||||||
|
* IO capabilities for MITM.
|
||||||
*/
|
*/
|
||||||
if (conn->io_capability != HCI_IO_NO_INPUT_OUTPUT &&
|
if (conn->io_capability != HCI_IO_NO_INPUT_OUTPUT &&
|
||||||
cp.authentication != HCI_AT_NO_BONDING)
|
cp.authentication != HCI_AT_NO_BONDING)
|
||||||
|
@ -3628,8 +3636,11 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev,
|
||||||
|
|
||||||
/* If we're not the initiators request authorization to
|
/* If we're not the initiators request authorization to
|
||||||
* proceed from user space (mgmt_user_confirm with
|
* proceed from user space (mgmt_user_confirm with
|
||||||
* confirm_hint set to 1). */
|
* confirm_hint set to 1). The exception is if neither
|
||||||
if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
|
* side had MITM in which case we do auto-accept.
|
||||||
|
*/
|
||||||
|
if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) &&
|
||||||
|
(loc_mitm || rem_mitm)) {
|
||||||
BT_DBG("Confirming auto-accept as acceptor");
|
BT_DBG("Confirming auto-accept as acceptor");
|
||||||
confirm_hint = 1;
|
confirm_hint = 1;
|
||||||
goto confirm;
|
goto confirm;
|
||||||
|
|
|
@ -1663,7 +1663,13 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
|
||||||
kfree_skb(conn->rx_skb);
|
kfree_skb(conn->rx_skb);
|
||||||
|
|
||||||
skb_queue_purge(&conn->pending_rx);
|
skb_queue_purge(&conn->pending_rx);
|
||||||
flush_work(&conn->pending_rx_work);
|
|
||||||
|
/* We can not call flush_work(&conn->pending_rx_work) here since we
|
||||||
|
* might block if we are running on a worker from the same workqueue
|
||||||
|
* pending_rx_work is waiting on.
|
||||||
|
*/
|
||||||
|
if (work_pending(&conn->pending_rx_work))
|
||||||
|
cancel_work_sync(&conn->pending_rx_work);
|
||||||
|
|
||||||
l2cap_unregister_all_users(conn);
|
l2cap_unregister_all_users(conn);
|
||||||
|
|
||||||
|
|
|
@ -787,11 +787,6 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||||
|
|
||||||
/*change security for LE channels */
|
/*change security for LE channels */
|
||||||
if (chan->scid == L2CAP_CID_ATT) {
|
if (chan->scid == L2CAP_CID_ATT) {
|
||||||
if (!conn->hcon->out) {
|
|
||||||
err = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (smp_conn_security(conn->hcon, sec.level))
|
if (smp_conn_security(conn->hcon, sec.level))
|
||||||
break;
|
break;
|
||||||
sk->sk_state = BT_CONFIG;
|
sk->sk_state = BT_CONFIG;
|
||||||
|
|
|
@ -1047,6 +1047,43 @@ static void clean_up_hci_complete(struct hci_dev *hdev, u8 status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hci_stop_discovery(struct hci_request *req)
|
||||||
|
{
|
||||||
|
struct hci_dev *hdev = req->hdev;
|
||||||
|
struct hci_cp_remote_name_req_cancel cp;
|
||||||
|
struct inquiry_entry *e;
|
||||||
|
|
||||||
|
switch (hdev->discovery.state) {
|
||||||
|
case DISCOVERY_FINDING:
|
||||||
|
if (test_bit(HCI_INQUIRY, &hdev->flags)) {
|
||||||
|
hci_req_add(req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
|
||||||
|
} else {
|
||||||
|
cancel_delayed_work(&hdev->le_scan_disable);
|
||||||
|
hci_req_add_le_scan_disable(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DISCOVERY_RESOLVING:
|
||||||
|
e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
|
||||||
|
NAME_PENDING);
|
||||||
|
if (!e)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bacpy(&cp.bdaddr, &e->data.bdaddr);
|
||||||
|
hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
|
||||||
|
&cp);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Passive scanning */
|
||||||
|
if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
|
||||||
|
hci_req_add_le_scan_disable(req);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int clean_up_hci_state(struct hci_dev *hdev)
|
static int clean_up_hci_state(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
struct hci_request req;
|
struct hci_request req;
|
||||||
|
@ -1063,9 +1100,7 @@ static int clean_up_hci_state(struct hci_dev *hdev)
|
||||||
if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
|
if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
|
||||||
disable_advertising(&req);
|
disable_advertising(&req);
|
||||||
|
|
||||||
if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
|
hci_stop_discovery(&req);
|
||||||
hci_req_add_le_scan_disable(&req);
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry(conn, &hdev->conn_hash.list, list) {
|
list_for_each_entry(conn, &hdev->conn_hash.list, list) {
|
||||||
struct hci_cp_disconnect dc;
|
struct hci_cp_disconnect dc;
|
||||||
|
@ -2996,8 +3031,13 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
|
if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
|
||||||
/* Continue with pairing via SMP */
|
/* Continue with pairing via SMP. The hdev lock must be
|
||||||
|
* released as SMP may try to recquire it for crypto
|
||||||
|
* purposes.
|
||||||
|
*/
|
||||||
|
hci_dev_unlock(hdev);
|
||||||
err = smp_user_confirm_reply(conn, mgmt_op, passkey);
|
err = smp_user_confirm_reply(conn, mgmt_op, passkey);
|
||||||
|
hci_dev_lock(hdev);
|
||||||
|
|
||||||
if (!err)
|
if (!err)
|
||||||
err = cmd_complete(sk, hdev->id, mgmt_op,
|
err = cmd_complete(sk, hdev->id, mgmt_op,
|
||||||
|
@ -3574,8 +3614,6 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||||
{
|
{
|
||||||
struct mgmt_cp_stop_discovery *mgmt_cp = data;
|
struct mgmt_cp_stop_discovery *mgmt_cp = data;
|
||||||
struct pending_cmd *cmd;
|
struct pending_cmd *cmd;
|
||||||
struct hci_cp_remote_name_req_cancel cp;
|
|
||||||
struct inquiry_entry *e;
|
|
||||||
struct hci_request req;
|
struct hci_request req;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -3605,52 +3643,22 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||||
|
|
||||||
hci_req_init(&req, hdev);
|
hci_req_init(&req, hdev);
|
||||||
|
|
||||||
switch (hdev->discovery.state) {
|
hci_stop_discovery(&req);
|
||||||
case DISCOVERY_FINDING:
|
|
||||||
if (test_bit(HCI_INQUIRY, &hdev->flags)) {
|
|
||||||
hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
|
|
||||||
} else {
|
|
||||||
cancel_delayed_work(&hdev->le_scan_disable);
|
|
||||||
|
|
||||||
hci_req_add_le_scan_disable(&req);
|
err = hci_req_run(&req, stop_discovery_complete);
|
||||||
}
|
if (!err) {
|
||||||
|
hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
|
||||||
break;
|
|
||||||
|
|
||||||
case DISCOVERY_RESOLVING:
|
|
||||||
e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
|
|
||||||
NAME_PENDING);
|
|
||||||
if (!e) {
|
|
||||||
mgmt_pending_remove(cmd);
|
|
||||||
err = cmd_complete(sk, hdev->id,
|
|
||||||
MGMT_OP_STOP_DISCOVERY, 0,
|
|
||||||
&mgmt_cp->type,
|
|
||||||
sizeof(mgmt_cp->type));
|
|
||||||
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
bacpy(&cp.bdaddr, &e->data.bdaddr);
|
|
||||||
hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
|
|
||||||
&cp);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
BT_DBG("unknown discovery state %u", hdev->discovery.state);
|
|
||||||
|
|
||||||
mgmt_pending_remove(cmd);
|
|
||||||
err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
|
|
||||||
MGMT_STATUS_FAILED, &mgmt_cp->type,
|
|
||||||
sizeof(mgmt_cp->type));
|
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = hci_req_run(&req, stop_discovery_complete);
|
mgmt_pending_remove(cmd);
|
||||||
if (err < 0)
|
|
||||||
mgmt_pending_remove(cmd);
|
/* If no HCI commands were sent we're done */
|
||||||
else
|
if (err == -ENODATA) {
|
||||||
hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
|
err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
|
||||||
|
&mgmt_cp->type, sizeof(mgmt_cp->type));
|
||||||
|
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
|
||||||
|
}
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
hci_dev_unlock(hdev);
|
hci_dev_unlock(hdev);
|
||||||
|
|
|
@ -385,6 +385,16 @@ static const u8 gen_method[5][5] = {
|
||||||
{ CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, OVERLAP },
|
{ CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, OVERLAP },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static u8 get_auth_method(struct smp_chan *smp, u8 local_io, u8 remote_io)
|
||||||
|
{
|
||||||
|
/* If either side has unknown io_caps, use JUST WORKS */
|
||||||
|
if (local_io > SMP_IO_KEYBOARD_DISPLAY ||
|
||||||
|
remote_io > SMP_IO_KEYBOARD_DISPLAY)
|
||||||
|
return JUST_WORKS;
|
||||||
|
|
||||||
|
return gen_method[remote_io][local_io];
|
||||||
|
}
|
||||||
|
|
||||||
static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
||||||
u8 local_io, u8 remote_io)
|
u8 local_io, u8 remote_io)
|
||||||
{
|
{
|
||||||
|
@ -401,14 +411,11 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
||||||
BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io);
|
BT_DBG("tk_request: auth:%d lcl:%d rem:%d", auth, local_io, remote_io);
|
||||||
|
|
||||||
/* If neither side wants MITM, use JUST WORKS */
|
/* If neither side wants MITM, use JUST WORKS */
|
||||||
/* If either side has unknown io_caps, use JUST WORKS */
|
|
||||||
/* Otherwise, look up method from the table */
|
/* Otherwise, look up method from the table */
|
||||||
if (!(auth & SMP_AUTH_MITM) ||
|
if (!(auth & SMP_AUTH_MITM))
|
||||||
local_io > SMP_IO_KEYBOARD_DISPLAY ||
|
|
||||||
remote_io > SMP_IO_KEYBOARD_DISPLAY)
|
|
||||||
method = JUST_WORKS;
|
method = JUST_WORKS;
|
||||||
else
|
else
|
||||||
method = gen_method[remote_io][local_io];
|
method = get_auth_method(smp, local_io, remote_io);
|
||||||
|
|
||||||
/* If not bonding, don't ask user to confirm a Zero TK */
|
/* If not bonding, don't ask user to confirm a Zero TK */
|
||||||
if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM)
|
if (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM)
|
||||||
|
@ -544,7 +551,7 @@ static u8 smp_random(struct smp_chan *smp)
|
||||||
hci_le_start_enc(hcon, ediv, rand, stk);
|
hci_le_start_enc(hcon, ediv, rand, stk);
|
||||||
hcon->enc_key_size = smp->enc_key_size;
|
hcon->enc_key_size = smp->enc_key_size;
|
||||||
} else {
|
} else {
|
||||||
u8 stk[16];
|
u8 stk[16], auth;
|
||||||
__le64 rand = 0;
|
__le64 rand = 0;
|
||||||
__le16 ediv = 0;
|
__le16 ediv = 0;
|
||||||
|
|
||||||
|
@ -556,8 +563,13 @@ static u8 smp_random(struct smp_chan *smp)
|
||||||
memset(stk + smp->enc_key_size, 0,
|
memset(stk + smp->enc_key_size, 0,
|
||||||
SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
|
SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
|
||||||
|
|
||||||
|
if (hcon->pending_sec_level == BT_SECURITY_HIGH)
|
||||||
|
auth = 1;
|
||||||
|
else
|
||||||
|
auth = 0;
|
||||||
|
|
||||||
hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
|
hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
|
||||||
HCI_SMP_STK_SLAVE, 0, stk, smp->enc_key_size,
|
HCI_SMP_STK_SLAVE, auth, stk, smp->enc_key_size,
|
||||||
ediv, rand);
|
ediv, rand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,7 +676,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct smp_cmd_pairing rsp, *req = (void *) skb->data;
|
struct smp_cmd_pairing rsp, *req = (void *) skb->data;
|
||||||
struct smp_chan *smp;
|
struct smp_chan *smp;
|
||||||
u8 key_size, auth;
|
u8 key_size, auth, sec_level;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
BT_DBG("conn %p", conn);
|
BT_DBG("conn %p", conn);
|
||||||
|
@ -690,7 +702,19 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||||
/* We didn't start the pairing, so match remote */
|
/* We didn't start the pairing, so match remote */
|
||||||
auth = req->auth_req;
|
auth = req->auth_req;
|
||||||
|
|
||||||
conn->hcon->pending_sec_level = authreq_to_seclevel(auth);
|
sec_level = authreq_to_seclevel(auth);
|
||||||
|
if (sec_level > conn->hcon->pending_sec_level)
|
||||||
|
conn->hcon->pending_sec_level = sec_level;
|
||||||
|
|
||||||
|
/* If we need MITM check that it can be acheived */
|
||||||
|
if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
|
||||||
|
u8 method;
|
||||||
|
|
||||||
|
method = get_auth_method(smp, conn->hcon->io_capability,
|
||||||
|
req->io_capability);
|
||||||
|
if (method == JUST_WORKS || method == JUST_CFM)
|
||||||
|
return SMP_AUTH_REQUIREMENTS;
|
||||||
|
}
|
||||||
|
|
||||||
build_pairing_cmd(conn, req, &rsp, auth);
|
build_pairing_cmd(conn, req, &rsp, auth);
|
||||||
|
|
||||||
|
@ -738,6 +762,16 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||||
if (check_enc_key_size(conn, key_size))
|
if (check_enc_key_size(conn, key_size))
|
||||||
return SMP_ENC_KEY_SIZE;
|
return SMP_ENC_KEY_SIZE;
|
||||||
|
|
||||||
|
/* If we need MITM check that it can be acheived */
|
||||||
|
if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
|
||||||
|
u8 method;
|
||||||
|
|
||||||
|
method = get_auth_method(smp, req->io_capability,
|
||||||
|
rsp->io_capability);
|
||||||
|
if (method == JUST_WORKS || method == JUST_CFM)
|
||||||
|
return SMP_AUTH_REQUIREMENTS;
|
||||||
|
}
|
||||||
|
|
||||||
get_random_bytes(smp->prnd, sizeof(smp->prnd));
|
get_random_bytes(smp->prnd, sizeof(smp->prnd));
|
||||||
|
|
||||||
smp->prsp[0] = SMP_CMD_PAIRING_RSP;
|
smp->prsp[0] = SMP_CMD_PAIRING_RSP;
|
||||||
|
@ -833,6 +867,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||||
struct smp_cmd_pairing cp;
|
struct smp_cmd_pairing cp;
|
||||||
struct hci_conn *hcon = conn->hcon;
|
struct hci_conn *hcon = conn->hcon;
|
||||||
struct smp_chan *smp;
|
struct smp_chan *smp;
|
||||||
|
u8 sec_level;
|
||||||
|
|
||||||
BT_DBG("conn %p", conn);
|
BT_DBG("conn %p", conn);
|
||||||
|
|
||||||
|
@ -842,7 +877,9 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||||
if (!(conn->hcon->link_mode & HCI_LM_MASTER))
|
if (!(conn->hcon->link_mode & HCI_LM_MASTER))
|
||||||
return SMP_CMD_NOTSUPP;
|
return SMP_CMD_NOTSUPP;
|
||||||
|
|
||||||
hcon->pending_sec_level = authreq_to_seclevel(rp->auth_req);
|
sec_level = authreq_to_seclevel(rp->auth_req);
|
||||||
|
if (sec_level > hcon->pending_sec_level)
|
||||||
|
hcon->pending_sec_level = sec_level;
|
||||||
|
|
||||||
if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
|
if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -896,9 +933,12 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
||||||
if (smp_sufficient_security(hcon, sec_level))
|
if (smp_sufficient_security(hcon, sec_level))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
if (sec_level > hcon->pending_sec_level)
|
||||||
|
hcon->pending_sec_level = sec_level;
|
||||||
|
|
||||||
if (hcon->link_mode & HCI_LM_MASTER)
|
if (hcon->link_mode & HCI_LM_MASTER)
|
||||||
if (smp_ltk_encrypt(conn, sec_level))
|
if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
|
||||||
goto done;
|
return 0;
|
||||||
|
|
||||||
if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
|
if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -913,7 +953,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
||||||
* requires it.
|
* requires it.
|
||||||
*/
|
*/
|
||||||
if (hcon->io_capability != HCI_IO_NO_INPUT_OUTPUT ||
|
if (hcon->io_capability != HCI_IO_NO_INPUT_OUTPUT ||
|
||||||
sec_level > BT_SECURITY_MEDIUM)
|
hcon->pending_sec_level > BT_SECURITY_MEDIUM)
|
||||||
authreq |= SMP_AUTH_MITM;
|
authreq |= SMP_AUTH_MITM;
|
||||||
|
|
||||||
if (hcon->link_mode & HCI_LM_MASTER) {
|
if (hcon->link_mode & HCI_LM_MASTER) {
|
||||||
|
@ -932,9 +972,6 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
||||||
|
|
||||||
set_bit(SMP_FLAG_INITIATOR, &smp->flags);
|
set_bit(SMP_FLAG_INITIATOR, &smp->flags);
|
||||||
|
|
||||||
done:
|
|
||||||
hcon->pending_sec_level = sec_level;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче