mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 22:51:42 +00:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
This commit is contained in:
commit
95d01a669b
@ -30,8 +30,8 @@ config BT_HCIUART
|
||||
help
|
||||
Bluetooth HCI UART driver.
|
||||
This driver is required if you want to use Bluetooth devices with
|
||||
serial port interface. You will also need this driver if you have
|
||||
UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card
|
||||
serial port interface. You will also need this driver if you have
|
||||
UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card
|
||||
adapter and BrainBoxes Bluetooth PC Card.
|
||||
|
||||
Say Y here to compile support for Bluetooth UART devices into the
|
||||
@ -41,9 +41,9 @@ config BT_HCIUART_H4
|
||||
bool "UART (H4) protocol support"
|
||||
depends on BT_HCIUART
|
||||
help
|
||||
UART (H4) is serial protocol for communication between Bluetooth
|
||||
device and host. This protocol is required for most Bluetooth devices
|
||||
with UART interface, including PCMCIA and CF cards.
|
||||
UART (H4) is serial protocol for communication between Bluetooth
|
||||
device and host. This protocol is required for most Bluetooth devices
|
||||
with UART interface, including PCMCIA and CF cards.
|
||||
|
||||
Say Y here to compile support for HCI UART (H4) protocol.
|
||||
|
||||
@ -52,7 +52,7 @@ config BT_HCIUART_BCSP
|
||||
depends on BT_HCIUART
|
||||
select BITREVERSE
|
||||
help
|
||||
BCSP (BlueCore Serial Protocol) is serial protocol for communication
|
||||
BCSP (BlueCore Serial Protocol) is serial protocol for communication
|
||||
between Bluetooth device and host. This protocol is required for non
|
||||
USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and
|
||||
CF cards.
|
||||
|
@ -90,7 +90,6 @@ static const struct usb_device_id ath3k_table[] = {
|
||||
{ USB_DEVICE(0x0b05, 0x17d0) },
|
||||
{ USB_DEVICE(0x0CF3, 0x0036) },
|
||||
{ USB_DEVICE(0x0CF3, 0x3004) },
|
||||
{ USB_DEVICE(0x0CF3, 0x3005) },
|
||||
{ USB_DEVICE(0x0CF3, 0x3008) },
|
||||
{ USB_DEVICE(0x0CF3, 0x311D) },
|
||||
{ USB_DEVICE(0x0CF3, 0x311E) },
|
||||
@ -104,6 +103,7 @@ static const struct usb_device_id ath3k_table[] = {
|
||||
{ USB_DEVICE(0x13d3, 0x3375) },
|
||||
{ USB_DEVICE(0x13d3, 0x3393) },
|
||||
{ USB_DEVICE(0x13d3, 0x3402) },
|
||||
{ USB_DEVICE(0x13d3, 0x3432) },
|
||||
|
||||
/* Atheros AR5BBU12 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xE02C) },
|
||||
@ -140,7 +140,6 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
|
||||
{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0CF3, 0x0036), .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, 0x311D), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x311E), .driver_info = BTUSB_ATH3012 },
|
||||
@ -154,6 +153,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
|
||||
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
|
||||
|
||||
/* Atheros AR5BBU22 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xE036), .driver_info = BTUSB_ATH3012 },
|
||||
@ -290,10 +290,10 @@ static int ath3k_load_fwfile(struct usb_device *udev,
|
||||
sent += size;
|
||||
count -= size;
|
||||
|
||||
pipe = usb_sndbulkpipe(udev, 0x02);
|
||||
|
||||
while (count) {
|
||||
size = min_t(uint, count, BULK_SIZE);
|
||||
pipe = usb_sndbulkpipe(udev, 0x02);
|
||||
|
||||
memcpy(send_buf, firmware->data + sent, size);
|
||||
|
||||
err = usb_bulk_msg(udev, pipe, send_buf, size,
|
||||
|
@ -68,6 +68,7 @@ struct btmrvl_adapter {
|
||||
u8 hs_state;
|
||||
u8 wakeup_tries;
|
||||
wait_queue_head_t cmd_wait_q;
|
||||
wait_queue_head_t event_hs_wait_q;
|
||||
u8 cmd_complete;
|
||||
bool is_suspended;
|
||||
};
|
||||
@ -89,6 +90,7 @@ struct btmrvl_private {
|
||||
#define MRVL_VENDOR_PKT 0xFE
|
||||
|
||||
/* Vendor specific Bluetooth commands */
|
||||
#define BT_CMD_PSCAN_WIN_REPORT_ENABLE 0xFC03
|
||||
#define BT_CMD_AUTO_SLEEP_MODE 0xFC23
|
||||
#define BT_CMD_HOST_SLEEP_CONFIG 0xFC59
|
||||
#define BT_CMD_HOST_SLEEP_ENABLE 0xFC5A
|
||||
@ -143,6 +145,7 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb);
|
||||
int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb);
|
||||
|
||||
int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, u8 subcmd);
|
||||
int btmrvl_pscan_window_reporting(struct btmrvl_private *priv, u8 subcmd);
|
||||
int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv);
|
||||
int btmrvl_enable_ps(struct btmrvl_private *priv);
|
||||
int btmrvl_prepare_command(struct btmrvl_private *priv);
|
||||
|
@ -114,6 +114,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
|
||||
adapter->hs_state = HS_ACTIVATED;
|
||||
if (adapter->psmode)
|
||||
adapter->ps_state = PS_SLEEP;
|
||||
wake_up_interruptible(&adapter->event_hs_wait_q);
|
||||
BT_DBG("HS ACTIVATED!");
|
||||
} else {
|
||||
BT_DBG("HS Enable failed");
|
||||
@ -214,6 +215,23 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, u8 subcmd)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd);
|
||||
|
||||
int btmrvl_pscan_window_reporting(struct btmrvl_private *priv, u8 subcmd)
|
||||
{
|
||||
struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;
|
||||
int ret;
|
||||
|
||||
if (!card->support_pscan_win_report)
|
||||
return 0;
|
||||
|
||||
ret = btmrvl_send_sync_cmd(priv, BT_CMD_PSCAN_WIN_REPORT_ENABLE,
|
||||
&subcmd, 1);
|
||||
if (ret)
|
||||
BT_ERR("PSCAN_WIN_REPORT_ENABLE command failed: %#x", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(btmrvl_pscan_window_reporting);
|
||||
|
||||
int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv)
|
||||
{
|
||||
int ret;
|
||||
@ -253,11 +271,31 @@ EXPORT_SYMBOL_GPL(btmrvl_enable_ps);
|
||||
|
||||
int btmrvl_enable_hs(struct btmrvl_private *priv)
|
||||
{
|
||||
struct btmrvl_adapter *adapter = priv->adapter;
|
||||
int ret;
|
||||
|
||||
ret = btmrvl_send_sync_cmd(priv, BT_CMD_HOST_SLEEP_ENABLE, NULL, 0);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
BT_ERR("Host sleep enable command failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wait_event_interruptible_timeout(adapter->event_hs_wait_q,
|
||||
adapter->hs_state,
|
||||
msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED));
|
||||
if (ret < 0) {
|
||||
BT_ERR("event_hs_wait_q terminated (%d): %d,%d,%d",
|
||||
ret, adapter->hs_state, adapter->ps_state,
|
||||
adapter->wakeup_tries);
|
||||
} else if (!ret) {
|
||||
BT_ERR("hs_enable timeout: %d,%d,%d", adapter->hs_state,
|
||||
adapter->ps_state, adapter->wakeup_tries);
|
||||
ret = -ETIMEDOUT;
|
||||
} else {
|
||||
BT_DBG("host sleep enabled: %d,%d,%d", adapter->hs_state,
|
||||
adapter->ps_state, adapter->wakeup_tries);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -358,6 +396,7 @@ static void btmrvl_init_adapter(struct btmrvl_private *priv)
|
||||
}
|
||||
|
||||
init_waitqueue_head(&priv->adapter->cmd_wait_q);
|
||||
init_waitqueue_head(&priv->adapter->event_hs_wait_q);
|
||||
}
|
||||
|
||||
static void btmrvl_free_adapter(struct btmrvl_private *priv)
|
||||
@ -489,6 +528,8 @@ static int btmrvl_setup(struct hci_dev *hdev)
|
||||
|
||||
btmrvl_cal_data_dt(priv);
|
||||
|
||||
btmrvl_pscan_window_reporting(priv, 0x01);
|
||||
|
||||
priv->btmrvl_dev.psmode = 1;
|
||||
btmrvl_enable_ps(priv);
|
||||
|
||||
@ -666,6 +707,7 @@ int btmrvl_remove_card(struct btmrvl_private *priv)
|
||||
hdev = priv->btmrvl_dev.hcidev;
|
||||
|
||||
wake_up_interruptible(&priv->adapter->cmd_wait_q);
|
||||
wake_up_interruptible(&priv->adapter->event_hs_wait_q);
|
||||
|
||||
kthread_stop(priv->main_thread.task);
|
||||
|
||||
|
@ -108,6 +108,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
|
||||
.helper = "mrvl/sd8688_helper.bin",
|
||||
.firmware = "mrvl/sd8688.bin",
|
||||
.reg = &btmrvl_reg_8688,
|
||||
.support_pscan_win_report = false,
|
||||
.sd_blksz_fw_dl = 64,
|
||||
};
|
||||
|
||||
@ -115,6 +116,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
|
||||
.helper = NULL,
|
||||
.firmware = "mrvl/sd8787_uapsta.bin",
|
||||
.reg = &btmrvl_reg_87xx,
|
||||
.support_pscan_win_report = false,
|
||||
.sd_blksz_fw_dl = 256,
|
||||
};
|
||||
|
||||
@ -122,6 +124,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
|
||||
.helper = NULL,
|
||||
.firmware = "mrvl/sd8797_uapsta.bin",
|
||||
.reg = &btmrvl_reg_87xx,
|
||||
.support_pscan_win_report = false,
|
||||
.sd_blksz_fw_dl = 256,
|
||||
};
|
||||
|
||||
@ -129,6 +132,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
|
||||
.helper = NULL,
|
||||
.firmware = "mrvl/sd8897_uapsta.bin",
|
||||
.reg = &btmrvl_reg_88xx,
|
||||
.support_pscan_win_report = true,
|
||||
.sd_blksz_fw_dl = 256,
|
||||
};
|
||||
|
||||
@ -1067,6 +1071,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
|
||||
card->firmware = data->firmware;
|
||||
card->reg = data->reg;
|
||||
card->sd_blksz_fw_dl = data->sd_blksz_fw_dl;
|
||||
card->support_pscan_win_report = data->support_pscan_win_report;
|
||||
}
|
||||
|
||||
if (btmrvl_sdio_register_dev(card) < 0) {
|
||||
|
@ -89,6 +89,7 @@ struct btmrvl_sdio_card {
|
||||
const char *helper;
|
||||
const char *firmware;
|
||||
const struct btmrvl_sdio_card_reg *reg;
|
||||
bool support_pscan_win_report;
|
||||
u16 sd_blksz_fw_dl;
|
||||
u8 rx_unit;
|
||||
struct btmrvl_private *priv;
|
||||
@ -98,6 +99,7 @@ struct btmrvl_sdio_device {
|
||||
const char *helper;
|
||||
const char *firmware;
|
||||
const struct btmrvl_sdio_card_reg *reg;
|
||||
const bool support_pscan_win_report;
|
||||
u16 sd_blksz_fw_dl;
|
||||
};
|
||||
|
||||
|
@ -30,9 +30,6 @@
|
||||
|
||||
#define VERSION "0.6"
|
||||
|
||||
static bool ignore_dga;
|
||||
static bool ignore_csr;
|
||||
static bool ignore_sniffer;
|
||||
static bool disable_scofix;
|
||||
static bool force_scofix;
|
||||
|
||||
@ -49,7 +46,8 @@ static struct usb_driver btusb_driver;
|
||||
#define BTUSB_WRONG_SCO_MTU 0x40
|
||||
#define BTUSB_ATH3012 0x80
|
||||
#define BTUSB_INTEL 0x100
|
||||
#define BTUSB_BCM_PATCHRAM 0x200
|
||||
#define BTUSB_INTEL_BOOT 0x200
|
||||
#define BTUSB_BCM_PATCHRAM 0x400
|
||||
|
||||
static const struct usb_device_id btusb_table[] = {
|
||||
/* Generic Bluetooth USB device */
|
||||
@ -121,6 +119,10 @@ static const struct usb_device_id btusb_table[] = {
|
||||
/* IMC Networks - Broadcom based */
|
||||
{ USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01) },
|
||||
|
||||
/* Intel Bluetooth USB Bootloader (RAM module) */
|
||||
{ USB_DEVICE(0x8087, 0x0a5a),
|
||||
.driver_info = BTUSB_INTEL_BOOT | BTUSB_BROKEN_ISOC },
|
||||
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
@ -162,7 +164,6 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x0036), .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, 0x311d), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 },
|
||||
@ -176,6 +177,7 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
|
||||
|
||||
/* Atheros AR5BBU12 with sflash firmware */
|
||||
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
|
||||
@ -229,10 +231,12 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
{ USB_DEVICE(0x08fd, 0x0002), .driver_info = BTUSB_IGNORE },
|
||||
|
||||
/* CSR BlueCore Bluetooth Sniffer */
|
||||
{ USB_DEVICE(0x0a12, 0x0002), .driver_info = BTUSB_SNIFFER },
|
||||
{ USB_DEVICE(0x0a12, 0x0002),
|
||||
.driver_info = BTUSB_SNIFFER | BTUSB_BROKEN_ISOC },
|
||||
|
||||
/* Frontline ComProbe Bluetooth Sniffer */
|
||||
{ USB_DEVICE(0x16d3, 0x0002), .driver_info = BTUSB_SNIFFER },
|
||||
{ USB_DEVICE(0x16d3, 0x0002),
|
||||
.driver_info = BTUSB_SNIFFER | BTUSB_BROKEN_ISOC },
|
||||
|
||||
/* Intel Bluetooth device */
|
||||
{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL },
|
||||
@ -1183,6 +1187,51 @@ static int btusb_setup_intel_patching(struct hci_dev *hdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BDADDR_INTEL (&(bdaddr_t) {{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}})
|
||||
|
||||
static int btusb_check_bdaddr_intel(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct hci_rp_read_bd_addr *rp;
|
||||
|
||||
skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL,
|
||||
HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
BT_ERR("%s reading Intel device address failed (%ld)",
|
||||
hdev->name, PTR_ERR(skb));
|
||||
return PTR_ERR(skb);
|
||||
}
|
||||
|
||||
if (skb->len != sizeof(*rp)) {
|
||||
BT_ERR("%s Intel device address length mismatch", hdev->name);
|
||||
kfree_skb(skb);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
rp = (struct hci_rp_read_bd_addr *) skb->data;
|
||||
if (rp->status) {
|
||||
BT_ERR("%s Intel device address result failed (%02x)",
|
||||
hdev->name, rp->status);
|
||||
kfree_skb(skb);
|
||||
return -bt_to_errno(rp->status);
|
||||
}
|
||||
|
||||
/* For some Intel based controllers, the default Bluetooth device
|
||||
* address 00:03:19:9E:8B:00 can be found. These controllers are
|
||||
* fully operational, but have the danger of duplicate addresses
|
||||
* and that in turn can cause problems with Bluetooth operation.
|
||||
*/
|
||||
if (!bacmp(&rp->bdaddr, BDADDR_INTEL)) {
|
||||
BT_ERR("%s found Intel default device address (%pMR)",
|
||||
hdev->name, &rp->bdaddr);
|
||||
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btusb_setup_intel(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
@ -1255,6 +1304,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
|
||||
BT_INFO("%s: Intel device is already patched. patch num: %02x",
|
||||
hdev->name, ver->fw_patch_num);
|
||||
kfree_skb(skb);
|
||||
btusb_check_bdaddr_intel(hdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1267,6 +1317,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
|
||||
fw = btusb_setup_intel_get_fw(hdev, ver);
|
||||
if (!fw) {
|
||||
kfree_skb(skb);
|
||||
btusb_check_bdaddr_intel(hdev);
|
||||
return 0;
|
||||
}
|
||||
fw_ptr = fw->data;
|
||||
@ -1346,6 +1397,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
|
||||
BT_INFO("%s: Intel Bluetooth firmware patch completed and activated",
|
||||
hdev->name);
|
||||
|
||||
btusb_check_bdaddr_intel(hdev);
|
||||
return 0;
|
||||
|
||||
exit_mfg_disable:
|
||||
@ -1360,6 +1412,8 @@ exit_mfg_disable:
|
||||
kfree_skb(skb);
|
||||
|
||||
BT_INFO("%s: Intel Bluetooth firmware patch completed", hdev->name);
|
||||
|
||||
btusb_check_bdaddr_intel(hdev);
|
||||
return 0;
|
||||
|
||||
exit_mfg_deactivate:
|
||||
@ -1380,9 +1434,29 @@ exit_mfg_deactivate:
|
||||
BT_INFO("%s: Intel Bluetooth firmware patch completed and deactivated",
|
||||
hdev->name);
|
||||
|
||||
btusb_check_bdaddr_intel(hdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btusb_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
long ret;
|
||||
|
||||
skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
ret = PTR_ERR(skb);
|
||||
BT_ERR("%s: changing Intel device address failed (%ld)",
|
||||
hdev->name, ret);
|
||||
return ret;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}})
|
||||
|
||||
static int btusb_setup_bcm_patchram(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
@ -1396,6 +1470,7 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev)
|
||||
u16 opcode;
|
||||
struct sk_buff *skb;
|
||||
struct hci_rp_read_local_version *ver;
|
||||
struct hci_rp_read_bd_addr *bda;
|
||||
long ret;
|
||||
|
||||
snprintf(fw_name, sizeof(fw_name), "brcm/%s-%04x-%04x.hcd",
|
||||
@ -1405,8 +1480,7 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev)
|
||||
|
||||
ret = request_firmware(&fw, fw_name, &hdev->dev);
|
||||
if (ret < 0) {
|
||||
BT_INFO("%s: BCM: patch %s not found", hdev->name,
|
||||
fw_name);
|
||||
BT_INFO("%s: BCM: patch %s not found", hdev->name, fw_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1525,12 +1599,67 @@ reset_fw:
|
||||
ver->lmp_ver, ver->lmp_subver);
|
||||
kfree_skb(skb);
|
||||
|
||||
/* Read BD Address */
|
||||
skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL,
|
||||
HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
ret = PTR_ERR(skb);
|
||||
BT_ERR("%s: HCI_OP_READ_BD_ADDR failed (%ld)",
|
||||
hdev->name, ret);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (skb->len != sizeof(*bda)) {
|
||||
BT_ERR("%s: HCI_OP_READ_BD_ADDR event length mismatch",
|
||||
hdev->name);
|
||||
kfree_skb(skb);
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
bda = (struct hci_rp_read_bd_addr *) skb->data;
|
||||
if (bda->status) {
|
||||
BT_ERR("%s: HCI_OP_READ_BD_ADDR error status (%02x)",
|
||||
hdev->name, bda->status);
|
||||
kfree_skb(skb);
|
||||
ret = -bt_to_errno(bda->status);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller
|
||||
* with no configured address.
|
||||
*/
|
||||
if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0)) {
|
||||
BT_INFO("%s: BCM: using default device address (%pMR)",
|
||||
hdev->name, &bda->bdaddr);
|
||||
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
done:
|
||||
release_firmware(fw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int btusb_set_bdaddr_bcm(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
long ret;
|
||||
|
||||
skb = __hci_cmd_sync(hdev, 0xfc01, 6, bdaddr, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
ret = PTR_ERR(skb);
|
||||
BT_ERR("%s: BCM: Change address command failed (%ld)",
|
||||
hdev->name, ret);
|
||||
return ret;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btusb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
@ -1555,15 +1684,6 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
if (id->driver_info == BTUSB_IGNORE)
|
||||
return -ENODEV;
|
||||
|
||||
if (ignore_dga && id->driver_info & BTUSB_DIGIANSWER)
|
||||
return -ENODEV;
|
||||
|
||||
if (ignore_csr && id->driver_info & BTUSB_CSR)
|
||||
return -ENODEV;
|
||||
|
||||
if (ignore_sniffer && id->driver_info & BTUSB_SNIFFER)
|
||||
return -ENODEV;
|
||||
|
||||
if (id->driver_info & BTUSB_ATH3012) {
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
|
||||
@ -1636,11 +1756,18 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
if (id->driver_info & BTUSB_BCM92035)
|
||||
hdev->setup = btusb_setup_bcm92035;
|
||||
|
||||
if (id->driver_info & BTUSB_BCM_PATCHRAM)
|
||||
if (id->driver_info & BTUSB_BCM_PATCHRAM) {
|
||||
hdev->setup = btusb_setup_bcm_patchram;
|
||||
hdev->set_bdaddr = btusb_set_bdaddr_bcm;
|
||||
}
|
||||
|
||||
if (id->driver_info & BTUSB_INTEL)
|
||||
if (id->driver_info & BTUSB_INTEL) {
|
||||
hdev->setup = btusb_setup_intel;
|
||||
hdev->set_bdaddr = btusb_set_bdaddr_intel;
|
||||
}
|
||||
|
||||
if (id->driver_info & BTUSB_INTEL_BOOT)
|
||||
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
|
||||
|
||||
/* Interface numbers are hardcoded in the specification */
|
||||
data->isoc = usb_ifnum_to_if(data->udev, 1);
|
||||
@ -1680,8 +1807,18 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
/* New sniffer firmware has crippled HCI interface */
|
||||
if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997)
|
||||
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
|
||||
}
|
||||
|
||||
data->isoc = NULL;
|
||||
if (id->driver_info & BTUSB_INTEL_BOOT) {
|
||||
/* A bug in the bootloader causes that interrupt interface is
|
||||
* only enabled after receiving SetInterface(0, AltSetting=0).
|
||||
*/
|
||||
err = usb_set_interface(data->udev, 0, 0);
|
||||
if (err < 0) {
|
||||
BT_ERR("failed to set interface 0, alt 0 %d", err);
|
||||
hci_free_dev(hdev);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->isoc) {
|
||||
@ -1846,15 +1983,6 @@ static struct usb_driver btusb_driver = {
|
||||
|
||||
module_usb_driver(btusb_driver);
|
||||
|
||||
module_param(ignore_dga, bool, 0644);
|
||||
MODULE_PARM_DESC(ignore_dga, "Ignore devices with id 08fd:0001");
|
||||
|
||||
module_param(ignore_csr, bool, 0644);
|
||||
MODULE_PARM_DESC(ignore_csr, "Ignore devices with id 0a12:0001");
|
||||
|
||||
module_param(ignore_sniffer, bool, 0644);
|
||||
MODULE_PARM_DESC(ignore_sniffer, "Ignore devices with id 0a12:0002");
|
||||
|
||||
module_param(disable_scofix, bool, 0644);
|
||||
MODULE_PARM_DESC(disable_scofix, "Disable fixup of wrong SCO buffer size");
|
||||
|
||||
|
@ -355,10 +355,7 @@ static void h5_complete_rx_pkt(struct hci_uart *hu)
|
||||
|
||||
static int h5_rx_crc(struct hci_uart *hu, unsigned char c)
|
||||
{
|
||||
struct h5 *h5 = hu->priv;
|
||||
|
||||
h5_complete_rx_pkt(hu);
|
||||
h5_reset_rx(h5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -373,7 +370,6 @@ static int h5_rx_payload(struct hci_uart *hu, unsigned char c)
|
||||
h5->rx_pending = 2;
|
||||
} else {
|
||||
h5_complete_rx_pkt(hu);
|
||||
h5_reset_rx(h5);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -406,6 +402,7 @@ static int h5_rx_3wire_hdr(struct hci_uart *hu, unsigned char c)
|
||||
H5_HDR_PKT_TYPE(hdr) != HCI_3WIRE_LINK_PKT) {
|
||||
BT_ERR("Non-link packet received in non-active state");
|
||||
h5_reset_rx(h5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
h5->rx_func = h5_rx_payload;
|
||||
|
@ -40,7 +40,7 @@
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
||||
#define VERSION "1.4"
|
||||
#define VERSION "1.5"
|
||||
|
||||
static bool amp;
|
||||
|
||||
@ -95,10 +95,21 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vhci_create_device(struct vhci_data *data, __u8 dev_type)
|
||||
static int vhci_create_device(struct vhci_data *data, __u8 opcode)
|
||||
{
|
||||
struct hci_dev *hdev;
|
||||
struct sk_buff *skb;
|
||||
__u8 dev_type;
|
||||
|
||||
/* bits 0-1 are dev_type (BR/EDR or AMP) */
|
||||
dev_type = opcode & 0x03;
|
||||
|
||||
if (dev_type != HCI_BREDR && dev_type != HCI_AMP)
|
||||
return -EINVAL;
|
||||
|
||||
/* bits 2-5 are reserved (must be zero) */
|
||||
if (opcode & 0x3c)
|
||||
return -EINVAL;
|
||||
|
||||
skb = bt_skb_alloc(4, GFP_KERNEL);
|
||||
if (!skb)
|
||||
@ -121,6 +132,14 @@ static int vhci_create_device(struct vhci_data *data, __u8 dev_type)
|
||||
hdev->flush = vhci_flush;
|
||||
hdev->send = vhci_send_frame;
|
||||
|
||||
/* bit 6 is for external configuration */
|
||||
if (opcode & 0x40)
|
||||
set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks);
|
||||
|
||||
/* bit 7 is for raw device */
|
||||
if (opcode & 0x80)
|
||||
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
|
||||
|
||||
if (hci_register_dev(hdev) < 0) {
|
||||
BT_ERR("Can't register HCI device");
|
||||
hci_free_dev(hdev);
|
||||
@ -132,7 +151,7 @@ static int vhci_create_device(struct vhci_data *data, __u8 dev_type)
|
||||
bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
|
||||
|
||||
*skb_put(skb, 1) = 0xff;
|
||||
*skb_put(skb, 1) = dev_type;
|
||||
*skb_put(skb, 1) = opcode;
|
||||
put_unaligned_le16(hdev->id, skb_put(skb, 2));
|
||||
skb_queue_tail(&data->readq, skb);
|
||||
|
||||
@ -146,7 +165,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
|
||||
{
|
||||
size_t len = iov_length(iov, count);
|
||||
struct sk_buff *skb;
|
||||
__u8 pkt_type, dev_type;
|
||||
__u8 pkt_type, opcode;
|
||||
unsigned long i;
|
||||
int ret;
|
||||
|
||||
@ -190,7 +209,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
|
||||
|
||||
cancel_delayed_work_sync(&data->open_timeout);
|
||||
|
||||
dev_type = *((__u8 *) skb->data);
|
||||
opcode = *((__u8 *) skb->data);
|
||||
skb_pull(skb, 1);
|
||||
|
||||
if (skb->len > 0) {
|
||||
@ -200,10 +219,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
if (dev_type != HCI_BREDR && dev_type != HCI_AMP)
|
||||
return -EINVAL;
|
||||
|
||||
ret = vhci_create_device(data, dev_type);
|
||||
ret = vhci_create_device(data, opcode);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -795,7 +795,11 @@ int ath10k_core_start(struct ath10k *ar)
|
||||
if (status)
|
||||
goto err_htc_stop;
|
||||
|
||||
ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1;
|
||||
if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
|
||||
ar->free_vdev_map = (1 << TARGET_10X_NUM_VDEVS) - 1;
|
||||
else
|
||||
ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1;
|
||||
|
||||
INIT_LIST_HEAD(&ar->arvifs);
|
||||
|
||||
if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
|
||||
|
@ -312,7 +312,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||
int msdu_len, msdu_chaining = 0;
|
||||
struct sk_buff *msdu;
|
||||
struct htt_rx_desc *rx_desc;
|
||||
bool corrupted = false;
|
||||
|
||||
lockdep_assert_held(&htt->rx_ring.lock);
|
||||
|
||||
@ -439,9 +438,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||
last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) &
|
||||
RX_MSDU_END_INFO0_LAST_MSDU;
|
||||
|
||||
if (msdu_chaining && !last_msdu)
|
||||
corrupted = true;
|
||||
|
||||
if (last_msdu) {
|
||||
msdu->next = NULL;
|
||||
break;
|
||||
@ -456,20 +452,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
|
||||
if (*head_msdu == NULL)
|
||||
msdu_chaining = -1;
|
||||
|
||||
/*
|
||||
* Apparently FW sometimes reports weird chained MSDU sequences with
|
||||
* more than one rx descriptor. This seems like a bug but needs more
|
||||
* analyzing. For the time being fix it by dropping such sequences to
|
||||
* avoid blowing up the host system.
|
||||
*/
|
||||
if (corrupted) {
|
||||
ath10k_warn("failed to pop chained msdus, dropping\n");
|
||||
ath10k_htt_rx_free_msdu_chain(*head_msdu);
|
||||
*head_msdu = NULL;
|
||||
*tail_msdu = NULL;
|
||||
msdu_chaining = -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't refill the ring yet.
|
||||
*
|
||||
|
@ -1183,8 +1183,6 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
|
||||
bus->bus_priv.usb = bus_pub;
|
||||
dev_set_drvdata(dev, bus);
|
||||
bus->ops = &brcmf_usb_bus_ops;
|
||||
bus->chip = bus_pub->devid;
|
||||
bus->chiprev = bus_pub->chiprev;
|
||||
bus->proto_type = BRCMF_PROTO_BCDC;
|
||||
bus->always_use_fws_queue = true;
|
||||
|
||||
@ -1193,6 +1191,9 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
|
||||
if (ret)
|
||||
goto fail;
|
||||
}
|
||||
bus->chip = bus_pub->devid;
|
||||
bus->chiprev = bus_pub->chiprev;
|
||||
|
||||
/* request firmware here */
|
||||
brcmf_fw_get_firmwares(dev, 0, brcmf_usb_get_fwname(devinfo), NULL,
|
||||
brcmf_usb_probe_phase2);
|
||||
|
@ -185,6 +185,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
|
||||
skb_reserve(skb_aggr, headroom + sizeof(struct txpd));
|
||||
tx_info_aggr = MWIFIEX_SKB_TXCB(skb_aggr);
|
||||
|
||||
memset(tx_info_aggr, 0, sizeof(*tx_info_aggr));
|
||||
tx_info_aggr->bss_type = tx_info_src->bss_type;
|
||||
tx_info_aggr->bss_num = tx_info_src->bss_num;
|
||||
|
||||
|
@ -188,6 +188,7 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
}
|
||||
|
||||
tx_info = MWIFIEX_SKB_TXCB(skb);
|
||||
memset(tx_info, 0, sizeof(*tx_info));
|
||||
tx_info->bss_num = priv->bss_num;
|
||||
tx_info->bss_type = priv->bss_type;
|
||||
tx_info->pkt_len = pkt_len;
|
||||
|
@ -462,6 +462,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
|
||||
|
||||
if (skb) {
|
||||
rx_info = MWIFIEX_SKB_RXCB(skb);
|
||||
memset(rx_info, 0, sizeof(*rx_info));
|
||||
rx_info->bss_num = priv->bss_num;
|
||||
rx_info->bss_type = priv->bss_type;
|
||||
}
|
||||
|
@ -644,6 +644,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
}
|
||||
|
||||
tx_info = MWIFIEX_SKB_TXCB(skb);
|
||||
memset(tx_info, 0, sizeof(*tx_info));
|
||||
tx_info->bss_num = priv->bss_num;
|
||||
tx_info->bss_type = priv->bss_type;
|
||||
tx_info->pkt_len = skb->len;
|
||||
|
@ -150,6 +150,7 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
|
||||
return -1;
|
||||
|
||||
tx_info = MWIFIEX_SKB_TXCB(skb);
|
||||
memset(tx_info, 0, sizeof(*tx_info));
|
||||
tx_info->bss_num = priv->bss_num;
|
||||
tx_info->bss_type = priv->bss_type;
|
||||
tx_info->pkt_len = data_len - (sizeof(struct txpd) + INTF_HEADER_LEN);
|
||||
|
@ -604,6 +604,7 @@ int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer,
|
||||
}
|
||||
|
||||
tx_info = MWIFIEX_SKB_TXCB(skb);
|
||||
memset(tx_info, 0, sizeof(*tx_info));
|
||||
tx_info->bss_num = priv->bss_num;
|
||||
tx_info->bss_type = priv->bss_type;
|
||||
|
||||
@ -757,6 +758,7 @@ int mwifiex_send_tdls_action_frame(struct mwifiex_private *priv, const u8 *peer,
|
||||
skb->priority = MWIFIEX_PRIO_VI;
|
||||
|
||||
tx_info = MWIFIEX_SKB_TXCB(skb);
|
||||
memset(tx_info, 0, sizeof(*tx_info));
|
||||
tx_info->bss_num = priv->bss_num;
|
||||
tx_info->bss_type = priv->bss_type;
|
||||
tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT;
|
||||
|
@ -55,6 +55,7 @@ int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(rx_info, 0, sizeof(*rx_info));
|
||||
rx_info->bss_num = priv->bss_num;
|
||||
rx_info->bss_type = priv->bss_type;
|
||||
|
||||
|
@ -174,6 +174,7 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
|
||||
}
|
||||
|
||||
tx_info = MWIFIEX_SKB_TXCB(skb);
|
||||
memset(tx_info, 0, sizeof(*tx_info));
|
||||
tx_info->bss_num = priv->bss_num;
|
||||
tx_info->bss_type = priv->bss_type;
|
||||
tx_info->flags |= MWIFIEX_BUF_FLAG_BRIDGED_PKT;
|
||||
|
@ -231,9 +231,12 @@ static enum hrtimer_restart rt2800usb_tx_sta_fifo_timeout(struct hrtimer *timer)
|
||||
*/
|
||||
static int rt2800usb_autorun_detect(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
__le32 reg;
|
||||
__le32 *reg;
|
||||
u32 fw_mode;
|
||||
|
||||
reg = kmalloc(sizeof(*reg), GFP_KERNEL);
|
||||
if (reg == NULL)
|
||||
return -ENOMEM;
|
||||
/* 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
|
||||
@ -241,8 +244,9 @@ static int rt2800usb_autorun_detect(struct rt2x00_dev *rt2x00dev)
|
||||
*/
|
||||
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);
|
||||
reg, sizeof(*reg), REGISTER_TIMEOUT_FIRMWARE);
|
||||
fw_mode = le32_to_cpu(*reg);
|
||||
kfree(reg);
|
||||
|
||||
if ((fw_mode & 0x00000003) == 2)
|
||||
return 1;
|
||||
@ -261,6 +265,7 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
|
||||
int status;
|
||||
u32 offset;
|
||||
u32 length;
|
||||
int retval;
|
||||
|
||||
/*
|
||||
* Check which section of the firmware we need.
|
||||
@ -278,7 +283,10 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
|
||||
/*
|
||||
* Write firmware to device.
|
||||
*/
|
||||
if (rt2800usb_autorun_detect(rt2x00dev)) {
|
||||
retval = rt2800usb_autorun_detect(rt2x00dev);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
if (retval) {
|
||||
rt2x00_info(rt2x00dev,
|
||||
"Firmware loading not required - NIC in AutoRun mode\n");
|
||||
} else {
|
||||
@ -763,7 +771,12 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
|
||||
*/
|
||||
static int rt2800usb_efuse_detect(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
if (rt2800usb_autorun_detect(rt2x00dev))
|
||||
int retval;
|
||||
|
||||
retval = rt2800usb_autorun_detect(rt2x00dev);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
if (retval)
|
||||
return 1;
|
||||
return rt2800_efuse_detect(rt2x00dev);
|
||||
}
|
||||
@ -772,7 +785,10 @@ static int rt2800usb_read_eeprom(struct rt2x00_dev *rt2x00dev)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (rt2800usb_efuse_detect(rt2x00dev))
|
||||
retval = rt2800usb_efuse_detect(rt2x00dev);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
if (retval)
|
||||
retval = rt2800_read_eeprom_efuse(rt2x00dev);
|
||||
else
|
||||
retval = rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom,
|
||||
|
@ -260,15 +260,15 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
|
||||
|
||||
/* Skb helpers */
|
||||
struct l2cap_ctrl {
|
||||
unsigned int sframe:1,
|
||||
poll:1,
|
||||
final:1,
|
||||
fcs:1,
|
||||
sar:2,
|
||||
super:2;
|
||||
__u16 reqseq;
|
||||
__u16 txseq;
|
||||
__u8 retries;
|
||||
__u8 sframe:1,
|
||||
poll:1,
|
||||
final:1,
|
||||
fcs:1,
|
||||
sar:2,
|
||||
super:2;
|
||||
__u16 reqseq;
|
||||
__u16 txseq;
|
||||
__u8 retries;
|
||||
};
|
||||
|
||||
struct hci_dev;
|
||||
|
@ -81,10 +81,54 @@
|
||||
|
||||
/* HCI device quirks */
|
||||
enum {
|
||||
/* When this quirk is set, the HCI Reset command is send when
|
||||
* closing the transport instead of when opening it.
|
||||
*
|
||||
* This quirk must be set before hci_register_dev is called.
|
||||
*/
|
||||
HCI_QUIRK_RESET_ON_CLOSE,
|
||||
|
||||
/* When this quirk is set, the device is turned into a raw-only
|
||||
* device and it will stay in unconfigured state.
|
||||
*
|
||||
* This quirk must be set before hci_register_dev is called.
|
||||
*/
|
||||
HCI_QUIRK_RAW_DEVICE,
|
||||
|
||||
/* When this quirk is set, the buffer sizes reported by
|
||||
* HCI Read Buffer Size command are corrected if invalid.
|
||||
*
|
||||
* This quirk must be set before hci_register_dev is called.
|
||||
*/
|
||||
HCI_QUIRK_FIXUP_BUFFER_SIZE,
|
||||
|
||||
/* When this quirk is set, then no stored link key handling
|
||||
* is performed. This is mainly due to the fact that the
|
||||
* HCI Delete Stored Link Key command is advertised, but
|
||||
* not supported.
|
||||
*
|
||||
* This quirk must be set before hci_register_dev is called.
|
||||
*/
|
||||
HCI_QUIRK_BROKEN_STORED_LINK_KEY,
|
||||
|
||||
/* When this quirk is set, an external configuration step
|
||||
* is required and will be indicated with the controller
|
||||
* configuation.
|
||||
*
|
||||
* This quirk can be set before hci_register_dev is called or
|
||||
* during the hdev->setup vendor callback.
|
||||
*/
|
||||
HCI_QUIRK_EXTERNAL_CONFIG,
|
||||
|
||||
/* When this quirk is set, the public Bluetooth address
|
||||
* initially reported by HCI Read BD Address command
|
||||
* is considered invalid. Controller configuration is
|
||||
* required before this device can be used.
|
||||
*
|
||||
* This quirk can be set before hci_register_dev is called or
|
||||
* during the hdev->setup vendor callback.
|
||||
*/
|
||||
HCI_QUIRK_INVALID_BDADDR,
|
||||
};
|
||||
|
||||
/* HCI device flags */
|
||||
@ -104,24 +148,34 @@ enum {
|
||||
HCI_RESET,
|
||||
};
|
||||
|
||||
/* BR/EDR and/or LE controller flags: the flags defined here should represent
|
||||
* states configured via debugfs for debugging and testing purposes only.
|
||||
*/
|
||||
enum {
|
||||
HCI_DUT_MODE,
|
||||
HCI_FORCE_SC,
|
||||
HCI_FORCE_STATIC_ADDR,
|
||||
};
|
||||
|
||||
/*
|
||||
* BR/EDR and/or LE controller flags: the flags defined here should represent
|
||||
* states from the controller.
|
||||
*/
|
||||
enum {
|
||||
HCI_SETUP,
|
||||
HCI_CONFIG,
|
||||
HCI_AUTO_OFF,
|
||||
HCI_RFKILLED,
|
||||
HCI_MGMT,
|
||||
HCI_PAIRABLE,
|
||||
HCI_SERVICE_CACHE,
|
||||
HCI_DEBUG_KEYS,
|
||||
HCI_DUT_MODE,
|
||||
HCI_FORCE_SC,
|
||||
HCI_FORCE_STATIC_ADDR,
|
||||
HCI_KEEP_DEBUG_KEYS,
|
||||
HCI_USE_DEBUG_KEYS,
|
||||
HCI_UNREGISTER,
|
||||
HCI_UNCONFIGURED,
|
||||
HCI_USER_CHANNEL,
|
||||
|
||||
HCI_EXT_CONFIGURED,
|
||||
HCI_LE_ADV,
|
||||
HCI_LE_SCAN,
|
||||
HCI_SSP_ENABLED,
|
||||
HCI_SC_ENABLED,
|
||||
@ -139,7 +193,6 @@ enum {
|
||||
HCI_PERIODIC_INQ,
|
||||
HCI_FAST_CONNECTABLE,
|
||||
HCI_BREDR_ENABLED,
|
||||
HCI_6LOWPAN_ENABLED,
|
||||
HCI_LE_SCAN_INTERRUPTED,
|
||||
};
|
||||
|
||||
@ -147,7 +200,7 @@ enum {
|
||||
* or the HCI device is closed.
|
||||
*/
|
||||
#define HCI_PERSISTENT_MASK (BIT(HCI_LE_SCAN) | BIT(HCI_PERIODIC_INQ) | \
|
||||
BIT(HCI_FAST_CONNECTABLE))
|
||||
BIT(HCI_FAST_CONNECTABLE) | BIT(HCI_LE_ADV))
|
||||
|
||||
/* HCI ioctl defines */
|
||||
#define HCIDEVUP _IOW('H', 201, int)
|
||||
@ -185,6 +238,7 @@ enum {
|
||||
#define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
|
||||
#define HCI_POWER_OFF_TIMEOUT msecs_to_jiffies(5000) /* 5 seconds */
|
||||
#define HCI_LE_CONN_TIMEOUT msecs_to_jiffies(20000) /* 20 seconds */
|
||||
#define HCI_LE_AUTOCONN_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
|
||||
|
||||
/* HCI data types */
|
||||
#define HCI_COMMAND_PKT 0x01
|
||||
@ -301,6 +355,10 @@ enum {
|
||||
#define LMP_HOST_LE_BREDR 0x04
|
||||
#define LMP_HOST_SC 0x08
|
||||
|
||||
/* LE features */
|
||||
#define HCI_LE_CONN_PARAM_REQ_PROC 0x02
|
||||
#define HCI_LE_PING 0x10
|
||||
|
||||
/* Connection modes */
|
||||
#define HCI_CM_ACTIVE 0x0000
|
||||
#define HCI_CM_HOLD 0x0001
|
||||
@ -347,17 +405,9 @@ enum {
|
||||
#define HCI_LK_CHANGED_COMBINATION 0x06
|
||||
#define HCI_LK_UNAUTH_COMBINATION_P256 0x07
|
||||
#define HCI_LK_AUTH_COMBINATION_P256 0x08
|
||||
/* The spec doesn't define types for SMP keys, the _MASTER suffix is implied */
|
||||
#define HCI_SMP_STK 0x80
|
||||
#define HCI_SMP_STK_SLAVE 0x81
|
||||
#define HCI_SMP_LTK 0x82
|
||||
#define HCI_SMP_LTK_SLAVE 0x83
|
||||
|
||||
/* Long Term Key types */
|
||||
#define HCI_LTK_UNAUTH 0x00
|
||||
#define HCI_LTK_AUTH 0x01
|
||||
|
||||
/* ---- HCI Error Codes ---- */
|
||||
#define HCI_ERROR_UNKNOWN_CONN_ID 0x02
|
||||
#define HCI_ERROR_AUTH_FAILURE 0x05
|
||||
#define HCI_ERROR_MEMORY_EXCEEDED 0x07
|
||||
#define HCI_ERROR_CONNECTION_TIMEOUT 0x08
|
||||
@ -367,6 +417,7 @@ enum {
|
||||
#define HCI_ERROR_REMOTE_POWER_OFF 0x15
|
||||
#define HCI_ERROR_LOCAL_HOST_TERM 0x16
|
||||
#define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18
|
||||
#define HCI_ERROR_INVALID_LL_PARAMS 0x1E
|
||||
#define HCI_ERROR_ADVERTISING_TIMEOUT 0x3c
|
||||
|
||||
/* Flow control modes */
|
||||
@ -536,6 +587,11 @@ struct hci_cp_read_remote_version {
|
||||
__le16 handle;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_READ_CLOCK_OFFSET 0x041f
|
||||
struct hci_cp_read_clock_offset {
|
||||
__le16 handle;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_SETUP_SYNC_CONN 0x0428
|
||||
struct hci_cp_setup_sync_conn {
|
||||
__le16 handle;
|
||||
@ -1085,6 +1141,18 @@ struct hci_rp_read_rssi {
|
||||
__s8 rssi;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_READ_CLOCK 0x1407
|
||||
struct hci_cp_read_clock {
|
||||
__le16 handle;
|
||||
__u8 which;
|
||||
} __packed;
|
||||
struct hci_rp_read_clock {
|
||||
__u8 status;
|
||||
__le16 handle;
|
||||
__le32 clock;
|
||||
__le16 accuracy;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_READ_LOCAL_AMP_INFO 0x1409
|
||||
struct hci_rp_read_local_amp_info {
|
||||
__u8 status;
|
||||
@ -1291,6 +1359,23 @@ struct hci_rp_le_read_supported_states {
|
||||
__u8 le_states[8];
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_CONN_PARAM_REQ_REPLY 0x2020
|
||||
struct hci_cp_le_conn_param_req_reply {
|
||||
__le16 handle;
|
||||
__le16 interval_min;
|
||||
__le16 interval_max;
|
||||
__le16 latency;
|
||||
__le16 timeout;
|
||||
__le16 min_ce_len;
|
||||
__le16 max_ce_len;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_CONN_PARAM_REQ_NEG_REPLY 0x2021
|
||||
struct hci_cp_le_conn_param_req_neg_reply {
|
||||
__le16 handle;
|
||||
__u8 reason;
|
||||
} __packed;
|
||||
|
||||
/* ---- HCI Events ---- */
|
||||
#define HCI_EV_INQUIRY_COMPLETE 0x01
|
||||
|
||||
@ -1670,6 +1755,15 @@ struct hci_ev_le_conn_complete {
|
||||
__u8 clk_accurancy;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_LE_CONN_UPDATE_COMPLETE 0x03
|
||||
struct hci_ev_le_conn_update_complete {
|
||||
__u8 status;
|
||||
__le16 handle;
|
||||
__le16 interval;
|
||||
__le16 latency;
|
||||
__le16 supervision_timeout;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_LE_LTK_REQ 0x05
|
||||
struct hci_ev_le_ltk_req {
|
||||
__le16 handle;
|
||||
@ -1677,6 +1771,15 @@ struct hci_ev_le_ltk_req {
|
||||
__le16 ediv;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_LE_REMOTE_CONN_PARAM_REQ 0x06
|
||||
struct hci_ev_le_remote_conn_param_req {
|
||||
__le16 handle;
|
||||
__le16 interval_min;
|
||||
__le16 interval_max;
|
||||
__le16 latency;
|
||||
__le16 timeout;
|
||||
} __packed;
|
||||
|
||||
/* Advertising report event types */
|
||||
#define LE_ADV_IND 0x00
|
||||
#define LE_ADV_DIRECT_IND 0x01
|
||||
|
@ -71,6 +71,7 @@ struct discovery_state {
|
||||
bdaddr_t last_adv_addr;
|
||||
u8 last_adv_addr_type;
|
||||
s8 last_adv_rssi;
|
||||
u32 last_adv_flags;
|
||||
u8 last_adv_data[HCI_MAX_AD_LENGTH];
|
||||
u8 last_adv_data_len;
|
||||
};
|
||||
@ -170,6 +171,8 @@ struct hci_dev {
|
||||
__u8 bus;
|
||||
__u8 dev_type;
|
||||
bdaddr_t bdaddr;
|
||||
bdaddr_t setup_addr;
|
||||
bdaddr_t public_addr;
|
||||
bdaddr_t random_addr;
|
||||
bdaddr_t static_addr;
|
||||
__u8 adv_addr_type;
|
||||
@ -203,10 +206,13 @@ struct hci_dev {
|
||||
__u16 le_scan_window;
|
||||
__u16 le_conn_min_interval;
|
||||
__u16 le_conn_max_interval;
|
||||
__u16 le_conn_latency;
|
||||
__u16 le_supv_timeout;
|
||||
__u16 discov_interleaved_timeout;
|
||||
__u16 conn_info_min_age;
|
||||
__u16 conn_info_max_age;
|
||||
__u8 ssp_debug_mode;
|
||||
__u32 clock;
|
||||
|
||||
__u16 devid_source;
|
||||
__u16 devid_vendor;
|
||||
@ -273,7 +279,7 @@ struct hci_dev {
|
||||
|
||||
struct delayed_work service_cache;
|
||||
|
||||
struct timer_list cmd_timer;
|
||||
struct delayed_work cmd_timer;
|
||||
|
||||
struct work_struct rx_work;
|
||||
struct work_struct cmd_work;
|
||||
@ -299,6 +305,7 @@ struct hci_dev {
|
||||
|
||||
struct list_head mgmt_pending;
|
||||
struct list_head blacklist;
|
||||
struct list_head whitelist;
|
||||
struct list_head uuids;
|
||||
struct list_head link_keys;
|
||||
struct list_head long_term_keys;
|
||||
@ -307,6 +314,7 @@ struct hci_dev {
|
||||
struct list_head le_white_list;
|
||||
struct list_head le_conn_params;
|
||||
struct list_head pend_le_conns;
|
||||
struct list_head pend_le_reports;
|
||||
|
||||
struct hci_dev_stats stat;
|
||||
|
||||
@ -318,6 +326,7 @@ struct hci_dev {
|
||||
|
||||
struct rfkill *rfkill;
|
||||
|
||||
unsigned long dbg_flags;
|
||||
unsigned long dev_flags;
|
||||
|
||||
struct delayed_work le_scan_disable;
|
||||
@ -339,6 +348,7 @@ struct hci_dev {
|
||||
int (*setup)(struct hci_dev *hdev);
|
||||
int (*send)(struct hci_dev *hdev, struct sk_buff *skb);
|
||||
void (*notify)(struct hci_dev *hdev, unsigned int evt);
|
||||
int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
|
||||
};
|
||||
|
||||
#define HCI_PHY_HANDLE(handle) (handle & 0xff)
|
||||
@ -366,7 +376,6 @@ struct hci_conn {
|
||||
__u8 features[HCI_MAX_PAGES][8];
|
||||
__u16 pkt_type;
|
||||
__u16 link_policy;
|
||||
__u32 link_mode;
|
||||
__u8 key_type;
|
||||
__u8 auth_type;
|
||||
__u8 sec_level;
|
||||
@ -377,20 +386,26 @@ struct hci_conn {
|
||||
__u32 passkey_notify;
|
||||
__u8 passkey_entered;
|
||||
__u16 disc_timeout;
|
||||
__u16 conn_timeout;
|
||||
__u16 setting;
|
||||
__u16 le_conn_min_interval;
|
||||
__u16 le_conn_max_interval;
|
||||
__u16 le_conn_interval;
|
||||
__u16 le_conn_latency;
|
||||
__u16 le_supv_timeout;
|
||||
__s8 rssi;
|
||||
__s8 tx_power;
|
||||
__s8 max_tx_power;
|
||||
unsigned long flags;
|
||||
|
||||
__u32 clock;
|
||||
__u16 clock_accuracy;
|
||||
|
||||
unsigned long conn_info_timestamp;
|
||||
|
||||
__u8 remote_cap;
|
||||
__u8 remote_auth;
|
||||
__u8 remote_id;
|
||||
bool flush_key;
|
||||
|
||||
unsigned int sent;
|
||||
|
||||
@ -407,7 +422,6 @@ struct hci_conn {
|
||||
struct hci_dev *hdev;
|
||||
void *l2cap_data;
|
||||
void *sco_data;
|
||||
void *smp_conn;
|
||||
struct amp_mgr *amp_mgr;
|
||||
|
||||
struct hci_conn *link;
|
||||
@ -428,15 +442,19 @@ struct hci_chan {
|
||||
|
||||
struct hci_conn_params {
|
||||
struct list_head list;
|
||||
struct list_head action;
|
||||
|
||||
bdaddr_t addr;
|
||||
u8 addr_type;
|
||||
|
||||
u16 conn_min_interval;
|
||||
u16 conn_max_interval;
|
||||
u16 conn_latency;
|
||||
u16 supervision_timeout;
|
||||
|
||||
enum {
|
||||
HCI_AUTO_CONN_DISABLED,
|
||||
HCI_AUTO_CONN_REPORT,
|
||||
HCI_AUTO_CONN_ALWAYS,
|
||||
HCI_AUTO_CONN_LINK_LOSS,
|
||||
} auto_connect;
|
||||
@ -501,8 +519,8 @@ struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev,
|
||||
int state);
|
||||
void hci_inquiry_cache_update_resolve(struct hci_dev *hdev,
|
||||
struct inquiry_entry *ie);
|
||||
bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
|
||||
bool name_known, bool *ssp);
|
||||
u32 hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
|
||||
bool name_known);
|
||||
void hci_inquiry_cache_flush(struct hci_dev *hdev);
|
||||
|
||||
/* ----- HCI Connections ----- */
|
||||
@ -520,7 +538,13 @@ enum {
|
||||
HCI_CONN_AES_CCM,
|
||||
HCI_CONN_POWER_SAVE,
|
||||
HCI_CONN_REMOTE_OOB,
|
||||
HCI_CONN_6LOWPAN,
|
||||
HCI_CONN_FLUSH_KEY,
|
||||
HCI_CONN_MASTER,
|
||||
HCI_CONN_ENCRYPT,
|
||||
HCI_CONN_AUTH,
|
||||
HCI_CONN_SECURE,
|
||||
HCI_CONN_FIPS,
|
||||
HCI_CONN_STK_ENCRYPT,
|
||||
};
|
||||
|
||||
static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
|
||||
@ -681,7 +705,8 @@ void hci_chan_list_flush(struct hci_conn *conn);
|
||||
struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle);
|
||||
|
||||
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
u8 dst_type, u8 sec_level, u8 auth_type);
|
||||
u8 dst_type, u8 sec_level, u16 conn_timeout,
|
||||
bool master);
|
||||
struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
u8 sec_level, u8 auth_type);
|
||||
struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
@ -825,30 +850,25 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg);
|
||||
int hci_get_auth_info(struct hci_dev *hdev, void __user *arg);
|
||||
int hci_inquiry(void __user *arg);
|
||||
|
||||
struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr, u8 type);
|
||||
int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
|
||||
struct bdaddr_list *hci_white_list_lookup(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr, u8 type);
|
||||
void hci_white_list_clear(struct hci_dev *hdev);
|
||||
int hci_white_list_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
int hci_white_list_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *list,
|
||||
bdaddr_t *bdaddr, u8 type);
|
||||
int hci_bdaddr_list_add(struct list_head *list, bdaddr_t *bdaddr, u8 type);
|
||||
int hci_bdaddr_list_del(struct list_head *list, bdaddr_t *bdaddr, u8 type);
|
||||
void hci_bdaddr_list_clear(struct list_head *list);
|
||||
|
||||
struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
|
||||
bdaddr_t *addr, u8 addr_type);
|
||||
int hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
|
||||
u8 auto_connect, u16 conn_min_interval,
|
||||
u16 conn_max_interval);
|
||||
void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
|
||||
void hci_conn_params_clear(struct hci_dev *hdev);
|
||||
|
||||
struct bdaddr_list *hci_pend_le_conn_lookup(struct hci_dev *hdev,
|
||||
struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev,
|
||||
bdaddr_t *addr, u8 addr_type);
|
||||
void hci_pend_le_conn_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
|
||||
void hci_pend_le_conn_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
|
||||
void hci_pend_le_conns_clear(struct hci_dev *hdev);
|
||||
int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
|
||||
u8 auto_connect);
|
||||
void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
|
||||
void hci_conn_params_clear_all(struct hci_dev *hdev);
|
||||
void hci_conn_params_clear_disabled(struct hci_dev *hdev);
|
||||
|
||||
struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list,
|
||||
bdaddr_t *addr,
|
||||
u8 addr_type);
|
||||
|
||||
void hci_update_background_scan(struct hci_dev *hdev);
|
||||
|
||||
@ -856,8 +876,9 @@ void hci_uuids_clear(struct hci_dev *hdev);
|
||||
|
||||
void hci_link_keys_clear(struct hci_dev *hdev);
|
||||
struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
|
||||
bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len);
|
||||
struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn,
|
||||
bdaddr_t *bdaddr, u8 *val, u8 type,
|
||||
u8 pin_len, bool *persistent);
|
||||
struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand,
|
||||
bool master);
|
||||
struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
@ -1021,7 +1042,7 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
|
||||
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
|
||||
return;
|
||||
|
||||
encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
|
||||
encrypt = test_bit(HCI_CONN_ENCRYPT, &conn->flags) ? 0x01 : 0x00;
|
||||
l2cap_security_cfm(conn, status, encrypt);
|
||||
|
||||
if (conn->security_cfm_cb)
|
||||
@ -1062,7 +1083,7 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
|
||||
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags))
|
||||
return;
|
||||
|
||||
encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
|
||||
encrypt = test_bit(HCI_CONN_ENCRYPT, &conn->flags) ? 0x01 : 0x00;
|
||||
|
||||
read_lock(&hci_cb_list_lock);
|
||||
list_for_each_entry(cb, &hci_cb_list, list) {
|
||||
@ -1147,7 +1168,7 @@ static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type)
|
||||
|
||||
static inline bool hci_bdaddr_is_rpa(bdaddr_t *bdaddr, u8 addr_type)
|
||||
{
|
||||
if (addr_type != 0x01)
|
||||
if (addr_type != ADDR_LE_DEV_RANDOM)
|
||||
return false;
|
||||
|
||||
if ((bdaddr->b[5] & 0xc0) == 0x40)
|
||||
@ -1156,6 +1177,18 @@ static inline bool hci_bdaddr_is_rpa(bdaddr_t *bdaddr, u8 addr_type)
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool hci_is_identity_address(bdaddr_t *addr, u8 addr_type)
|
||||
{
|
||||
if (addr_type == ADDR_LE_DEV_PUBLIC)
|
||||
return true;
|
||||
|
||||
/* Check for Random Static address type */
|
||||
if ((addr->b[5] & 0xc0) == 0xc0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline struct smp_irk *hci_get_irk(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr, u8 addr_type)
|
||||
{
|
||||
@ -1165,6 +1198,27 @@ static inline struct smp_irk *hci_get_irk(struct hci_dev *hdev,
|
||||
return hci_find_irk_by_rpa(hdev, bdaddr);
|
||||
}
|
||||
|
||||
static inline int hci_check_conn_params(u16 min, u16 max, u16 latency,
|
||||
u16 to_multiplier)
|
||||
{
|
||||
u16 max_latency;
|
||||
|
||||
if (min > max || min < 6 || max > 3200)
|
||||
return -EINVAL;
|
||||
|
||||
if (to_multiplier < 10 || to_multiplier > 3200)
|
||||
return -EINVAL;
|
||||
|
||||
if (max >= to_multiplier * 8)
|
||||
return -EINVAL;
|
||||
|
||||
max_latency = (to_multiplier * 8 / max) - 1;
|
||||
if (latency > 499 || latency > max_latency)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hci_register_cb(struct hci_cb *hcb);
|
||||
int hci_unregister_cb(struct hci_cb *hcb);
|
||||
|
||||
@ -1227,6 +1281,7 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event);
|
||||
#define DISCOV_BREDR_INQUIRY_LEN 0x08
|
||||
|
||||
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
|
||||
int mgmt_new_settings(struct hci_dev *hdev);
|
||||
void mgmt_index_added(struct hci_dev *hdev);
|
||||
void mgmt_index_removed(struct hci_dev *hdev);
|
||||
void mgmt_set_powered_failed(struct hci_dev *hdev, int err);
|
||||
@ -1234,7 +1289,6 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered);
|
||||
void mgmt_discoverable_timeout(struct hci_dev *hdev);
|
||||
void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable);
|
||||
void mgmt_connectable(struct hci_dev *hdev, u8 connectable);
|
||||
void mgmt_advertising(struct hci_dev *hdev, u8 advertising);
|
||||
void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status);
|
||||
void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
|
||||
bool persistent);
|
||||
@ -1281,18 +1335,18 @@ void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
|
||||
u8 *randomizer192, u8 *hash256,
|
||||
u8 *randomizer256, u8 status);
|
||||
void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name,
|
||||
u8 ssp, u8 *eir, u16 eir_len, u8 *scan_rsp,
|
||||
u8 scan_rsp_len);
|
||||
u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
|
||||
u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len);
|
||||
void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, s8 rssi, u8 *name, u8 name_len);
|
||||
void mgmt_discovering(struct hci_dev *hdev, u8 discovering);
|
||||
int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent);
|
||||
void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk);
|
||||
void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
|
||||
bool persistent);
|
||||
void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 bdaddr_type, u8 store_hint, u16 min_interval,
|
||||
u16 max_interval, u16 latency, u16 timeout);
|
||||
void mgmt_reenable_advertising(struct hci_dev *hdev);
|
||||
void mgmt_smp_complete(struct hci_conn *conn, bool complete);
|
||||
|
||||
@ -1324,8 +1378,8 @@ struct hci_sec_filter {
|
||||
#define hci_req_lock(d) mutex_lock(&d->req_lock)
|
||||
#define hci_req_unlock(d) mutex_unlock(&d->req_lock)
|
||||
|
||||
void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
|
||||
u16 latency, u16 to_multiplier);
|
||||
u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
|
||||
u16 to_multiplier);
|
||||
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand,
|
||||
__u8 ltk[16]);
|
||||
|
||||
|
@ -137,7 +137,6 @@ struct l2cap_conninfo {
|
||||
#define L2CAP_FC_L2CAP 0x02
|
||||
#define L2CAP_FC_CONNLESS 0x04
|
||||
#define L2CAP_FC_A2MP 0x08
|
||||
#define L2CAP_FC_6LOWPAN 0x3e /* reserved and temporary value */
|
||||
|
||||
/* L2CAP Control Field bit masks */
|
||||
#define L2CAP_CTRL_SAR 0xC000
|
||||
@ -579,7 +578,7 @@ struct l2cap_chan {
|
||||
struct list_head global_l;
|
||||
|
||||
void *data;
|
||||
struct l2cap_ops *ops;
|
||||
const struct l2cap_ops *ops;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
@ -600,7 +599,12 @@ struct l2cap_ops {
|
||||
void (*set_shutdown) (struct l2cap_chan *chan);
|
||||
long (*get_sndtimeo) (struct l2cap_chan *chan);
|
||||
struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan,
|
||||
unsigned long hdr_len,
|
||||
unsigned long len, int nb);
|
||||
int (*memcpy_fromiovec) (struct l2cap_chan *chan,
|
||||
unsigned char *kdata,
|
||||
struct iovec *iov,
|
||||
int len);
|
||||
};
|
||||
|
||||
struct l2cap_conn {
|
||||
@ -856,6 +860,31 @@ static inline long l2cap_chan_no_get_sndtimeo(struct l2cap_chan *chan)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int l2cap_chan_no_memcpy_fromiovec(struct l2cap_chan *chan,
|
||||
unsigned char *kdata,
|
||||
struct iovec *iov,
|
||||
int len)
|
||||
{
|
||||
/* Following is safe since for compiler definitions of kvec and
|
||||
* iovec are identical, yielding the same in-core layout and alignment
|
||||
*/
|
||||
struct kvec *vec = (struct kvec *)iov;
|
||||
|
||||
while (len > 0) {
|
||||
if (vec->iov_len) {
|
||||
int copy = min_t(unsigned int, len, vec->iov_len);
|
||||
memcpy(kdata, vec->iov_base, copy);
|
||||
len -= copy;
|
||||
kdata += copy;
|
||||
vec->iov_base += copy;
|
||||
vec->iov_len -= copy;
|
||||
}
|
||||
vec++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern bool disable_ertm;
|
||||
|
||||
int l2cap_init_sockets(void);
|
||||
@ -872,8 +901,7 @@ struct l2cap_chan *l2cap_chan_create(void);
|
||||
void l2cap_chan_close(struct l2cap_chan *chan, int reason);
|
||||
int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
|
||||
bdaddr_t *dst, u8 dst_type);
|
||||
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
|
||||
u32 priority);
|
||||
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
|
||||
void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
|
||||
int l2cap_chan_check_security(struct l2cap_chan *chan);
|
||||
void l2cap_chan_set_defaults(struct l2cap_chan *chan);
|
||||
|
@ -97,6 +97,7 @@ struct mgmt_rp_read_index_list {
|
||||
#define MGMT_SETTING_SECURE_CONN 0x00000800
|
||||
#define MGMT_SETTING_DEBUG_KEYS 0x00001000
|
||||
#define MGMT_SETTING_PRIVACY 0x00002000
|
||||
#define MGMT_SETTING_CONFIGURATION 0x00004000
|
||||
|
||||
#define MGMT_OP_READ_INFO 0x0004
|
||||
#define MGMT_READ_INFO_SIZE 0
|
||||
@ -424,6 +425,76 @@ struct mgmt_rp_get_conn_info {
|
||||
__s8 max_tx_power;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_GET_CLOCK_INFO 0x0032
|
||||
struct mgmt_cp_get_clock_info {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
#define MGMT_GET_CLOCK_INFO_SIZE MGMT_ADDR_INFO_SIZE
|
||||
struct mgmt_rp_get_clock_info {
|
||||
struct mgmt_addr_info addr;
|
||||
__le32 local_clock;
|
||||
__le32 piconet_clock;
|
||||
__le16 accuracy;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_ADD_DEVICE 0x0033
|
||||
struct mgmt_cp_add_device {
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 action;
|
||||
} __packed;
|
||||
#define MGMT_ADD_DEVICE_SIZE (MGMT_ADDR_INFO_SIZE + 1)
|
||||
|
||||
#define MGMT_OP_REMOVE_DEVICE 0x0034
|
||||
struct mgmt_cp_remove_device {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
#define MGMT_REMOVE_DEVICE_SIZE MGMT_ADDR_INFO_SIZE
|
||||
|
||||
struct mgmt_conn_param {
|
||||
struct mgmt_addr_info addr;
|
||||
__le16 min_interval;
|
||||
__le16 max_interval;
|
||||
__le16 latency;
|
||||
__le16 timeout;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_LOAD_CONN_PARAM 0x0035
|
||||
struct mgmt_cp_load_conn_param {
|
||||
__le16 param_count;
|
||||
struct mgmt_conn_param params[0];
|
||||
} __packed;
|
||||
#define MGMT_LOAD_CONN_PARAM_SIZE 2
|
||||
|
||||
#define MGMT_OP_READ_UNCONF_INDEX_LIST 0x0036
|
||||
#define MGMT_READ_UNCONF_INDEX_LIST_SIZE 0
|
||||
struct mgmt_rp_read_unconf_index_list {
|
||||
__le16 num_controllers;
|
||||
__le16 index[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OPTION_EXTERNAL_CONFIG 0x00000001
|
||||
#define MGMT_OPTION_PUBLIC_ADDRESS 0x00000002
|
||||
|
||||
#define MGMT_OP_READ_CONFIG_INFO 0x0037
|
||||
#define MGMT_READ_CONFIG_INFO_SIZE 0
|
||||
struct mgmt_rp_read_config_info {
|
||||
__le16 manufacturer;
|
||||
__le32 supported_options;
|
||||
__le32 missing_options;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_EXTERNAL_CONFIG 0x0038
|
||||
struct mgmt_cp_set_external_config {
|
||||
__u8 config;
|
||||
} __packed;
|
||||
#define MGMT_SET_EXTERNAL_CONFIG_SIZE 1
|
||||
|
||||
#define MGMT_OP_SET_PUBLIC_ADDRESS 0x0039
|
||||
struct mgmt_cp_set_public_address {
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
#define MGMT_SET_PUBLIC_ADDRESS_SIZE 6
|
||||
|
||||
#define MGMT_EV_CMD_COMPLETE 0x0001
|
||||
struct mgmt_ev_cmd_complete {
|
||||
__le16 opcode;
|
||||
@ -522,6 +593,7 @@ struct mgmt_ev_auth_failed {
|
||||
|
||||
#define MGMT_DEV_FOUND_CONFIRM_NAME 0x01
|
||||
#define MGMT_DEV_FOUND_LEGACY_PAIRING 0x02
|
||||
#define MGMT_DEV_FOUND_NOT_CONNECTABLE 0x04
|
||||
|
||||
#define MGMT_EV_DEVICE_FOUND 0x0012
|
||||
struct mgmt_ev_device_found {
|
||||
@ -578,3 +650,30 @@ struct mgmt_ev_new_csrk {
|
||||
__u8 store_hint;
|
||||
struct mgmt_csrk_info key;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_ADDED 0x001a
|
||||
struct mgmt_ev_device_added {
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 action;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_REMOVED 0x001b
|
||||
struct mgmt_ev_device_removed {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_NEW_CONN_PARAM 0x001c
|
||||
struct mgmt_ev_new_conn_param {
|
||||
struct mgmt_addr_info addr;
|
||||
__u8 store_hint;
|
||||
__le16 min_interval;
|
||||
__le16 max_interval;
|
||||
__le16 latency;
|
||||
__le16 timeout;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_UNCONF_INDEX_ADDED 0x001d
|
||||
|
||||
#define MGMT_EV_UNCONF_INDEX_REMOVED 0x001e
|
||||
|
||||
#define MGMT_EV_NEW_CONFIG_OPTIONS 0x001f
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,47 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2013 Intel Corp.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 and
|
||||
only version 2 as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __6LOWPAN_H
|
||||
#define __6LOWPAN_H
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/bluetooth/l2cap.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_6LOWPAN)
|
||||
int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb);
|
||||
int bt_6lowpan_add_conn(struct l2cap_conn *conn);
|
||||
int bt_6lowpan_del_conn(struct l2cap_conn *conn);
|
||||
int bt_6lowpan_init(void);
|
||||
void bt_6lowpan_cleanup(void);
|
||||
#else
|
||||
static int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static int bt_6lowpan_add_conn(struct l2cap_conn *conn)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
int bt_6lowpan_del_conn(struct l2cap_conn *conn)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static int bt_6lowpan_init(void)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static void bt_6lowpan_cleanup(void) { }
|
||||
#endif
|
||||
|
||||
#endif /* __6LOWPAN_H */
|
@ -6,7 +6,6 @@ menuconfig BT
|
||||
tristate "Bluetooth subsystem support"
|
||||
depends on NET && !S390
|
||||
depends on RFKILL || !RFKILL
|
||||
select 6LOWPAN_IPHC if BT_6LOWPAN
|
||||
select CRC16
|
||||
select CRYPTO
|
||||
select CRYPTO_BLKCIPHER
|
||||
@ -41,10 +40,11 @@ menuconfig BT
|
||||
more information, see <http://www.bluez.org/>.
|
||||
|
||||
config BT_6LOWPAN
|
||||
bool "Bluetooth 6LoWPAN support"
|
||||
tristate "Bluetooth 6LoWPAN support"
|
||||
depends on BT && IPV6
|
||||
select 6LOWPAN_IPHC if BT_6LOWPAN
|
||||
help
|
||||
IPv6 compression over Bluetooth.
|
||||
IPv6 compression over Bluetooth Low Energy.
|
||||
|
||||
source "net/bluetooth/rfcomm/Kconfig"
|
||||
|
||||
|
@ -7,10 +7,12 @@ obj-$(CONFIG_BT_RFCOMM) += rfcomm/
|
||||
obj-$(CONFIG_BT_BNEP) += bnep/
|
||||
obj-$(CONFIG_BT_CMTP) += cmtp/
|
||||
obj-$(CONFIG_BT_HIDP) += hidp/
|
||||
obj-$(CONFIG_BT_6LOWPAN) += bluetooth_6lowpan.o
|
||||
|
||||
bluetooth_6lowpan-y := 6lowpan.o
|
||||
|
||||
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
|
||||
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
|
||||
a2mp.o amp.o
|
||||
bluetooth-$(CONFIG_BT_6LOWPAN) += 6lowpan.o
|
||||
|
||||
subdir-ccflags-y += -D__CHECK_ENDIAN__
|
||||
|
@ -63,7 +63,7 @@ void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data)
|
||||
msg.msg_iov = (struct iovec *) &iv;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
l2cap_chan_send(chan, &msg, total_len, 0);
|
||||
l2cap_chan_send(chan, &msg, total_len);
|
||||
|
||||
kfree(cmd);
|
||||
}
|
||||
@ -693,18 +693,19 @@ static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state,
|
||||
}
|
||||
|
||||
static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,
|
||||
unsigned long hdr_len,
|
||||
unsigned long len, int nb)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = bt_skb_alloc(len, GFP_KERNEL);
|
||||
skb = bt_skb_alloc(hdr_len + len, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
static struct l2cap_ops a2mp_chan_ops = {
|
||||
static const struct l2cap_ops a2mp_chan_ops = {
|
||||
.name = "L2CAP A2MP channel",
|
||||
.recv = a2mp_chan_recv_cb,
|
||||
.close = a2mp_chan_close_cb,
|
||||
@ -719,6 +720,7 @@ static struct l2cap_ops a2mp_chan_ops = {
|
||||
.resume = l2cap_chan_no_resume,
|
||||
.set_shutdown = l2cap_chan_no_set_shutdown,
|
||||
.get_sndtimeo = l2cap_chan_no_get_sndtimeo,
|
||||
.memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec,
|
||||
};
|
||||
|
||||
static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked)
|
||||
|
@ -639,7 +639,7 @@ static int bt_seq_show(struct seq_file *seq, void *v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct seq_operations bt_seq_ops = {
|
||||
static const struct seq_operations bt_seq_ops = {
|
||||
.start = bt_seq_start,
|
||||
.next = bt_seq_next,
|
||||
.stop = bt_seq_stop,
|
||||
|
@ -67,7 +67,7 @@ static void hci_acl_create_connection(struct hci_conn *conn)
|
||||
conn->state = BT_CONNECT;
|
||||
conn->out = true;
|
||||
|
||||
conn->link_mode = HCI_LM_MASTER;
|
||||
set_bit(HCI_CONN_MASTER, &conn->flags);
|
||||
|
||||
conn->attempt++;
|
||||
|
||||
@ -136,7 +136,7 @@ void hci_disconnect(struct hci_conn *conn, __u8 reason)
|
||||
hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
static void hci_amp_disconn(struct hci_conn *conn, __u8 reason)
|
||||
static void hci_amp_disconn(struct hci_conn *conn)
|
||||
{
|
||||
struct hci_cp_disconn_phy_link cp;
|
||||
|
||||
@ -145,7 +145,7 @@ static void hci_amp_disconn(struct hci_conn *conn, __u8 reason)
|
||||
conn->state = BT_DISCONN;
|
||||
|
||||
cp.phy_handle = HCI_PHY_HANDLE(conn->handle);
|
||||
cp.reason = reason;
|
||||
cp.reason = hci_proto_disconn_ind(conn);
|
||||
hci_send_cmd(conn->hdev, HCI_OP_DISCONN_PHY_LINK,
|
||||
sizeof(cp), &cp);
|
||||
}
|
||||
@ -213,14 +213,26 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
|
||||
return true;
|
||||
}
|
||||
|
||||
void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
|
||||
u16 latency, u16 to_multiplier)
|
||||
u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
|
||||
u16 to_multiplier)
|
||||
{
|
||||
struct hci_cp_le_conn_update cp;
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
struct hci_conn_params *params;
|
||||
struct hci_cp_le_conn_update cp;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
|
||||
if (params) {
|
||||
params->conn_min_interval = min;
|
||||
params->conn_max_interval = max;
|
||||
params->conn_latency = latency;
|
||||
params->supervision_timeout = to_multiplier;
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
cp.conn_interval_min = cpu_to_le16(min);
|
||||
cp.conn_interval_max = cpu_to_le16(max);
|
||||
@ -230,6 +242,11 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
|
||||
cp.max_ce_len = cpu_to_le16(0x0000);
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp);
|
||||
|
||||
if (params)
|
||||
return 0x01;
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand,
|
||||
@ -271,28 +288,24 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status)
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_conn_disconnect(struct hci_conn *conn)
|
||||
{
|
||||
__u8 reason = hci_proto_disconn_ind(conn);
|
||||
|
||||
switch (conn->type) {
|
||||
case AMP_LINK:
|
||||
hci_amp_disconn(conn, reason);
|
||||
break;
|
||||
default:
|
||||
hci_disconnect(conn, reason);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_conn_timeout(struct work_struct *work)
|
||||
{
|
||||
struct hci_conn *conn = container_of(work, struct hci_conn,
|
||||
disc_work.work);
|
||||
int refcnt = atomic_read(&conn->refcnt);
|
||||
|
||||
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;
|
||||
|
||||
switch (conn->state) {
|
||||
@ -309,7 +322,31 @@ static void hci_conn_timeout(struct work_struct *work)
|
||||
break;
|
||||
case BT_CONFIG:
|
||||
case BT_CONNECTED:
|
||||
hci_conn_disconnect(conn);
|
||||
if (conn->type == AMP_LINK) {
|
||||
hci_amp_disconn(conn);
|
||||
} else {
|
||||
__u8 reason = hci_proto_disconn_ind(conn);
|
||||
|
||||
/* When we are master of an established connection
|
||||
* and it enters the disconnect timeout, then go
|
||||
* ahead and try to read the current clock offset.
|
||||
*
|
||||
* Processing of the result is done within the
|
||||
* event handling and hci_clock_offset_evt function.
|
||||
*/
|
||||
if (conn->type == ACL_LINK &&
|
||||
test_bit(HCI_CONN_MASTER, &conn->flags)) {
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
struct hci_cp_read_clock_offset cp;
|
||||
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_READ_CLOCK_OFFSET,
|
||||
sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
hci_disconnect(conn, reason);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
conn->state = BT_CLOSED;
|
||||
@ -326,9 +363,6 @@ static void hci_conn_idle(struct work_struct *work)
|
||||
|
||||
BT_DBG("hcon %p mode %d", conn, conn->mode);
|
||||
|
||||
if (test_bit(HCI_RAW, &hdev->flags))
|
||||
return;
|
||||
|
||||
if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn))
|
||||
return;
|
||||
|
||||
@ -519,7 +553,6 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
|
||||
|
||||
list_for_each_entry(d, &hci_dev_list, list) {
|
||||
if (!test_bit(HCI_UP, &d->flags) ||
|
||||
test_bit(HCI_RAW, &d->flags) ||
|
||||
test_bit(HCI_USER_CHANNEL, &d->dev_flags) ||
|
||||
d->dev_type != HCI_BREDR)
|
||||
continue;
|
||||
@ -617,7 +650,8 @@ static void hci_req_add_le_create_conn(struct hci_request *req,
|
||||
cp.own_address_type = own_addr_type;
|
||||
cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval);
|
||||
cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval);
|
||||
cp.supervision_timeout = cpu_to_le16(0x002a);
|
||||
cp.conn_latency = cpu_to_le16(conn->le_conn_latency);
|
||||
cp.supervision_timeout = cpu_to_le16(conn->le_supv_timeout);
|
||||
cp.min_ce_len = cpu_to_le16(0x0000);
|
||||
cp.max_ce_len = cpu_to_le16(0x0000);
|
||||
|
||||
@ -634,15 +668,12 @@ static void hci_req_directed_advertising(struct hci_request *req,
|
||||
u8 own_addr_type;
|
||||
u8 enable;
|
||||
|
||||
enable = 0x00;
|
||||
hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
|
||||
|
||||
/* Clear the HCI_ADVERTISING bit temporarily so that the
|
||||
/* Clear the HCI_LE_ADV bit temporarily so that the
|
||||
* hci_update_random_address knows that it's safe to go ahead
|
||||
* and write a new random address. The flag will be set back on
|
||||
* as soon as the SET_ADV_ENABLE HCI command completes.
|
||||
*/
|
||||
clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
|
||||
clear_bit(HCI_LE_ADV, &hdev->dev_flags);
|
||||
|
||||
/* Set require_privacy to false so that the remote device has a
|
||||
* chance of identifying us.
|
||||
@ -666,7 +697,8 @@ static void hci_req_directed_advertising(struct hci_request *req,
|
||||
}
|
||||
|
||||
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
u8 dst_type, u8 sec_level, u8 auth_type)
|
||||
u8 dst_type, u8 sec_level, u16 conn_timeout,
|
||||
bool master)
|
||||
{
|
||||
struct hci_conn_params *params;
|
||||
struct hci_conn *conn;
|
||||
@ -686,7 +718,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
|
||||
if (conn) {
|
||||
conn->pending_sec_level = sec_level;
|
||||
conn->auth_type = auth_type;
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -723,25 +754,52 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
conn->dst_type = dst_type;
|
||||
conn->sec_level = BT_SECURITY_LOW;
|
||||
conn->pending_sec_level = sec_level;
|
||||
conn->auth_type = auth_type;
|
||||
conn->conn_timeout = conn_timeout;
|
||||
|
||||
hci_req_init(&req, hdev);
|
||||
|
||||
if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
|
||||
/* Disable advertising if we're active. For master role
|
||||
* connections most controllers will refuse to connect if
|
||||
* advertising is enabled, and for slave role connections we
|
||||
* anyway have to disable it in order to start directed
|
||||
* advertising.
|
||||
*/
|
||||
if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) {
|
||||
u8 enable = 0x00;
|
||||
hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable),
|
||||
&enable);
|
||||
}
|
||||
|
||||
/* If requested to connect as slave use directed advertising */
|
||||
if (!master) {
|
||||
/* If we're active scanning most controllers are unable
|
||||
* to initiate advertising. Simply reject the attempt.
|
||||
*/
|
||||
if (test_bit(HCI_LE_SCAN, &hdev->dev_flags) &&
|
||||
hdev->le_scan_type == LE_SCAN_ACTIVE) {
|
||||
skb_queue_purge(&req.cmd_q);
|
||||
hci_conn_del(conn);
|
||||
return ERR_PTR(-EBUSY);
|
||||
}
|
||||
|
||||
hci_req_directed_advertising(&req, conn);
|
||||
goto create_conn;
|
||||
}
|
||||
|
||||
conn->out = true;
|
||||
conn->link_mode |= HCI_LM_MASTER;
|
||||
set_bit(HCI_CONN_MASTER, &conn->flags);
|
||||
|
||||
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
|
||||
if (params) {
|
||||
conn->le_conn_min_interval = params->conn_min_interval;
|
||||
conn->le_conn_max_interval = params->conn_max_interval;
|
||||
conn->le_conn_latency = params->conn_latency;
|
||||
conn->le_supv_timeout = params->supervision_timeout;
|
||||
} else {
|
||||
conn->le_conn_min_interval = hdev->le_conn_min_interval;
|
||||
conn->le_conn_max_interval = hdev->le_conn_max_interval;
|
||||
conn->le_conn_latency = hdev->le_conn_latency;
|
||||
conn->le_supv_timeout = hdev->le_supv_timeout;
|
||||
}
|
||||
|
||||
/* If controller is scanning, we stop it since some controllers are
|
||||
@ -855,7 +913,8 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hci_conn_ssp_enabled(conn) && !(conn->link_mode & HCI_LM_ENCRYPT))
|
||||
if (hci_conn_ssp_enabled(conn) &&
|
||||
!test_bit(HCI_CONN_ENCRYPT, &conn->flags))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@ -871,7 +930,7 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
|
||||
|
||||
if (sec_level > conn->sec_level)
|
||||
conn->pending_sec_level = sec_level;
|
||||
else if (conn->link_mode & HCI_LM_AUTH)
|
||||
else if (test_bit(HCI_CONN_AUTH, &conn->flags))
|
||||
return 1;
|
||||
|
||||
/* Make sure we preserve an existing MITM requirement*/
|
||||
@ -889,7 +948,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,
|
||||
* otherwise set the ENCRYPT_PEND.
|
||||
*/
|
||||
if (conn->link_mode & HCI_LM_ENCRYPT)
|
||||
if (test_bit(HCI_CONN_ENCRYPT, &conn->flags))
|
||||
set_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
|
||||
else
|
||||
set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
|
||||
@ -930,7 +989,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
|
||||
return 1;
|
||||
|
||||
/* For other security levels we need the link key. */
|
||||
if (!(conn->link_mode & HCI_LM_AUTH))
|
||||
if (!test_bit(HCI_CONN_AUTH, &conn->flags))
|
||||
goto auth;
|
||||
|
||||
/* An authenticated FIPS approved combination key has sufficient
|
||||
@ -970,7 +1029,7 @@ auth:
|
||||
return 0;
|
||||
|
||||
encrypt:
|
||||
if (conn->link_mode & HCI_LM_ENCRYPT)
|
||||
if (test_bit(HCI_CONN_ENCRYPT, &conn->flags))
|
||||
return 1;
|
||||
|
||||
hci_conn_encrypt(conn);
|
||||
@ -1017,7 +1076,7 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
|
||||
{
|
||||
BT_DBG("hcon %p", conn);
|
||||
|
||||
if (!role && conn->link_mode & HCI_LM_MASTER)
|
||||
if (!role && test_bit(HCI_CONN_MASTER, &conn->flags))
|
||||
return 1;
|
||||
|
||||
if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) {
|
||||
@ -1038,9 +1097,6 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
|
||||
|
||||
BT_DBG("hcon %p mode %d", conn, conn->mode);
|
||||
|
||||
if (test_bit(HCI_RAW, &hdev->flags))
|
||||
return;
|
||||
|
||||
if (conn->mode != HCI_CM_SNIFF)
|
||||
goto timer;
|
||||
|
||||
@ -1091,6 +1147,28 @@ void hci_conn_check_pending(struct hci_dev *hdev)
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static u32 get_link_mode(struct hci_conn *conn)
|
||||
{
|
||||
u32 link_mode = 0;
|
||||
|
||||
if (test_bit(HCI_CONN_MASTER, &conn->flags))
|
||||
link_mode |= HCI_LM_MASTER;
|
||||
|
||||
if (test_bit(HCI_CONN_ENCRYPT, &conn->flags))
|
||||
link_mode |= HCI_LM_ENCRYPT;
|
||||
|
||||
if (test_bit(HCI_CONN_AUTH, &conn->flags))
|
||||
link_mode |= HCI_LM_AUTH;
|
||||
|
||||
if (test_bit(HCI_CONN_SECURE, &conn->flags))
|
||||
link_mode |= HCI_LM_SECURE;
|
||||
|
||||
if (test_bit(HCI_CONN_FIPS, &conn->flags))
|
||||
link_mode |= HCI_LM_FIPS;
|
||||
|
||||
return link_mode;
|
||||
}
|
||||
|
||||
int hci_get_conn_list(void __user *arg)
|
||||
{
|
||||
struct hci_conn *c;
|
||||
@ -1126,7 +1204,7 @@ int hci_get_conn_list(void __user *arg)
|
||||
(ci + n)->type = c->type;
|
||||
(ci + n)->out = c->out;
|
||||
(ci + n)->state = c->state;
|
||||
(ci + n)->link_mode = c->link_mode;
|
||||
(ci + n)->link_mode = get_link_mode(c);
|
||||
if (++n >= req.conn_num)
|
||||
break;
|
||||
}
|
||||
@ -1162,7 +1240,7 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
|
||||
ci.type = conn->type;
|
||||
ci.out = conn->out;
|
||||
ci.state = conn->state;
|
||||
ci.link_mode = conn->link_mode;
|
||||
ci.link_mode = get_link_mode(conn);
|
||||
}
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -481,7 +481,7 @@ static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg)
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
err = hci_blacklist_add(hdev, &bdaddr, BDADDR_BREDR);
|
||||
err = hci_bdaddr_list_add(&hdev->blacklist, &bdaddr, BDADDR_BREDR);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
@ -498,7 +498,7 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
err = hci_blacklist_del(hdev, &bdaddr, BDADDR_BREDR);
|
||||
err = hci_bdaddr_list_del(&hdev->blacklist, &bdaddr, BDADDR_BREDR);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
@ -517,6 +517,9 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd,
|
||||
if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags))
|
||||
return -EBUSY;
|
||||
|
||||
if (test_bit(HCI_UNCONFIGURED, &hdev->dev_flags))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (hdev->dev_type != HCI_BREDR)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@ -690,7 +693,8 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
|
||||
|
||||
if (test_bit(HCI_UP, &hdev->flags) ||
|
||||
test_bit(HCI_INIT, &hdev->flags) ||
|
||||
test_bit(HCI_SETUP, &hdev->dev_flags)) {
|
||||
test_bit(HCI_SETUP, &hdev->dev_flags) ||
|
||||
test_bit(HCI_CONFIG, &hdev->dev_flags)) {
|
||||
err = -EBUSY;
|
||||
hci_dev_put(hdev);
|
||||
goto done;
|
||||
@ -960,7 +964,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
|
||||
goto drop;
|
||||
}
|
||||
|
||||
if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) {
|
||||
if (ogf == 0x3f) {
|
||||
skb_queue_tail(&hdev->raw_q, skb);
|
||||
queue_work(hdev->workqueue, &hdev->tx_work);
|
||||
} else {
|
||||
|
@ -40,7 +40,6 @@
|
||||
#include "smp.h"
|
||||
#include "a2mp.h"
|
||||
#include "amp.h"
|
||||
#include "6lowpan.h"
|
||||
|
||||
#define LE_FLOWCTL_MAX_CREDITS 65535
|
||||
|
||||
@ -205,6 +204,7 @@ done:
|
||||
write_unlock(&chan_list_lock);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2cap_add_psm);
|
||||
|
||||
int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
|
||||
{
|
||||
@ -437,6 +437,7 @@ struct l2cap_chan *l2cap_chan_create(void)
|
||||
|
||||
return chan;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2cap_chan_create);
|
||||
|
||||
static void l2cap_chan_destroy(struct kref *kref)
|
||||
{
|
||||
@ -464,6 +465,7 @@ void l2cap_chan_put(struct l2cap_chan *c)
|
||||
|
||||
kref_put(&c->kref, l2cap_chan_destroy);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2cap_chan_put);
|
||||
|
||||
void l2cap_chan_set_defaults(struct l2cap_chan *chan)
|
||||
{
|
||||
@ -482,6 +484,7 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan)
|
||||
|
||||
set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2cap_chan_set_defaults);
|
||||
|
||||
static void l2cap_le_flowctl_init(struct l2cap_chan *chan)
|
||||
{
|
||||
@ -614,6 +617,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
|
||||
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2cap_chan_del);
|
||||
|
||||
void l2cap_conn_update_id_addr(struct hci_conn *hcon)
|
||||
{
|
||||
@ -717,6 +721,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(l2cap_chan_close);
|
||||
|
||||
static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
|
||||
{
|
||||
@ -1455,13 +1460,12 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid,
|
||||
static void l2cap_le_conn_ready(struct l2cap_conn *conn)
|
||||
{
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
struct l2cap_chan *chan, *pchan;
|
||||
u8 dst_type;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
bt_6lowpan_add_conn(conn);
|
||||
|
||||
/* Check if we have socket listening on cid */
|
||||
pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT,
|
||||
&hcon->src, &hcon->dst);
|
||||
@ -1475,9 +1479,28 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
|
||||
dst_type = bdaddr_type(hcon, hcon->dst_type);
|
||||
|
||||
/* If device is blocked, do not create a channel for it */
|
||||
if (hci_blacklist_lookup(hcon->hdev, &hcon->dst, dst_type))
|
||||
if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type))
|
||||
return;
|
||||
|
||||
/* For LE slave connections, make sure the connection interval
|
||||
* is in the range of the minium and maximum interval that has
|
||||
* been configured for this connection. If not, then trigger
|
||||
* the connection update procedure.
|
||||
*/
|
||||
if (!test_bit(HCI_CONN_MASTER, &hcon->flags) &&
|
||||
(hcon->le_conn_interval < hcon->le_conn_min_interval ||
|
||||
hcon->le_conn_interval > hcon->le_conn_max_interval)) {
|
||||
struct l2cap_conn_param_update_req req;
|
||||
|
||||
req.min = cpu_to_le16(hcon->le_conn_min_interval);
|
||||
req.max = cpu_to_le16(hcon->le_conn_max_interval);
|
||||
req.latency = cpu_to_le16(hcon->le_conn_latency);
|
||||
req.to_multiplier = cpu_to_le16(hcon->le_supv_timeout);
|
||||
|
||||
l2cap_send_cmd(conn, l2cap_get_ident(conn),
|
||||
L2CAP_CONN_PARAM_UPDATE_REQ, sizeof(req), &req);
|
||||
}
|
||||
|
||||
l2cap_chan_lock(pchan);
|
||||
|
||||
chan = pchan->ops->new_connection(pchan);
|
||||
@ -2118,7 +2141,8 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
|
||||
struct sk_buff **frag;
|
||||
int sent = 0;
|
||||
|
||||
if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
|
||||
if (chan->ops->memcpy_fromiovec(chan, skb_put(skb, count),
|
||||
msg->msg_iov, count))
|
||||
return -EFAULT;
|
||||
|
||||
sent += count;
|
||||
@ -2131,18 +2155,17 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
|
||||
|
||||
count = min_t(unsigned int, conn->mtu, len);
|
||||
|
||||
tmp = chan->ops->alloc_skb(chan, count,
|
||||
tmp = chan->ops->alloc_skb(chan, 0, count,
|
||||
msg->msg_flags & MSG_DONTWAIT);
|
||||
if (IS_ERR(tmp))
|
||||
return PTR_ERR(tmp);
|
||||
|
||||
*frag = tmp;
|
||||
|
||||
if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
|
||||
if (chan->ops->memcpy_fromiovec(chan, skb_put(*frag, count),
|
||||
msg->msg_iov, count))
|
||||
return -EFAULT;
|
||||
|
||||
(*frag)->priority = skb->priority;
|
||||
|
||||
sent += count;
|
||||
len -= count;
|
||||
|
||||
@ -2156,26 +2179,23 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
|
||||
}
|
||||
|
||||
static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
|
||||
struct msghdr *msg, size_t len,
|
||||
u32 priority)
|
||||
struct msghdr *msg, size_t len)
|
||||
{
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
struct sk_buff *skb;
|
||||
int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
|
||||
struct l2cap_hdr *lh;
|
||||
|
||||
BT_DBG("chan %p psm 0x%2.2x len %zu priority %u", chan,
|
||||
__le16_to_cpu(chan->psm), len, priority);
|
||||
BT_DBG("chan %p psm 0x%2.2x len %zu", chan,
|
||||
__le16_to_cpu(chan->psm), len);
|
||||
|
||||
count = min_t(unsigned int, (conn->mtu - hlen), len);
|
||||
|
||||
skb = chan->ops->alloc_skb(chan, count + hlen,
|
||||
skb = chan->ops->alloc_skb(chan, hlen, count,
|
||||
msg->msg_flags & MSG_DONTWAIT);
|
||||
if (IS_ERR(skb))
|
||||
return skb;
|
||||
|
||||
skb->priority = priority;
|
||||
|
||||
/* Create L2CAP header */
|
||||
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
|
||||
lh->cid = cpu_to_le16(chan->dcid);
|
||||
@ -2191,8 +2211,7 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
|
||||
}
|
||||
|
||||
static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
|
||||
struct msghdr *msg, size_t len,
|
||||
u32 priority)
|
||||
struct msghdr *msg, size_t len)
|
||||
{
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
struct sk_buff *skb;
|
||||
@ -2203,13 +2222,11 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
|
||||
|
||||
count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len);
|
||||
|
||||
skb = chan->ops->alloc_skb(chan, count + L2CAP_HDR_SIZE,
|
||||
skb = chan->ops->alloc_skb(chan, L2CAP_HDR_SIZE, count,
|
||||
msg->msg_flags & MSG_DONTWAIT);
|
||||
if (IS_ERR(skb))
|
||||
return skb;
|
||||
|
||||
skb->priority = priority;
|
||||
|
||||
/* Create L2CAP header */
|
||||
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
|
||||
lh->cid = cpu_to_le16(chan->dcid);
|
||||
@ -2247,7 +2264,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
|
||||
|
||||
count = min_t(unsigned int, (conn->mtu - hlen), len);
|
||||
|
||||
skb = chan->ops->alloc_skb(chan, count + hlen,
|
||||
skb = chan->ops->alloc_skb(chan, hlen, count,
|
||||
msg->msg_flags & MSG_DONTWAIT);
|
||||
if (IS_ERR(skb))
|
||||
return skb;
|
||||
@ -2368,7 +2385,7 @@ static struct sk_buff *l2cap_create_le_flowctl_pdu(struct l2cap_chan *chan,
|
||||
|
||||
count = min_t(unsigned int, (conn->mtu - hlen), len);
|
||||
|
||||
skb = chan->ops->alloc_skb(chan, count + hlen,
|
||||
skb = chan->ops->alloc_skb(chan, hlen, count,
|
||||
msg->msg_flags & MSG_DONTWAIT);
|
||||
if (IS_ERR(skb))
|
||||
return skb;
|
||||
@ -2430,8 +2447,7 @@ static int l2cap_segment_le_sdu(struct l2cap_chan *chan,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
|
||||
u32 priority)
|
||||
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int err;
|
||||
@ -2442,7 +2458,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
|
||||
|
||||
/* Connectionless channel */
|
||||
if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
|
||||
skb = l2cap_create_connless_pdu(chan, msg, len, priority);
|
||||
skb = l2cap_create_connless_pdu(chan, msg, len);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
@ -2499,7 +2515,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
|
||||
return -EMSGSIZE;
|
||||
|
||||
/* Create a basic PDU */
|
||||
skb = l2cap_create_basic_pdu(chan, msg, len, priority);
|
||||
skb = l2cap_create_basic_pdu(chan, msg, len);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
@ -2562,6 +2578,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2cap_chan_send);
|
||||
|
||||
static void l2cap_send_srej(struct l2cap_chan *chan, u16 txseq)
|
||||
{
|
||||
@ -3217,6 +3234,9 @@ done:
|
||||
|
||||
switch (chan->mode) {
|
||||
case L2CAP_MODE_BASIC:
|
||||
if (disable_ertm)
|
||||
break;
|
||||
|
||||
if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
|
||||
!(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
|
||||
break;
|
||||
@ -5197,27 +5217,6 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
|
||||
u16 to_multiplier)
|
||||
{
|
||||
u16 max_latency;
|
||||
|
||||
if (min > max || min < 6 || max > 3200)
|
||||
return -EINVAL;
|
||||
|
||||
if (to_multiplier < 10 || to_multiplier > 3200)
|
||||
return -EINVAL;
|
||||
|
||||
if (max >= to_multiplier * 8)
|
||||
return -EINVAL;
|
||||
|
||||
max_latency = (to_multiplier * 8 / max) - 1;
|
||||
if (latency > 499 || latency > max_latency)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
|
||||
struct l2cap_cmd_hdr *cmd,
|
||||
u16 cmd_len, u8 *data)
|
||||
@ -5228,7 +5227,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
|
||||
u16 min, max, latency, to_multiplier;
|
||||
int err;
|
||||
|
||||
if (!(hcon->link_mode & HCI_LM_MASTER))
|
||||
if (!test_bit(HCI_CONN_MASTER, &hcon->flags))
|
||||
return -EINVAL;
|
||||
|
||||
if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
|
||||
@ -5245,7 +5244,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
|
||||
|
||||
memset(&rsp, 0, sizeof(rsp));
|
||||
|
||||
err = l2cap_check_conn_param(min, max, latency, to_multiplier);
|
||||
err = hci_check_conn_params(min, max, latency, to_multiplier);
|
||||
if (err)
|
||||
rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
|
||||
else
|
||||
@ -5254,8 +5253,16 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
|
||||
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
|
||||
sizeof(rsp), &rsp);
|
||||
|
||||
if (!err)
|
||||
hci_le_conn_update(hcon, min, max, latency, to_multiplier);
|
||||
if (!err) {
|
||||
u8 store_hint;
|
||||
|
||||
store_hint = hci_le_conn_update(hcon, min, max, latency,
|
||||
to_multiplier);
|
||||
mgmt_new_conn_param(hcon->hdev, &hcon->dst, hcon->dst_type,
|
||||
store_hint, min, max, latency,
|
||||
to_multiplier);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -6879,9 +6886,6 @@ static void l2cap_att_channel(struct l2cap_conn *conn,
|
||||
|
||||
BT_DBG("chan %p, len %d", chan, skb->len);
|
||||
|
||||
if (hci_blacklist_lookup(hcon->hdev, &hcon->dst, hcon->dst_type))
|
||||
goto drop;
|
||||
|
||||
if (chan->imtu < skb->len)
|
||||
goto drop;
|
||||
|
||||
@ -6914,6 +6918,16 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Since we can't actively block incoming LE connections we must
|
||||
* at least ensure that we ignore incoming data from them.
|
||||
*/
|
||||
if (hcon->type == LE_LINK &&
|
||||
hci_bdaddr_list_lookup(&hcon->hdev->blacklist, &hcon->dst,
|
||||
bdaddr_type(hcon, hcon->dst_type))) {
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
BT_DBG("len %d, cid 0x%4.4x", len, cid);
|
||||
|
||||
switch (cid) {
|
||||
@ -6940,10 +6954,6 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
l2cap_conn_del(conn->hcon, EACCES);
|
||||
break;
|
||||
|
||||
case L2CAP_FC_6LOWPAN:
|
||||
bt_6lowpan_recv(conn, skb);
|
||||
break;
|
||||
|
||||
default:
|
||||
l2cap_data_channel(conn, cid, skb);
|
||||
break;
|
||||
@ -7042,7 +7052,6 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
|
||||
struct l2cap_conn *conn;
|
||||
struct hci_conn *hcon;
|
||||
struct hci_dev *hdev;
|
||||
__u8 auth_type;
|
||||
int err;
|
||||
|
||||
BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", &chan->src, dst,
|
||||
@ -7118,9 +7127,9 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
|
||||
chan->psm = psm;
|
||||
chan->dcid = cid;
|
||||
|
||||
auth_type = l2cap_get_auth_type(chan);
|
||||
|
||||
if (bdaddr_type_is_le(dst_type)) {
|
||||
bool master;
|
||||
|
||||
/* Convert from L2CAP channel address type to HCI address type
|
||||
*/
|
||||
if (dst_type == BDADDR_LE_PUBLIC)
|
||||
@ -7128,9 +7137,12 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
|
||||
else
|
||||
dst_type = ADDR_LE_DEV_RANDOM;
|
||||
|
||||
master = !test_bit(HCI_ADVERTISING, &hdev->dev_flags);
|
||||
|
||||
hcon = hci_connect_le(hdev, dst, dst_type, chan->sec_level,
|
||||
auth_type);
|
||||
HCI_LE_CONN_TIMEOUT, master);
|
||||
} else {
|
||||
u8 auth_type = l2cap_get_auth_type(chan);
|
||||
hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type);
|
||||
}
|
||||
|
||||
@ -7190,6 +7202,7 @@ done:
|
||||
hci_dev_put(hdev);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2cap_chan_connect);
|
||||
|
||||
/* ---- L2CAP interface with lower layer (HCI) ---- */
|
||||
|
||||
@ -7252,8 +7265,6 @@ void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
|
||||
{
|
||||
BT_DBG("hcon %p reason %d", hcon, reason);
|
||||
|
||||
bt_6lowpan_del_conn(hcon->l2cap_data);
|
||||
|
||||
l2cap_conn_del(hcon, bt_to_errno(reason));
|
||||
}
|
||||
|
||||
@ -7536,14 +7547,11 @@ int __init l2cap_init(void)
|
||||
debugfs_create_u16("l2cap_le_default_mps", 0644, bt_debugfs,
|
||||
&le_default_mps);
|
||||
|
||||
bt_6lowpan_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void l2cap_exit(void)
|
||||
{
|
||||
bt_6lowpan_cleanup();
|
||||
debugfs_remove(l2cap_debugfs);
|
||||
l2cap_cleanup_sockets();
|
||||
}
|
||||
|
@ -361,7 +361,8 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr,
|
||||
BT_DBG("sock %p, sk %p", sock, sk);
|
||||
|
||||
if (peer && sk->sk_state != BT_CONNECTED &&
|
||||
sk->sk_state != BT_CONNECT && sk->sk_state != BT_CONNECT2)
|
||||
sk->sk_state != BT_CONNECT && sk->sk_state != BT_CONNECT2 &&
|
||||
sk->sk_state != BT_CONFIG)
|
||||
return -ENOTCONN;
|
||||
|
||||
memset(la, 0, sizeof(struct sockaddr_l2));
|
||||
@ -964,7 +965,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
|
||||
return err;
|
||||
|
||||
l2cap_chan_lock(chan);
|
||||
err = l2cap_chan_send(chan, msg, len, sk->sk_priority);
|
||||
err = l2cap_chan_send(chan, msg, len);
|
||||
l2cap_chan_unlock(chan);
|
||||
|
||||
return err;
|
||||
@ -1292,6 +1293,7 @@ static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state,
|
||||
}
|
||||
|
||||
static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
|
||||
unsigned long hdr_len,
|
||||
unsigned long len, int nb)
|
||||
{
|
||||
struct sock *sk = chan->data;
|
||||
@ -1299,17 +1301,26 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
|
||||
int err;
|
||||
|
||||
l2cap_chan_unlock(chan);
|
||||
skb = bt_skb_send_alloc(sk, len, nb, &err);
|
||||
skb = bt_skb_send_alloc(sk, hdr_len + len, nb, &err);
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
if (!skb)
|
||||
return ERR_PTR(err);
|
||||
|
||||
skb->priority = sk->sk_priority;
|
||||
|
||||
bt_cb(skb)->chan = chan;
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
static int l2cap_sock_memcpy_fromiovec_cb(struct l2cap_chan *chan,
|
||||
unsigned char *kdata,
|
||||
struct iovec *iov, int len)
|
||||
{
|
||||
return memcpy_fromiovec(kdata, iov, len);
|
||||
}
|
||||
|
||||
static void l2cap_sock_ready_cb(struct l2cap_chan *chan)
|
||||
{
|
||||
struct sock *sk = chan->data;
|
||||
@ -1375,20 +1386,21 @@ static void l2cap_sock_suspend_cb(struct l2cap_chan *chan)
|
||||
sk->sk_state_change(sk);
|
||||
}
|
||||
|
||||
static struct l2cap_ops l2cap_chan_ops = {
|
||||
.name = "L2CAP Socket Interface",
|
||||
.new_connection = l2cap_sock_new_connection_cb,
|
||||
.recv = l2cap_sock_recv_cb,
|
||||
.close = l2cap_sock_close_cb,
|
||||
.teardown = l2cap_sock_teardown_cb,
|
||||
.state_change = l2cap_sock_state_change_cb,
|
||||
.ready = l2cap_sock_ready_cb,
|
||||
.defer = l2cap_sock_defer_cb,
|
||||
.resume = l2cap_sock_resume_cb,
|
||||
.suspend = l2cap_sock_suspend_cb,
|
||||
.set_shutdown = l2cap_sock_set_shutdown_cb,
|
||||
.get_sndtimeo = l2cap_sock_get_sndtimeo_cb,
|
||||
.alloc_skb = l2cap_sock_alloc_skb_cb,
|
||||
static const struct l2cap_ops l2cap_chan_ops = {
|
||||
.name = "L2CAP Socket Interface",
|
||||
.new_connection = l2cap_sock_new_connection_cb,
|
||||
.recv = l2cap_sock_recv_cb,
|
||||
.close = l2cap_sock_close_cb,
|
||||
.teardown = l2cap_sock_teardown_cb,
|
||||
.state_change = l2cap_sock_state_change_cb,
|
||||
.ready = l2cap_sock_ready_cb,
|
||||
.defer = l2cap_sock_defer_cb,
|
||||
.resume = l2cap_sock_resume_cb,
|
||||
.suspend = l2cap_sock_suspend_cb,
|
||||
.set_shutdown = l2cap_sock_set_shutdown_cb,
|
||||
.get_sndtimeo = l2cap_sock_get_sndtimeo_cb,
|
||||
.alloc_skb = l2cap_sock_alloc_skb_cb,
|
||||
.memcpy_fromiovec = l2cap_sock_memcpy_fromiovec_cb,
|
||||
};
|
||||
|
||||
static void l2cap_sock_destruct(struct sock *sk)
|
||||
|
1250
net/bluetooth/mgmt.c
1250
net/bluetooth/mgmt.c
File diff suppressed because it is too large
Load Diff
@ -35,11 +35,13 @@
|
||||
|
||||
#define AUTH_REQ_MASK 0x07
|
||||
|
||||
#define SMP_FLAG_TK_VALID 1
|
||||
#define SMP_FLAG_CFM_PENDING 2
|
||||
#define SMP_FLAG_MITM_AUTH 3
|
||||
#define SMP_FLAG_COMPLETE 4
|
||||
#define SMP_FLAG_INITIATOR 5
|
||||
enum {
|
||||
SMP_FLAG_TK_VALID,
|
||||
SMP_FLAG_CFM_PENDING,
|
||||
SMP_FLAG_MITM_AUTH,
|
||||
SMP_FLAG_COMPLETE,
|
||||
SMP_FLAG_INITIATOR,
|
||||
};
|
||||
|
||||
struct smp_chan {
|
||||
struct l2cap_conn *conn;
|
||||
@ -60,20 +62,16 @@ struct smp_chan {
|
||||
struct smp_ltk *slave_ltk;
|
||||
struct smp_irk *remote_irk;
|
||||
unsigned long flags;
|
||||
|
||||
struct crypto_blkcipher *tfm_aes;
|
||||
};
|
||||
|
||||
static inline void swap128(const u8 src[16], u8 dst[16])
|
||||
static inline void swap_buf(const u8 *src, u8 *dst, size_t len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 16; i++)
|
||||
dst[15 - i] = src[i];
|
||||
}
|
||||
size_t i;
|
||||
|
||||
static inline void swap56(const u8 src[7], u8 dst[7])
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 7; i++)
|
||||
dst[6 - i] = src[i];
|
||||
for (i = 0; i < len; i++)
|
||||
dst[len - 1 - i] = src[i];
|
||||
}
|
||||
|
||||
static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
|
||||
@ -92,7 +90,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
|
||||
desc.flags = 0;
|
||||
|
||||
/* The most significant octet of key corresponds to k[0] */
|
||||
swap128(k, tmp);
|
||||
swap_buf(k, tmp, 16);
|
||||
|
||||
err = crypto_blkcipher_setkey(tfm, tmp, 16);
|
||||
if (err) {
|
||||
@ -101,7 +99,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
|
||||
}
|
||||
|
||||
/* Most significant octet of plaintextData corresponds to data[0] */
|
||||
swap128(r, data);
|
||||
swap_buf(r, data, 16);
|
||||
|
||||
sg_init_one(&sg, data, 16);
|
||||
|
||||
@ -110,7 +108,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
|
||||
BT_ERR("Encrypt data error %d", err);
|
||||
|
||||
/* Most significant octet of encryptedData corresponds to data[0] */
|
||||
swap128(data, r);
|
||||
swap_buf(data, r, 16);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -174,13 +172,16 @@ int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16],
|
||||
u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia,
|
||||
u8 _rat, bdaddr_t *ra, u8 res[16])
|
||||
static int smp_c1(struct smp_chan *smp, u8 k[16], u8 r[16], u8 preq[7],
|
||||
u8 pres[7], u8 _iat, bdaddr_t *ia, u8 _rat, bdaddr_t *ra,
|
||||
u8 res[16])
|
||||
{
|
||||
struct hci_dev *hdev = smp->conn->hcon->hdev;
|
||||
u8 p1[16], p2[16];
|
||||
int err;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
memset(p1, 0, 16);
|
||||
|
||||
/* p1 = pres || preq || _rat || _iat */
|
||||
@ -198,7 +199,7 @@ static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16],
|
||||
u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
|
||||
|
||||
/* res = e(k, res) */
|
||||
err = smp_e(tfm, k, res);
|
||||
err = smp_e(smp->tfm_aes, k, res);
|
||||
if (err) {
|
||||
BT_ERR("Encrypt data error");
|
||||
return err;
|
||||
@ -208,23 +209,26 @@ static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16],
|
||||
u128_xor((u128 *) res, (u128 *) res, (u128 *) p2);
|
||||
|
||||
/* res = e(k, res) */
|
||||
err = smp_e(tfm, k, res);
|
||||
err = smp_e(smp->tfm_aes, k, res);
|
||||
if (err)
|
||||
BT_ERR("Encrypt data error");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int smp_s1(struct crypto_blkcipher *tfm, u8 k[16], u8 r1[16],
|
||||
u8 r2[16], u8 _r[16])
|
||||
static int smp_s1(struct smp_chan *smp, u8 k[16], u8 r1[16], u8 r2[16],
|
||||
u8 _r[16])
|
||||
{
|
||||
struct hci_dev *hdev = smp->conn->hcon->hdev;
|
||||
int err;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
/* Just least significant octets from r1 and r2 are considered */
|
||||
memcpy(_r, r2, 8);
|
||||
memcpy(_r + 8, r1, 8);
|
||||
|
||||
err = smp_e(tfm, k, _r);
|
||||
err = smp_e(smp->tfm_aes, k, _r);
|
||||
if (err)
|
||||
BT_ERR("Encrypt data error");
|
||||
|
||||
@ -385,6 +389,16 @@ static const u8 gen_method[5][5] = {
|
||||
{ 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,
|
||||
u8 local_io, u8 remote_io)
|
||||
{
|
||||
@ -401,14 +415,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);
|
||||
|
||||
/* 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 */
|
||||
if (!(auth & SMP_AUTH_MITM) ||
|
||||
local_io > SMP_IO_KEYBOARD_DISPLAY ||
|
||||
remote_io > SMP_IO_KEYBOARD_DISPLAY)
|
||||
if (!(auth & SMP_AUTH_MITM))
|
||||
method = JUST_WORKS;
|
||||
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 (!(auth & SMP_AUTH_BONDING) && method == JUST_CFM)
|
||||
@ -432,7 +443,7 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
||||
* Confirms and the slave Enters the passkey.
|
||||
*/
|
||||
if (method == OVERLAP) {
|
||||
if (hcon->link_mode & HCI_LM_MASTER)
|
||||
if (test_bit(HCI_CONN_MASTER, &hcon->flags))
|
||||
method = CFM_PASSKEY;
|
||||
else
|
||||
method = REQ_PASSKEY;
|
||||
@ -470,23 +481,15 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
||||
static u8 smp_confirm(struct smp_chan *smp)
|
||||
{
|
||||
struct l2cap_conn *conn = smp->conn;
|
||||
struct hci_dev *hdev = conn->hcon->hdev;
|
||||
struct crypto_blkcipher *tfm = hdev->tfm_aes;
|
||||
struct smp_cmd_pairing_confirm cp;
|
||||
int ret;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
/* Prevent mutual access to hdev->tfm_aes */
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
|
||||
ret = smp_c1(smp, smp->tk, smp->prnd, smp->preq, smp->prsp,
|
||||
conn->hcon->init_addr_type, &conn->hcon->init_addr,
|
||||
conn->hcon->resp_addr_type, &conn->hcon->resp_addr,
|
||||
cp.confirm_val);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
if (ret)
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
@ -501,25 +504,17 @@ static u8 smp_random(struct smp_chan *smp)
|
||||
{
|
||||
struct l2cap_conn *conn = smp->conn;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
struct crypto_blkcipher *tfm = hdev->tfm_aes;
|
||||
u8 confirm[16];
|
||||
int ret;
|
||||
|
||||
if (IS_ERR_OR_NULL(tfm))
|
||||
if (IS_ERR_OR_NULL(smp->tfm_aes))
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
|
||||
|
||||
/* Prevent mutual access to hdev->tfm_aes */
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
|
||||
ret = smp_c1(smp, smp->tk, smp->rrnd, smp->preq, smp->prsp,
|
||||
hcon->init_addr_type, &hcon->init_addr,
|
||||
hcon->resp_addr_type, &hcon->resp_addr, confirm);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
if (ret)
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
@ -533,7 +528,7 @@ static u8 smp_random(struct smp_chan *smp)
|
||||
__le64 rand = 0;
|
||||
__le16 ediv = 0;
|
||||
|
||||
smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, stk);
|
||||
smp_s1(smp, smp->tk, smp->rrnd, smp->prnd, stk);
|
||||
|
||||
memset(stk + smp->enc_key_size, 0,
|
||||
SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
|
||||
@ -543,6 +538,7 @@ static u8 smp_random(struct smp_chan *smp)
|
||||
|
||||
hci_le_start_enc(hcon, ediv, rand, stk);
|
||||
hcon->enc_key_size = smp->enc_key_size;
|
||||
set_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags);
|
||||
} else {
|
||||
u8 stk[16], auth;
|
||||
__le64 rand = 0;
|
||||
@ -551,7 +547,7 @@ static u8 smp_random(struct smp_chan *smp)
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
|
||||
smp->prnd);
|
||||
|
||||
smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, stk);
|
||||
smp_s1(smp, smp->tk, smp->prnd, smp->rrnd, stk);
|
||||
|
||||
memset(stk + smp->enc_key_size, 0,
|
||||
SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
|
||||
@ -561,9 +557,12 @@ static u8 smp_random(struct smp_chan *smp)
|
||||
else
|
||||
auth = 0;
|
||||
|
||||
/* Even though there's no _SLAVE suffix this is the
|
||||
* slave STK we're adding for later lookup (the master
|
||||
* STK never needs to be stored).
|
||||
*/
|
||||
hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
|
||||
HCI_SMP_STK_SLAVE, auth, stk, smp->enc_key_size,
|
||||
ediv, rand);
|
||||
SMP_STK, auth, stk, smp->enc_key_size, ediv, rand);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -577,9 +576,15 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
|
||||
if (!smp)
|
||||
return NULL;
|
||||
|
||||
smp->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(smp->tfm_aes)) {
|
||||
BT_ERR("Unable to create ECB crypto context");
|
||||
kfree(smp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
smp->conn = conn;
|
||||
conn->smp_chan = smp;
|
||||
conn->hcon->smp_conn = conn;
|
||||
|
||||
hci_conn_hold(conn->hcon);
|
||||
|
||||
@ -599,6 +604,8 @@ void smp_chan_destroy(struct l2cap_conn *conn)
|
||||
kfree(smp->csrk);
|
||||
kfree(smp->slave_csrk);
|
||||
|
||||
crypto_free_blkcipher(smp->tfm_aes);
|
||||
|
||||
/* If pairing failed clean up any keys we might have */
|
||||
if (!complete) {
|
||||
if (smp->ltk) {
|
||||
@ -619,19 +626,18 @@ void smp_chan_destroy(struct l2cap_conn *conn)
|
||||
|
||||
kfree(smp);
|
||||
conn->smp_chan = NULL;
|
||||
conn->hcon->smp_conn = NULL;
|
||||
hci_conn_drop(conn->hcon);
|
||||
}
|
||||
|
||||
int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
|
||||
{
|
||||
struct l2cap_conn *conn = hcon->smp_conn;
|
||||
struct l2cap_conn *conn = hcon->l2cap_data;
|
||||
struct smp_chan *smp;
|
||||
u32 value;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
if (!conn)
|
||||
if (!conn || !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
|
||||
return -ENOTCONN;
|
||||
|
||||
smp = conn->smp_chan;
|
||||
@ -669,7 +675,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_chan *smp;
|
||||
u8 key_size, auth;
|
||||
u8 key_size, auth, sec_level;
|
||||
int ret;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
@ -677,7 +683,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
if (skb->len < sizeof(*req))
|
||||
return SMP_INVALID_PARAMS;
|
||||
|
||||
if (conn->hcon->link_mode & HCI_LM_MASTER)
|
||||
if (test_bit(HCI_CONN_MASTER, &conn->hcon->flags))
|
||||
return SMP_CMD_NOTSUPP;
|
||||
|
||||
if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
|
||||
@ -695,7 +701,19 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
/* We didn't start the pairing, so match remote */
|
||||
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);
|
||||
|
||||
@ -732,7 +750,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
if (skb->len < sizeof(*rsp))
|
||||
return SMP_INVALID_PARAMS;
|
||||
|
||||
if (!(conn->hcon->link_mode & HCI_LM_MASTER))
|
||||
if (!test_bit(HCI_CONN_MASTER, &conn->hcon->flags))
|
||||
return SMP_CMD_NOTSUPP;
|
||||
|
||||
skb_pull(skb, sizeof(*rsp));
|
||||
@ -743,6 +761,16 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
if (check_enc_key_size(conn, 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));
|
||||
|
||||
smp->prsp[0] = SMP_CMD_PAIRING_RSP;
|
||||
@ -810,7 +838,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
return smp_random(smp);
|
||||
}
|
||||
|
||||
static u8 smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level)
|
||||
static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level)
|
||||
{
|
||||
struct smp_ltk *key;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
@ -818,18 +846,40 @@ static u8 smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level)
|
||||
key = hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type,
|
||||
hcon->out);
|
||||
if (!key)
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
if (sec_level > BT_SECURITY_MEDIUM && !key->authenticated)
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags))
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
hci_le_start_enc(hcon, key->ediv, key->rand, key->val);
|
||||
hcon->enc_key_size = key->enc_size;
|
||||
|
||||
return 1;
|
||||
/* We never store STKs for master role, so clear this flag */
|
||||
clear_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level)
|
||||
{
|
||||
if (sec_level == BT_SECURITY_LOW)
|
||||
return true;
|
||||
|
||||
/* If we're encrypted with an STK always claim insufficient
|
||||
* security. This way we allow the connection to be re-encrypted
|
||||
* with an LTK, even if the LTK provides the same level of
|
||||
* security.
|
||||
*/
|
||||
if (test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags))
|
||||
return false;
|
||||
|
||||
if (hcon->sec_level >= sec_level)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
@ -838,16 +888,22 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
struct smp_cmd_pairing cp;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct smp_chan *smp;
|
||||
u8 sec_level;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (skb->len < sizeof(*rp))
|
||||
return SMP_INVALID_PARAMS;
|
||||
|
||||
if (!(conn->hcon->link_mode & HCI_LM_MASTER))
|
||||
if (!test_bit(HCI_CONN_MASTER, &conn->hcon->flags))
|
||||
return SMP_CMD_NOTSUPP;
|
||||
|
||||
hcon->pending_sec_level = authreq_to_seclevel(rp->auth_req);
|
||||
sec_level = authreq_to_seclevel(rp->auth_req);
|
||||
if (smp_sufficient_security(hcon, sec_level))
|
||||
return 0;
|
||||
|
||||
if (sec_level > hcon->pending_sec_level)
|
||||
hcon->pending_sec_level = sec_level;
|
||||
|
||||
if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
|
||||
return 0;
|
||||
@ -856,6 +912,8 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
return 0;
|
||||
|
||||
smp = smp_chan_create(conn);
|
||||
if (!smp)
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
skb_pull(skb, sizeof(*rp));
|
||||
|
||||
@ -872,17 +930,6 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level)
|
||||
{
|
||||
if (sec_level == BT_SECURITY_LOW)
|
||||
return true;
|
||||
|
||||
if (hcon->sec_level >= sec_level)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
||||
{
|
||||
struct l2cap_conn *conn = hcon->l2cap_data;
|
||||
@ -901,9 +948,12 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
||||
if (smp_sufficient_security(hcon, sec_level))
|
||||
return 1;
|
||||
|
||||
if (hcon->link_mode & HCI_LM_MASTER)
|
||||
if (smp_ltk_encrypt(conn, sec_level))
|
||||
goto done;
|
||||
if (sec_level > hcon->pending_sec_level)
|
||||
hcon->pending_sec_level = sec_level;
|
||||
|
||||
if (test_bit(HCI_CONN_MASTER, &hcon->flags))
|
||||
if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
|
||||
return 0;
|
||||
|
||||
if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
|
||||
return 0;
|
||||
@ -918,10 +968,10 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
||||
* requires it.
|
||||
*/
|
||||
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;
|
||||
|
||||
if (hcon->link_mode & HCI_LM_MASTER) {
|
||||
if (test_bit(HCI_CONN_MASTER, &hcon->flags)) {
|
||||
struct smp_cmd_pairing cp;
|
||||
|
||||
build_pairing_cmd(conn, &cp, NULL, authreq);
|
||||
@ -937,9 +987,6 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
||||
|
||||
set_bit(SMP_FLAG_INITIATOR, &smp->flags);
|
||||
|
||||
done:
|
||||
hcon->pending_sec_level = sec_level;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -989,7 +1036,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
authenticated = (hcon->sec_level == BT_SECURITY_HIGH);
|
||||
ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK,
|
||||
ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, SMP_LTK,
|
||||
authenticated, smp->tk, smp->enc_key_size,
|
||||
rp->ediv, rp->rand);
|
||||
smp->ltk = ltk;
|
||||
@ -1043,6 +1090,8 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
|
||||
|
||||
skb_pull(skb, sizeof(*info));
|
||||
|
||||
hci_dev_lock(hcon->hdev);
|
||||
|
||||
/* Strictly speaking the Core Specification (4.1) allows sending
|
||||
* an empty address which would force us to rely on just the IRK
|
||||
* as "identity information". However, since such
|
||||
@ -1052,8 +1101,7 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
|
||||
*/
|
||||
if (!bacmp(&info->bdaddr, BDADDR_ANY)) {
|
||||
BT_ERR("Ignoring IRK with no identity address");
|
||||
smp_distribute_keys(conn);
|
||||
return 0;
|
||||
goto distribute;
|
||||
}
|
||||
|
||||
bacpy(&smp->id_addr, &info->bdaddr);
|
||||
@ -1067,8 +1115,11 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
|
||||
smp->remote_irk = hci_add_irk(conn->hcon->hdev, &smp->id_addr,
|
||||
smp->id_addr_type, smp->irk, &rpa);
|
||||
|
||||
distribute:
|
||||
smp_distribute_keys(conn);
|
||||
|
||||
hci_dev_unlock(hcon->hdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1305,7 +1356,7 @@ int smp_distribute_keys(struct l2cap_conn *conn)
|
||||
|
||||
authenticated = hcon->sec_level == BT_SECURITY_HIGH;
|
||||
ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type,
|
||||
HCI_SMP_LTK_SLAVE, authenticated, enc.ltk,
|
||||
SMP_LTK_SLAVE, authenticated, enc.ltk,
|
||||
smp->enc_key_size, ediv, rand);
|
||||
smp->slave_ltk = ltk;
|
||||
|
||||
|
@ -116,6 +116,13 @@ struct smp_cmd_security_req {
|
||||
#define SMP_MIN_ENC_KEY_SIZE 7
|
||||
#define SMP_MAX_ENC_KEY_SIZE 16
|
||||
|
||||
/* LTK types used in internal storage (struct smp_ltk) */
|
||||
enum {
|
||||
SMP_STK,
|
||||
SMP_LTK,
|
||||
SMP_LTK_SLAVE,
|
||||
};
|
||||
|
||||
/* SMP Commands */
|
||||
bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level);
|
||||
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level);
|
||||
|
@ -1150,11 +1150,12 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
|
||||
int err;
|
||||
|
||||
/* 24 + 6 = header + auth_algo + auth_transaction + status_code */
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24 + 6 + extra_len);
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + IEEE80211_WEP_IV_LEN +
|
||||
24 + 6 + extra_len + IEEE80211_WEP_ICV_LEN);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom + IEEE80211_WEP_IV_LEN);
|
||||
|
||||
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
|
||||
memset(mgmt, 0, 24 + 6);
|
||||
|
@ -424,7 +424,7 @@ static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
|
||||
if (end >= start)
|
||||
return jiffies_to_msecs(end - start);
|
||||
|
||||
return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1);
|
||||
return jiffies_to_msecs(end + (ULONG_MAX - start) + 1);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1498,18 +1498,17 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
|
||||
}
|
||||
CMD(start_p2p_device, START_P2P_DEVICE);
|
||||
CMD(set_mcast_rate, SET_MCAST_RATE);
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
CMD(testmode_cmd, TESTMODE);
|
||||
#endif
|
||||
if (state->split) {
|
||||
CMD(crit_proto_start, CRIT_PROTOCOL_START);
|
||||
CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
|
||||
if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
|
||||
CMD(channel_switch, CHANNEL_SWITCH);
|
||||
CMD(set_qos_map, SET_QOS_MAP);
|
||||
}
|
||||
CMD(set_qos_map, SET_QOS_MAP);
|
||||
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
CMD(testmode_cmd, TESTMODE);
|
||||
#endif
|
||||
|
||||
/* add into the if now */
|
||||
#undef CMD
|
||||
|
||||
if (rdev->ops->connect || rdev->ops->auth) {
|
||||
|
@ -935,7 +935,7 @@ freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
|
||||
if (!band_rule_found)
|
||||
band_rule_found = freq_in_rule_band(fr, center_freq);
|
||||
|
||||
bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(5));
|
||||
bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(20));
|
||||
|
||||
if (band_rule_found && bw_fits)
|
||||
return rr;
|
||||
@ -1019,10 +1019,10 @@ static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Find an ieee80211_reg_rule such that a 5MHz channel with frequency
|
||||
* chan->center_freq fits there.
|
||||
* If there is no such reg_rule, disable the channel, otherwise set the
|
||||
* flags corresponding to the bandwidths allowed in the particular reg_rule
|
||||
/*
|
||||
* Note that right now we assume the desired channel bandwidth
|
||||
* is always 20 MHz for each individual channel (HT40 uses 20 MHz
|
||||
* per channel, the primary and the extension channel).
|
||||
*/
|
||||
static void handle_channel(struct wiphy *wiphy,
|
||||
enum nl80211_reg_initiator initiator,
|
||||
@ -1083,12 +1083,8 @@ static void handle_channel(struct wiphy *wiphy,
|
||||
if (reg_rule->flags & NL80211_RRF_AUTO_BW)
|
||||
max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
|
||||
|
||||
if (max_bandwidth_khz < MHZ_TO_KHZ(10))
|
||||
bw_flags = IEEE80211_CHAN_NO_10MHZ;
|
||||
if (max_bandwidth_khz < MHZ_TO_KHZ(20))
|
||||
bw_flags |= IEEE80211_CHAN_NO_20MHZ;
|
||||
if (max_bandwidth_khz < MHZ_TO_KHZ(40))
|
||||
bw_flags |= IEEE80211_CHAN_NO_HT40;
|
||||
bw_flags = IEEE80211_CHAN_NO_HT40;
|
||||
if (max_bandwidth_khz < MHZ_TO_KHZ(80))
|
||||
bw_flags |= IEEE80211_CHAN_NO_80MHZ;
|
||||
if (max_bandwidth_khz < MHZ_TO_KHZ(160))
|
||||
@ -1522,12 +1518,8 @@ static void handle_channel_custom(struct wiphy *wiphy,
|
||||
if (reg_rule->flags & NL80211_RRF_AUTO_BW)
|
||||
max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
|
||||
|
||||
if (max_bandwidth_khz < MHZ_TO_KHZ(10))
|
||||
bw_flags = IEEE80211_CHAN_NO_10MHZ;
|
||||
if (max_bandwidth_khz < MHZ_TO_KHZ(20))
|
||||
bw_flags |= IEEE80211_CHAN_NO_20MHZ;
|
||||
if (max_bandwidth_khz < MHZ_TO_KHZ(40))
|
||||
bw_flags |= IEEE80211_CHAN_NO_HT40;
|
||||
bw_flags = IEEE80211_CHAN_NO_HT40;
|
||||
if (max_bandwidth_khz < MHZ_TO_KHZ(80))
|
||||
bw_flags |= IEEE80211_CHAN_NO_80MHZ;
|
||||
if (max_bandwidth_khz < MHZ_TO_KHZ(160))
|
||||
|
Loading…
Reference in New Issue
Block a user