Commit c3d0dac6 authored by David S. Miller's avatar David S. Miller

Merge branch 'for-upstream' of...

Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next

Johan Hedberg says:

====================
pull request: bluetooth-next 2015-04-09

We've had enough new patches during the past week (especially from
Marcel) that it'd be good to still get these queued for 4.1.

The majority of the changes are from Marcel with lots of cleanup &
refactoring patches for the HCI UART driver. Marcel also split out some
Broadcom & Intel vendor specific functionality into two new btintel &
btbcm modules.

In addition to the HCI driver changes there's the completion of our
local OOB data interface for pairing, added support for requesting
remote LE features when connecting, as well as a couple of minor fixes
for mac802154.

Please let me know if there are any issues pulling. Thanks.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b52e6921 23310f6f
...@@ -2,9 +2,17 @@ ...@@ -2,9 +2,17 @@
menu "Bluetooth device drivers" menu "Bluetooth device drivers"
depends on BT depends on BT
config BT_INTEL
tristate
config BT_BCM
tristate
select FW_LOADER
config BT_HCIBTUSB config BT_HCIBTUSB
tristate "HCI USB driver" tristate "HCI USB driver"
depends on USB depends on USB
select BT_INTEL
help help
Bluetooth HCI USB driver. Bluetooth HCI USB driver.
This driver is required if you want to use Bluetooth devices with This driver is required if you want to use Bluetooth devices with
...@@ -13,6 +21,17 @@ config BT_HCIBTUSB ...@@ -13,6 +21,17 @@ config BT_HCIBTUSB
Say Y here to compile support for Bluetooth USB devices into the Say Y here to compile support for Bluetooth USB devices into the
kernel or say M to compile it as module (btusb). kernel or say M to compile it as module (btusb).
config BT_HCIBTUSB_BCM
bool "Broadcom protocol support"
depends on BT_HCIBTUSB
select BT_BCM
default y
help
The Broadcom protocol support enables firmware and patchram
download support for Broadcom Bluetooth controllers.
Say Y here to compile support for Broadcom protocol.
config BT_HCIBTSDIO config BT_HCIBTSDIO
tristate "HCI SDIO driver" tristate "HCI SDIO driver"
depends on MMC depends on MMC
...@@ -62,6 +81,7 @@ config BT_HCIUART_BCSP ...@@ -62,6 +81,7 @@ config BT_HCIUART_BCSP
config BT_HCIUART_ATH3K config BT_HCIUART_ATH3K
bool "Atheros AR300x serial support" bool "Atheros AR300x serial support"
depends on BT_HCIUART depends on BT_HCIUART
select BT_HCIUART_H4
help help
HCIATH3K (HCI Atheros AR300x) is a serial protocol for HCIATH3K (HCI Atheros AR300x) is a serial protocol for
communication between host and Atheros AR300x Bluetooth devices. communication between host and Atheros AR300x Bluetooth devices.
...@@ -94,6 +114,27 @@ config BT_HCIUART_3WIRE ...@@ -94,6 +114,27 @@ config BT_HCIUART_3WIRE
Say Y here to compile support for Three-wire UART protocol. Say Y here to compile support for Three-wire UART protocol.
config BT_HCIUART_INTEL
bool "Intel protocol support"
depends on BT_HCIUART
select BT_INTEL
help
The Intel protocol support enables Bluetooth HCI over serial
port interface for Intel Bluetooth controllers.
Say Y here to compile support for Intel protocol.
config BT_HCIUART_BCM
bool "Broadcom protocol support"
depends on BT_HCIUART
select BT_HCIUART_H4
select BT_BCM
help
The Broadcom protocol support enables Bluetooth HCI over serial
port interface for Broadcom Bluetooth controllers.
Say Y here to compile support for Broadcom protocol.
config BT_HCIBCM203X config BT_HCIBCM203X
tristate "HCI BCM203x USB driver" tristate "HCI BCM203x USB driver"
depends on USB depends on USB
......
...@@ -15,10 +15,12 @@ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o ...@@ -15,10 +15,12 @@ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o
obj-$(CONFIG_BT_HCIBTUSB) += btusb.o obj-$(CONFIG_BT_HCIBTUSB) += btusb.o
obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o
obj-$(CONFIG_BT_INTEL) += btintel.o
obj-$(CONFIG_BT_ATH3K) += ath3k.o obj-$(CONFIG_BT_ATH3K) += ath3k.o
obj-$(CONFIG_BT_MRVL) += btmrvl.o obj-$(CONFIG_BT_MRVL) += btmrvl.o
obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o
obj-$(CONFIG_BT_WILINK) += btwilink.o obj-$(CONFIG_BT_WILINK) += btwilink.o
obj-$(CONFIG_BT_BCM) += btbcm.o
btmrvl-y := btmrvl_main.o btmrvl-y := btmrvl_main.o
btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
...@@ -29,6 +31,8 @@ hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o ...@@ -29,6 +31,8 @@ hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
hci_uart-$(CONFIG_BT_HCIUART_ATH3K) += hci_ath.o hci_uart-$(CONFIG_BT_HCIUART_ATH3K) += hci_ath.o
hci_uart-$(CONFIG_BT_HCIUART_3WIRE) += hci_h5.o hci_uart-$(CONFIG_BT_HCIUART_3WIRE) += hci_h5.o
hci_uart-$(CONFIG_BT_HCIUART_INTEL) += hci_intel.o
hci_uart-$(CONFIG_BT_HCIUART_BCM) += hci_bcm.o
hci_uart-objs := $(hci_uart-y) hci_uart-objs := $(hci_uart-y)
ccflags-y += -D__CHECK_ENDIAN__ ccflags-y += -D__CHECK_ENDIAN__
/*
*
* Bluetooth support for Broadcom devices
*
* Copyright (C) 2015 Intel Corporation
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/module.h>
#include <linux/firmware.h>
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include "btbcm.h"
#define VERSION "0.1"
#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}})
int btbcm_check_bdaddr(struct hci_dev *hdev)
{
struct hci_rp_read_bd_addr *bda;
struct sk_buff *skb;
skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
int err = PTR_ERR(skb);
BT_ERR("%s: BCM: Reading device address failed (%d)",
hdev->name, err);
return err;
}
if (skb->len != sizeof(*bda)) {
BT_ERR("%s: BCM: Device address length mismatch", hdev->name);
kfree_skb(skb);
return -EIO;
}
bda = (struct hci_rp_read_bd_addr *)skb->data;
if (bda->status) {
BT_ERR("%s: BCM: Device address result failed (%02x)",
hdev->name, bda->status);
kfree_skb(skb);
return -bt_to_errno(bda->status);
}
/* 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);
return 0;
}
EXPORT_SYMBOL_GPL(btbcm_check_bdaddr);
int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
{
struct sk_buff *skb;
int err;
skb = __hci_cmd_sync(hdev, 0xfc01, 6, bdaddr, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
BT_ERR("%s: BCM: Change address command failed (%d)",
hdev->name, err);
return err;
}
kfree_skb(skb);
return 0;
}
EXPORT_SYMBOL_GPL(btbcm_set_bdaddr);
static int btbcm_reset(struct hci_dev *hdev)
{
struct sk_buff *skb;
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
int err = PTR_ERR(skb);
BT_ERR("%s: BCM: Reset failed (%d)", hdev->name, err);
return err;
}
kfree_skb(skb);
return 0;
}
static struct sk_buff *btbcm_read_local_version(struct hci_dev *hdev)
{
struct sk_buff *skb;
skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
BT_ERR("%s: BCM: Reading local version info failed (%ld)",
hdev->name, PTR_ERR(skb));
return skb;
}
if (skb->len != sizeof(struct hci_rp_read_local_version)) {
BT_ERR("%s: BCM: Local version length mismatch", hdev->name);
kfree_skb(skb);
return ERR_PTR(-EIO);
}
return skb;
}
static struct sk_buff *btbcm_read_verbose_config(struct hci_dev *hdev)
{
struct sk_buff *skb;
skb = __hci_cmd_sync(hdev, 0xfc79, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
BT_ERR("%s: BCM: Read verbose config info failed (%ld)",
hdev->name, PTR_ERR(skb));
return skb;
}
if (skb->len != 7) {
BT_ERR("%s: BCM: Verbose config length mismatch", hdev->name);
kfree_skb(skb);
return ERR_PTR(-EIO);
}
return skb;
}
static struct sk_buff *btbcm_read_usb_product(struct hci_dev *hdev)
{
struct sk_buff *skb;
skb = __hci_cmd_sync(hdev, 0xfc5a, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
BT_ERR("%s: BCM: Read USB product info failed (%ld)",
hdev->name, PTR_ERR(skb));
return skb;
}
if (skb->len != 5) {
BT_ERR("%s: BCM: USB product length mismatch", hdev->name);
kfree_skb(skb);
return ERR_PTR(-EIO);
}
return skb;
}
static const struct {
u16 subver;
const char *name;
} bcm_uart_subver_table[] = {
{ 0x410e, "BCM43341B0" }, /* 002.001.014 */
{ }
};
static const struct {
u16 subver;
const char *name;
} bcm_usb_subver_table[] = {
{ 0x210b, "BCM43142A0" }, /* 001.001.011 */
{ 0x2112, "BCM4314A0" }, /* 001.001.018 */
{ 0x2118, "BCM20702A0" }, /* 001.001.024 */
{ 0x2126, "BCM4335A0" }, /* 001.001.038 */
{ 0x220e, "BCM20702A1" }, /* 001.002.014 */
{ 0x230f, "BCM4354A2" }, /* 001.003.015 */
{ 0x4106, "BCM4335B0" }, /* 002.001.006 */
{ 0x410e, "BCM20702B0" }, /* 002.001.014 */
{ 0x6109, "BCM4335C0" }, /* 003.001.009 */
{ 0x610c, "BCM4354" }, /* 003.001.012 */
{ }
};
int btbcm_setup_patchram(struct hci_dev *hdev)
{
const struct hci_command_hdr *cmd;
const struct firmware *fw;
const u8 *fw_ptr;
size_t fw_size;
char fw_name[64];
u16 opcode, subver, rev, pid, vid;
const char *hw_name = NULL;
struct sk_buff *skb;
struct hci_rp_read_local_version *ver;
int i, err;
/* Reset */
err = btbcm_reset(hdev);
if (err)
return err;
/* Read Local Version Info */
skb = btbcm_read_local_version(hdev);
if (IS_ERR(skb))
return PTR_ERR(skb);
ver = (struct hci_rp_read_local_version *)skb->data;
rev = le16_to_cpu(ver->hci_rev);
subver = le16_to_cpu(ver->lmp_subver);
kfree_skb(skb);
/* Read Verbose Config Version Info */
skb = btbcm_read_verbose_config(hdev);
if (IS_ERR(skb))
return PTR_ERR(skb);
BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]);
kfree_skb(skb);
switch ((rev & 0xf000) >> 12) {
case 0:
for (i = 0; bcm_uart_subver_table[i].name; i++) {
if (subver == bcm_uart_subver_table[i].subver) {
hw_name = bcm_uart_subver_table[i].name;
break;
}
}
snprintf(fw_name, sizeof(fw_name), "brcm/%s.hcd",
hw_name ? : "BCM");
break;
case 1:
case 2:
/* Read USB Product Info */
skb = btbcm_read_usb_product(hdev);
if (IS_ERR(skb))
return PTR_ERR(skb);
vid = get_unaligned_le16(skb->data + 1);
pid = get_unaligned_le16(skb->data + 3);
kfree_skb(skb);
for (i = 0; bcm_usb_subver_table[i].name; i++) {
if (subver == bcm_usb_subver_table[i].subver) {
hw_name = bcm_usb_subver_table[i].name;
break;
}
}
snprintf(fw_name, sizeof(fw_name), "brcm/%s-%4.4x-%4.4x.hcd",
hw_name ? : "BCM", vid, pid);
break;
default:
return 0;
}
BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
hw_name ? : "BCM", (subver & 0x7000) >> 13,
(subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
err = request_firmware(&fw, fw_name, &hdev->dev);
if (err < 0) {
BT_INFO("%s: BCM: patch %s not found", hdev->name, fw_name);
return 0;
}
/* Start Download */
skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
BT_ERR("%s: BCM: Download Minidrv command failed (%d)",
hdev->name, err);
goto reset;
}
kfree_skb(skb);
/* 50 msec delay after Download Minidrv completes */
msleep(50);
fw_ptr = fw->data;
fw_size = fw->size;
while (fw_size >= sizeof(*cmd)) {
const u8 *cmd_param;
cmd = (struct hci_command_hdr *)fw_ptr;
fw_ptr += sizeof(*cmd);
fw_size -= sizeof(*cmd);
if (fw_size < cmd->plen) {
BT_ERR("%s: BCM: patch %s is corrupted", hdev->name,
fw_name);
err = -EINVAL;
goto reset;
}
cmd_param = fw_ptr;
fw_ptr += cmd->plen;
fw_size -= cmd->plen;
opcode = le16_to_cpu(cmd->opcode);
skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
BT_ERR("%s: BCM: patch command %04x failed (%d)",
hdev->name, opcode, err);
goto reset;
}
kfree_skb(skb);
}
/* 250 msec delay after Launch Ram completes */
msleep(250);
reset:
/* Reset */
err = btbcm_reset(hdev);
if (err)
goto done;
/* Read Local Version Info */
skb = btbcm_read_local_version(hdev);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
goto done;
}
ver = (struct hci_rp_read_local_version *)skb->data;
rev = le16_to_cpu(ver->hci_rev);
subver = le16_to_cpu(ver->lmp_subver);
kfree_skb(skb);
BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
hw_name ? : "BCM", (subver & 0x7000) >> 13,
(subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
btbcm_check_bdaddr(hdev);
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
done:
release_firmware(fw);
return err;
}
EXPORT_SYMBOL_GPL(btbcm_setup_patchram);
int btbcm_setup_apple(struct hci_dev *hdev)
{
struct sk_buff *skb;
/* Read Verbose Config Version Info */
skb = btbcm_read_verbose_config(hdev);
if (IS_ERR(skb))
return PTR_ERR(skb);
BT_INFO("%s: BCM: chip id %u build %4.4u", hdev->name, skb->data[1],
get_unaligned_le16(skb->data + 5));
kfree_skb(skb);
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
return 0;
}
EXPORT_SYMBOL_GPL(btbcm_setup_apple);
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth support for Broadcom devices ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
/*
*
* Bluetooth support for Broadcom devices
*
* Copyright (C) 2015 Intel Corporation
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#if IS_ENABLED(CONFIG_BT_BCM)
int btbcm_check_bdaddr(struct hci_dev *hdev);
int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
int btbcm_setup_patchram(struct hci_dev *hdev);
int btbcm_setup_apple(struct hci_dev *hdev);
#else
static inline int btbcm_check_bdaddr(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
}
static inline int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
{
return -EOPNOTSUPP;
}
static inline int btbcm_setup_patchram(struct hci_dev *hdev)
{
return 0;
}
static inline int btbcm_setup_apple(struct hci_dev *hdev)
{
return 0;
}
#endif
/*
*
* Bluetooth support for Intel devices
*
* Copyright (C) 2015 Intel Corporation
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/module.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include "btintel.h"
#define VERSION "0.1"
#define BDADDR_INTEL (&(bdaddr_t) {{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}})
int btintel_check_bdaddr(struct hci_dev *hdev)
{
struct hci_rp_read_bd_addr *bda;
struct sk_buff *skb;
skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
int err = PTR_ERR(skb);
BT_ERR("%s: Reading Intel device address failed (%d)",
hdev->name, err);
return err;
}
if (skb->len != sizeof(*bda)) {
BT_ERR("%s: Intel device address length mismatch", hdev->name);
kfree_skb(skb);
return -EIO;
}
bda = (struct hci_rp_read_bd_addr *)skb->data;
if (bda->status) {
BT_ERR("%s: Intel device address result failed (%02x)",
hdev->name, bda->status);
kfree_skb(skb);
return -bt_to_errno(bda->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(&bda->bdaddr, BDADDR_INTEL)) {
BT_ERR("%s: Found Intel default device address (%pMR)",
hdev->name, &bda->bdaddr);
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
}
kfree_skb(skb);
return 0;
}
EXPORT_SYMBOL_GPL(btintel_check_bdaddr);
int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
{
struct sk_buff *skb;
int err;
skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
BT_ERR("%s: Changing Intel device address failed (%d)",
hdev->name, err);
return err;
}
kfree_skb(skb);
return 0;
}
EXPORT_SYMBOL_GPL(btintel_set_bdaddr);
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
/*
*
* Bluetooth support for Intel devices
*
* Copyright (C) 2015 Intel Corporation
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
struct intel_version {
u8 status;
u8 hw_platform;
u8 hw_variant;
u8 hw_revision;
u8 fw_variant;
u8 fw_revision;
u8 fw_build_num;
u8 fw_build_ww;
u8 fw_build_yy;
u8 fw_patch_num;
} __packed;
struct intel_boot_params {
__u8 status;
__u8 otp_format;
__u8 otp_content;
__u8 otp_patch;
__le16 dev_revid;
__u8 secure_boot;
__u8 key_from_hdr;
__u8 key_type;
__u8 otp_lock;
__u8 api_lock;
__u8 debug_lock;
bdaddr_t otp_bdaddr;
__u8 min_fw_build_nn;
__u8 min_fw_build_cw;
__u8 min_fw_build_yy;
__u8 limited_cce;
__u8 unlocked_state;
} __packed;
struct intel_bootup {
__u8 zero;
__u8 num_cmds;
__u8 source;
__u8 reset_type;
__u8 reset_reason;
__u8 ddc_status;
} __packed;
struct intel_secure_send_result {
__u8 result;
__le16 opcode;
__u8 status;
} __packed;
#if IS_ENABLED(CONFIG_BT_INTEL)
int btintel_check_bdaddr(struct hci_dev *hdev);
int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
#else
static inline int btintel_check_bdaddr(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
}
static inline int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
{
return -EOPNOTSUPP;
}
#endif
This diff is collapsed.
...@@ -45,6 +45,7 @@ struct ath_struct { ...@@ -45,6 +45,7 @@ struct ath_struct {
struct hci_uart *hu; struct hci_uart *hu;
unsigned int cur_sleep; unsigned int cur_sleep;
struct sk_buff *rx_skb;
struct sk_buff_head txq; struct sk_buff_head txq;
struct work_struct ctxtsw; struct work_struct ctxtsw;
}; };
...@@ -136,6 +137,8 @@ static int ath_close(struct hci_uart *hu) ...@@ -136,6 +137,8 @@ static int ath_close(struct hci_uart *hu)
skb_queue_purge(&ath->txq); skb_queue_purge(&ath->txq);
kfree_skb(ath->rx_skb);
cancel_work_sync(&ath->ctxtsw); cancel_work_sync(&ath->ctxtsw);
hu->priv = NULL; hu->priv = NULL;
...@@ -187,22 +190,31 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu) ...@@ -187,22 +190,31 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu)
return skb_dequeue(&ath->txq); return skb_dequeue(&ath->txq);
} }
static const struct h4_recv_pkt ath_recv_pkts[] = {
{ H4_RECV_ACL, .recv = hci_recv_frame },
{ H4_RECV_SCO, .recv = hci_recv_frame },
{ H4_RECV_EVENT, .recv = hci_recv_frame },
};
/* Recv data */ /* Recv data */
static int ath_recv(struct hci_uart *hu, void *data, int count) static int ath_recv(struct hci_uart *hu, const void *data, int count)
{ {
int ret; struct ath_struct *ath = hu->priv;
ret = hci_recv_stream_fragment(hu->hdev, data, count); ath->rx_skb = h4_recv_buf(hu->hdev, ath->rx_skb, data, count,
if (ret < 0) { ath_recv_pkts, ARRAY_SIZE(ath_recv_pkts));
BT_ERR("Frame Reassembly Failed"); if (IS_ERR(ath->rx_skb)) {
return ret; int err = PTR_ERR(ath->rx_skb);
BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
return err;
} }
return count; return count;
} }
static struct hci_uart_proto athp = { static const struct hci_uart_proto athp = {
.id = HCI_UART_ATH3K, .id = HCI_UART_ATH3K,
.name = "ATH3K",
.open = ath_open, .open = ath_open,
.close = ath_close, .close = ath_close,
.recv = ath_recv, .recv = ath_recv,
...@@ -213,14 +225,7 @@ static struct hci_uart_proto athp = { ...@@ -213,14 +225,7 @@ static struct hci_uart_proto athp = {
int __init ath_init(void) int __init ath_init(void)
{ {
int err = hci_uart_register_proto(&athp); return hci_uart_register_proto(&athp);
if (!err)
BT_INFO("HCIATH3K protocol initialized");
else
BT_ERR("HCIATH3K protocol registration failed");
return err;
} }
int __exit ath_deinit(void) int __exit ath_deinit(void)
......
/*
*
* Bluetooth HCI UART driver for Broadcom devices
*
* Copyright (C) 2015 Intel Corporation
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/skbuff.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include "btbcm.h"
#include "hci_uart.h"
struct bcm_data {
struct sk_buff *rx_skb;
struct sk_buff_head txq;
};
static int bcm_open(struct hci_uart *hu)
{
struct bcm_data *bcm;
BT_DBG("hu %p", hu);
bcm = kzalloc(sizeof(*bcm), GFP_KERNEL);
if (!bcm)
return -ENOMEM;
skb_queue_head_init(&bcm->txq);
hu->priv = bcm;
return 0;
}
static int bcm_close(struct hci_uart *hu)
{
struct bcm_data *bcm = hu->priv;
BT_DBG("hu %p", hu);
skb_queue_purge(&bcm->txq);
kfree_skb(bcm->rx_skb);
kfree(bcm);
hu->priv = NULL;
return 0;
}
static int bcm_flush(struct hci_uart *hu)
{
struct bcm_data *bcm = hu->priv;
BT_DBG("hu %p", hu);
skb_queue_purge(&bcm->txq);
return 0;
}
static int bcm_setup(struct hci_uart *hu)
{
BT_DBG("hu %p", hu);
hu->hdev->set_bdaddr = btbcm_set_bdaddr;
return btbcm_setup_patchram(hu->hdev);
}
static const struct h4_recv_pkt bcm_recv_pkts[] = {
{ H4_RECV_ACL, .recv = hci_recv_frame },
{ H4_RECV_SCO, .recv = hci_recv_frame },
{ H4_RECV_EVENT, .recv = hci_recv_frame },
};
static int bcm_recv(struct hci_uart *hu, const void *data, int count)
{
struct bcm_data *bcm = hu->priv;
if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
return -EUNATCH;
bcm->rx_skb = h4_recv_buf(hu->hdev, bcm->rx_skb, data, count,
bcm_recv_pkts, ARRAY_SIZE(bcm_recv_pkts));
if (IS_ERR(bcm->rx_skb)) {
int err = PTR_ERR(bcm->rx_skb);
BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
return err;
}
return count;
}
static int bcm_enqueue(struct hci_uart *hu, struct sk_buff *skb)
{
struct bcm_data *bcm = hu->priv;
BT_DBG("hu %p skb %p", hu, skb);
/* Prepend skb with frame type */
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
skb_queue_tail(&bcm->txq, skb);
return 0;
}
static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
{
struct bcm_data *bcm = hu->priv;
return skb_dequeue(&bcm->txq);
}
static const struct hci_uart_proto bcm_proto = {
.id = HCI_UART_BCM,
.name = "BCM",
.open = bcm_open,
.close = bcm_close,
.flush = bcm_flush,
.setup = bcm_setup,
.recv = bcm_recv,
.enqueue = bcm_enqueue,
.dequeue = bcm_dequeue,
};
int __init bcm_init(void)
{
return hci_uart_register_proto(&bcm_proto);
}
int __exit bcm_deinit(void)
{
return hci_uart_unregister_proto(&bcm_proto);
}
...@@ -47,8 +47,6 @@ ...@@ -47,8 +47,6 @@
#include "hci_uart.h" #include "hci_uart.h"
#define VERSION "0.3"
static bool txcrc = 1; static bool txcrc = 1;
static bool hciextn = 1; static bool hciextn = 1;
...@@ -554,10 +552,10 @@ static u16 bscp_get_crc(struct bcsp_struct *bcsp) ...@@ -554,10 +552,10 @@ static u16 bscp_get_crc(struct bcsp_struct *bcsp)
} }
/* Recv data */ /* Recv data */
static int bcsp_recv(struct hci_uart *hu, void *data, int count) static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
{ {
struct bcsp_struct *bcsp = hu->priv; struct bcsp_struct *bcsp = hu->priv;
unsigned char *ptr; const unsigned char *ptr;
BT_DBG("hu %p count %d rx_state %d rx_count %ld", BT_DBG("hu %p count %d rx_state %d rx_count %ld",
hu, count, bcsp->rx_state, bcsp->rx_count); hu, count, bcsp->rx_state, bcsp->rx_count);
...@@ -735,8 +733,9 @@ static int bcsp_close(struct hci_uart *hu) ...@@ -735,8 +733,9 @@ static int bcsp_close(struct hci_uart *hu)
return 0; return 0;
} }
static struct hci_uart_proto bcsp = { static const struct hci_uart_proto bcsp = {
.id = HCI_UART_BCSP, .id = HCI_UART_BCSP,
.name = "BCSP",
.open = bcsp_open, .open = bcsp_open,
.close = bcsp_close, .close = bcsp_close,
.enqueue = bcsp_enqueue, .enqueue = bcsp_enqueue,
...@@ -747,14 +746,7 @@ static struct hci_uart_proto bcsp = { ...@@ -747,14 +746,7 @@ static struct hci_uart_proto bcsp = {
int __init bcsp_init(void) int __init bcsp_init(void)
{ {
int err = hci_uart_register_proto(&bcsp); return hci_uart_register_proto(&bcsp);
if (!err)
BT_INFO("HCI BCSP protocol initialized");
else
BT_ERR("HCI BCSP protocol registration failed");
return err;
} }
int __exit bcsp_deinit(void) int __exit bcsp_deinit(void)
......
...@@ -40,17 +40,14 @@ ...@@ -40,17 +40,14 @@
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
#include "hci_uart.h" #include "hci_uart.h"
#define VERSION "1.2"
struct h4_struct { struct h4_struct {
unsigned long rx_state;
unsigned long rx_count;
struct sk_buff *rx_skb; struct sk_buff *rx_skb;
struct sk_buff_head txq; struct sk_buff_head txq;
}; };
...@@ -117,18 +114,26 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb) ...@@ -117,18 +114,26 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
return 0; return 0;
} }
static const struct h4_recv_pkt h4_recv_pkts[] = {
{ H4_RECV_ACL, .recv = hci_recv_frame },
{ H4_RECV_SCO, .recv = hci_recv_frame },
{ H4_RECV_EVENT, .recv = hci_recv_frame },
};
/* Recv data */ /* Recv data */
static int h4_recv(struct hci_uart *hu, void *data, int count) static int h4_recv(struct hci_uart *hu, const void *data, int count)
{ {
int ret; struct h4_struct *h4 = hu->priv;
if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
return -EUNATCH; return -EUNATCH;
ret = hci_recv_stream_fragment(hu->hdev, data, count); h4->rx_skb = h4_recv_buf(hu->hdev, h4->rx_skb, data, count,
if (ret < 0) { h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts));
BT_ERR("Frame Reassembly Failed"); if (IS_ERR(h4->rx_skb)) {
return ret; int err = PTR_ERR(h4->rx_skb);
BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err);
return err;
} }
return count; return count;
...@@ -140,8 +145,9 @@ static struct sk_buff *h4_dequeue(struct hci_uart *hu) ...@@ -140,8 +145,9 @@ static struct sk_buff *h4_dequeue(struct hci_uart *hu)
return skb_dequeue(&h4->txq); return skb_dequeue(&h4->txq);
} }
static struct hci_uart_proto h4p = { static const struct hci_uart_proto h4p = {
.id = HCI_UART_H4, .id = HCI_UART_H4,
.name = "H4",
.open = h4_open, .open = h4_open,
.close = h4_close, .close = h4_close,
.recv = h4_recv, .recv = h4_recv,
...@@ -152,17 +158,105 @@ static struct hci_uart_proto h4p = { ...@@ -152,17 +158,105 @@ static struct hci_uart_proto h4p = {
int __init h4_init(void) int __init h4_init(void)
{ {
int err = hci_uart_register_proto(&h4p); return hci_uart_register_proto(&h4p);
if (!err)
BT_INFO("HCI H4 protocol initialized");
else
BT_ERR("HCI H4 protocol registration failed");
return err;
} }
int __exit h4_deinit(void) int __exit h4_deinit(void)
{ {
return hci_uart_unregister_proto(&h4p); return hci_uart_unregister_proto(&h4p);
} }
struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
const unsigned char *buffer, int count,
const struct h4_recv_pkt *pkts, int pkts_count)
{
while (count) {
int i, len;
if (!skb) {
for (i = 0; i < pkts_count; i++) {
if (buffer[0] != (&pkts[i])->type)
continue;
skb = bt_skb_alloc((&pkts[i])->maxlen,
GFP_ATOMIC);
if (!skb)
return ERR_PTR(-ENOMEM);
bt_cb(skb)->pkt_type = (&pkts[i])->type;
bt_cb(skb)->expect = (&pkts[i])->hlen;
break;
}
/* Check for invalid packet type */
if (!skb)
return ERR_PTR(-EILSEQ);
count -= 1;
buffer += 1;
}
len = min_t(uint, bt_cb(skb)->expect - skb->len, count);
memcpy(skb_put(skb, len), buffer, len);
count -= len;
buffer += len;
/* Check for partial packet */
if (skb->len < bt_cb(skb)->expect)
continue;
for (i = 0; i < pkts_count; i++) {
if (bt_cb(skb)->pkt_type == (&pkts[i])->type)
break;
}
if (i >= pkts_count) {
kfree_skb(skb);
return ERR_PTR(-EILSEQ);
}
if (skb->len == (&pkts[i])->hlen) {
u16 dlen;
switch ((&pkts[i])->lsize) {
case 0:
/* No variable data length */
(&pkts[i])->recv(hdev, skb);
skb = NULL;
break;
case 1:
/* Single octet variable length */
dlen = skb->data[(&pkts[i])->loff];
bt_cb(skb)->expect += dlen;
if (skb_tailroom(skb) < dlen) {
kfree_skb(skb);
return ERR_PTR(-EMSGSIZE);
}
break;
case 2:
/* Double octet variable length */
dlen = get_unaligned_le16(skb->data +
(&pkts[i])->loff);
bt_cb(skb)->expect += dlen;
if (skb_tailroom(skb) < dlen) {
kfree_skb(skb);
return ERR_PTR(-EMSGSIZE);
}
break;
default:
/* Unsupported variable length */
kfree_skb(skb);
return ERR_PTR(-EILSEQ);
}
} else {
/* Complete frame */
(&pkts[i])->recv(hdev, skb);
skb = NULL;
}
}
return skb;
}
...@@ -511,10 +511,10 @@ static void h5_reset_rx(struct h5 *h5) ...@@ -511,10 +511,10 @@ static void h5_reset_rx(struct h5 *h5)
clear_bit(H5_RX_ESC, &h5->flags); clear_bit(H5_RX_ESC, &h5->flags);
} }
static int h5_recv(struct hci_uart *hu, void *data, int count) static int h5_recv(struct hci_uart *hu, const void *data, int count)
{ {
struct h5 *h5 = hu->priv; struct h5 *h5 = hu->priv;
unsigned char *ptr = data; const unsigned char *ptr = data;
BT_DBG("%s pending %zu count %d", hu->hdev->name, h5->rx_pending, BT_DBG("%s pending %zu count %d", hu->hdev->name, h5->rx_pending,
count); count);
...@@ -743,8 +743,9 @@ static int h5_flush(struct hci_uart *hu) ...@@ -743,8 +743,9 @@ static int h5_flush(struct hci_uart *hu)
return 0; return 0;
} }
static struct hci_uart_proto h5p = { static const struct hci_uart_proto h5p = {
.id = HCI_UART_3WIRE, .id = HCI_UART_3WIRE,
.name = "Three-wire (H5)",
.open = h5_open, .open = h5_open,
.close = h5_close, .close = h5_close,
.recv = h5_recv, .recv = h5_recv,
...@@ -755,14 +756,7 @@ static struct hci_uart_proto h5p = { ...@@ -755,14 +756,7 @@ static struct hci_uart_proto h5p = {
int __init h5_init(void) int __init h5_init(void)
{ {
int err = hci_uart_register_proto(&h5p); return hci_uart_register_proto(&h5p);
if (!err)
BT_INFO("HCI Three-wire UART (H5) protocol initialized");
else
BT_ERR("HCI Three-wire UART (H5) protocol init failed");
return err;
} }
int __exit h5_deinit(void) int __exit h5_deinit(void)
......
/*
*
* Bluetooth HCI UART driver for Intel devices
*
* Copyright (C) 2015 Intel Corporation
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/skbuff.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include "hci_uart.h"
...@@ -44,13 +44,15 @@ ...@@ -44,13 +44,15 @@
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
#include "btintel.h"
#include "btbcm.h"
#include "hci_uart.h" #include "hci_uart.h"
#define VERSION "2.2" #define VERSION "2.3"
static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; static const struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
int hci_uart_register_proto(struct hci_uart_proto *p) int hci_uart_register_proto(const struct hci_uart_proto *p)
{ {
if (p->id >= HCI_UART_MAX_PROTO) if (p->id >= HCI_UART_MAX_PROTO)
return -EINVAL; return -EINVAL;
...@@ -60,10 +62,12 @@ int hci_uart_register_proto(struct hci_uart_proto *p) ...@@ -60,10 +62,12 @@ int hci_uart_register_proto(struct hci_uart_proto *p)
hup[p->id] = p; hup[p->id] = p;
BT_INFO("HCI UART protocol %s registered", p->name);
return 0; return 0;
} }
int hci_uart_unregister_proto(struct hci_uart_proto *p) int hci_uart_unregister_proto(const struct hci_uart_proto *p)
{ {
if (p->id >= HCI_UART_MAX_PROTO) if (p->id >= HCI_UART_MAX_PROTO)
return -EINVAL; return -EINVAL;
...@@ -76,7 +80,7 @@ int hci_uart_unregister_proto(struct hci_uart_proto *p) ...@@ -76,7 +80,7 @@ int hci_uart_unregister_proto(struct hci_uart_proto *p)
return 0; return 0;
} }
static struct hci_uart_proto *hci_uart_get_proto(unsigned int id) static const struct hci_uart_proto *hci_uart_get_proto(unsigned int id)
{ {
if (id >= HCI_UART_MAX_PROTO) if (id >= HCI_UART_MAX_PROTO)
return NULL; return NULL;
...@@ -264,10 +268,48 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -264,10 +268,48 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
static int hci_uart_setup(struct hci_dev *hdev) static int hci_uart_setup(struct hci_dev *hdev)
{ {
struct hci_uart *hu = hci_get_drvdata(hdev); struct hci_uart *hu = hci_get_drvdata(hdev);
struct hci_rp_read_local_version *ver;
struct sk_buff *skb;
if (hu->proto->setup) if (hu->proto->setup)
return hu->proto->setup(hu); return hu->proto->setup(hu);
if (!test_bit(HCI_UART_VND_DETECT, &hu->hdev_flags))
return 0;
skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
BT_ERR("%s: Reading local version information failed (%ld)",
hdev->name, PTR_ERR(skb));
return 0;
}
if (skb->len != sizeof(*ver)) {
BT_ERR("%s: Event length mismatch for version information",
hdev->name);
goto done;
}
ver = (struct hci_rp_read_local_version *)skb->data;
switch (le16_to_cpu(ver->manufacturer)) {
#ifdef CONFIG_BT_HCIUART_INTEL
case 2:
hdev->set_bdaddr = btintel_set_bdaddr;
btintel_check_bdaddr(hdev);
break;
#endif
#ifdef CONFIG_BT_HCIUART_BCM
case 15:
hdev->set_bdaddr = btbcm_set_bdaddr;
btbcm_check_bdaddr(hdev);
break;
#endif
}
done:
kfree_skb(skb);
return 0; return 0;
} }
...@@ -326,7 +368,7 @@ static int hci_uart_tty_open(struct tty_struct *tty) ...@@ -326,7 +368,7 @@ static int hci_uart_tty_open(struct tty_struct *tty)
*/ */
static void hci_uart_tty_close(struct tty_struct *tty) static void hci_uart_tty_close(struct tty_struct *tty)
{ {
struct hci_uart *hu = (void *)tty->disc_data; struct hci_uart *hu = tty->disc_data;
struct hci_dev *hdev; struct hci_dev *hdev;
BT_DBG("tty %p", tty); BT_DBG("tty %p", tty);
...@@ -365,7 +407,7 @@ static void hci_uart_tty_close(struct tty_struct *tty) ...@@ -365,7 +407,7 @@ static void hci_uart_tty_close(struct tty_struct *tty)
*/ */
static void hci_uart_tty_wakeup(struct tty_struct *tty) static void hci_uart_tty_wakeup(struct tty_struct *tty)
{ {
struct hci_uart *hu = (void *)tty->disc_data; struct hci_uart *hu = tty->disc_data;
BT_DBG(""); BT_DBG("");
...@@ -393,9 +435,10 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty) ...@@ -393,9 +435,10 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
* *
* Return Value: None * Return Value: None
*/ */
static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count) static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
char *flags, int count)
{ {
struct hci_uart *hu = (void *)tty->disc_data; struct hci_uart *hu = tty->disc_data;
if (!hu || tty != hu->tty) if (!hu || tty != hu->tty)
return; return;
...@@ -404,7 +447,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f ...@@ -404,7 +447,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f
return; return;
spin_lock(&hu->rx_lock); spin_lock(&hu->rx_lock);
hu->proto->recv(hu, (void *) data, count); hu->proto->recv(hu, data, count);
if (hu->hdev) if (hu->hdev)
hu->hdev->stat.byte_rx += count; hu->hdev->stat.byte_rx += count;
...@@ -469,7 +512,7 @@ static int hci_uart_register_dev(struct hci_uart *hu) ...@@ -469,7 +512,7 @@ static int hci_uart_register_dev(struct hci_uart *hu)
static int hci_uart_set_proto(struct hci_uart *hu, int id) static int hci_uart_set_proto(struct hci_uart *hu, int id)
{ {
struct hci_uart_proto *p; const struct hci_uart_proto *p;
int err; int err;
p = hci_uart_get_proto(id); p = hci_uart_get_proto(id);
...@@ -497,7 +540,8 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags) ...@@ -497,7 +540,8 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags)
BIT(HCI_UART_RESET_ON_INIT) | BIT(HCI_UART_RESET_ON_INIT) |
BIT(HCI_UART_CREATE_AMP) | BIT(HCI_UART_CREATE_AMP) |
BIT(HCI_UART_INIT_PENDING) | BIT(HCI_UART_INIT_PENDING) |
BIT(HCI_UART_EXT_CONFIG); BIT(HCI_UART_EXT_CONFIG) |
BIT(HCI_UART_VND_DETECT);
if (flags & ~valid_flags) if (flags & ~valid_flags)
return -EINVAL; return -EINVAL;
...@@ -520,10 +564,10 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags) ...@@ -520,10 +564,10 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags)
* *
* Return Value: Command dependent * Return Value: Command dependent
*/ */
static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
struct hci_uart *hu = (void *)tty->disc_data; struct hci_uart *hu = tty->disc_data;
int err = 0; int err = 0;
BT_DBG(""); BT_DBG("");
...@@ -637,6 +681,9 @@ static int __init hci_uart_init(void) ...@@ -637,6 +681,9 @@ static int __init hci_uart_init(void)
#ifdef CONFIG_BT_HCIUART_3WIRE #ifdef CONFIG_BT_HCIUART_3WIRE
h5_init(); h5_init();
#endif #endif
#ifdef CONFIG_BT_HCIUART_BCM
bcm_init();
#endif
return 0; return 0;
} }
...@@ -660,6 +707,9 @@ static void __exit hci_uart_exit(void) ...@@ -660,6 +707,9 @@ static void __exit hci_uart_exit(void)
#ifdef CONFIG_BT_HCIUART_3WIRE #ifdef CONFIG_BT_HCIUART_3WIRE
h5_deinit(); h5_deinit();
#endif #endif
#ifdef CONFIG_BT_HCIUART_BCM
bcm_deinit();
#endif
/* Release tty registration of line discipline */ /* Release tty registration of line discipline */
err = tty_unregister_ldisc(N_HCI); err = tty_unregister_ldisc(N_HCI);
......
...@@ -370,10 +370,10 @@ static inline int ll_check_data_len(struct hci_dev *hdev, struct ll_struct *ll, ...@@ -370,10 +370,10 @@ static inline int ll_check_data_len(struct hci_dev *hdev, struct ll_struct *ll,
} }
/* Recv data */ /* Recv data */
static int ll_recv(struct hci_uart *hu, void *data, int count) static int ll_recv(struct hci_uart *hu, const void *data, int count)
{ {
struct ll_struct *ll = hu->priv; struct ll_struct *ll = hu->priv;
char *ptr; const char *ptr;
struct hci_event_hdr *eh; struct hci_event_hdr *eh;
struct hci_acl_hdr *ah; struct hci_acl_hdr *ah;
struct hci_sco_hdr *sh; struct hci_sco_hdr *sh;
...@@ -505,8 +505,9 @@ static struct sk_buff *ll_dequeue(struct hci_uart *hu) ...@@ -505,8 +505,9 @@ static struct sk_buff *ll_dequeue(struct hci_uart *hu)
return skb_dequeue(&ll->txq); return skb_dequeue(&ll->txq);
} }
static struct hci_uart_proto llp = { static const struct hci_uart_proto llp = {
.id = HCI_UART_LL, .id = HCI_UART_LL,
.name = "LL",
.open = ll_open, .open = ll_open,
.close = ll_close, .close = ll_close,
.recv = ll_recv, .recv = ll_recv,
...@@ -517,14 +518,7 @@ static struct hci_uart_proto llp = { ...@@ -517,14 +518,7 @@ static struct hci_uart_proto llp = {
int __init ll_init(void) int __init ll_init(void)
{ {
int err = hci_uart_register_proto(&llp); return hci_uart_register_proto(&llp);
if (!err)
BT_INFO("HCILL protocol initialized");
else
BT_ERR("HCILL protocol registration failed");
return err;
} }
int __exit ll_deinit(void) int __exit ll_deinit(void)
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
#define HCIUARTGETFLAGS _IOR('U', 204, int) #define HCIUARTGETFLAGS _IOR('U', 204, int)
/* UART protocols */ /* UART protocols */
#define HCI_UART_MAX_PROTO 6 #define HCI_UART_MAX_PROTO 8
#define HCI_UART_H4 0 #define HCI_UART_H4 0
#define HCI_UART_BCSP 1 #define HCI_UART_BCSP 1
...@@ -43,23 +43,27 @@ ...@@ -43,23 +43,27 @@
#define HCI_UART_H4DS 3 #define HCI_UART_H4DS 3
#define HCI_UART_LL 4 #define HCI_UART_LL 4
#define HCI_UART_ATH3K 5 #define HCI_UART_ATH3K 5
#define HCI_UART_INTEL 6
#define HCI_UART_BCM 7
#define HCI_UART_RAW_DEVICE 0 #define HCI_UART_RAW_DEVICE 0
#define HCI_UART_RESET_ON_INIT 1 #define HCI_UART_RESET_ON_INIT 1
#define HCI_UART_CREATE_AMP 2 #define HCI_UART_CREATE_AMP 2
#define HCI_UART_INIT_PENDING 3 #define HCI_UART_INIT_PENDING 3
#define HCI_UART_EXT_CONFIG 4 #define HCI_UART_EXT_CONFIG 4
#define HCI_UART_VND_DETECT 5
struct hci_uart; struct hci_uart;
struct hci_uart_proto { struct hci_uart_proto {
unsigned int id; unsigned int id;
const char *name;
int (*open)(struct hci_uart *hu); int (*open)(struct hci_uart *hu);
int (*close)(struct hci_uart *hu); int (*close)(struct hci_uart *hu);
int (*flush)(struct hci_uart *hu); int (*flush)(struct hci_uart *hu);
int (*recv)(struct hci_uart *hu, void *data, int len);
int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb);
int (*setup)(struct hci_uart *hu); int (*setup)(struct hci_uart *hu);
int (*recv)(struct hci_uart *hu, const void *data, int len);
int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb);
struct sk_buff *(*dequeue)(struct hci_uart *hu); struct sk_buff *(*dequeue)(struct hci_uart *hu);
}; };
...@@ -72,7 +76,7 @@ struct hci_uart { ...@@ -72,7 +76,7 @@ struct hci_uart {
struct work_struct init_ready; struct work_struct init_ready;
struct work_struct write_work; struct work_struct write_work;
struct hci_uart_proto *proto; const struct hci_uart_proto *proto;
void *priv; void *priv;
struct sk_buff *tx_skb; struct sk_buff *tx_skb;
...@@ -88,14 +92,48 @@ struct hci_uart { ...@@ -88,14 +92,48 @@ struct hci_uart {
#define HCI_UART_SENDING 1 #define HCI_UART_SENDING 1
#define HCI_UART_TX_WAKEUP 2 #define HCI_UART_TX_WAKEUP 2
int hci_uart_register_proto(struct hci_uart_proto *p); int hci_uart_register_proto(const struct hci_uart_proto *p);
int hci_uart_unregister_proto(struct hci_uart_proto *p); int hci_uart_unregister_proto(const struct hci_uart_proto *p);
int hci_uart_tx_wakeup(struct hci_uart *hu); int hci_uart_tx_wakeup(struct hci_uart *hu);
int hci_uart_init_ready(struct hci_uart *hu); int hci_uart_init_ready(struct hci_uart *hu);
#ifdef CONFIG_BT_HCIUART_H4 #ifdef CONFIG_BT_HCIUART_H4
int h4_init(void); int h4_init(void);
int h4_deinit(void); int h4_deinit(void);
struct h4_recv_pkt {
u8 type; /* Packet type */
u8 hlen; /* Header length */
u8 loff; /* Data length offset in header */
u8 lsize; /* Data length field size */
u16 maxlen; /* Max overall packet length */
int (*recv)(struct hci_dev *hdev, struct sk_buff *skb);
};
#define H4_RECV_ACL \
.type = HCI_ACLDATA_PKT, \
.hlen = HCI_ACL_HDR_SIZE, \
.loff = 2, \
.lsize = 2, \
.maxlen = HCI_MAX_FRAME_SIZE \
#define H4_RECV_SCO \
.type = HCI_SCODATA_PKT, \
.hlen = HCI_SCO_HDR_SIZE, \
.loff = 2, \
.lsize = 1, \
.maxlen = HCI_MAX_SCO_SIZE
#define H4_RECV_EVENT \
.type = HCI_EVENT_PKT, \
.hlen = HCI_EVENT_HDR_SIZE, \
.loff = 1, \
.lsize = 1, \
.maxlen = HCI_MAX_EVENT_SIZE
struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
const unsigned char *buffer, int count,
const struct h4_recv_pkt *pkts, int pkts_count);
#endif #endif
#ifdef CONFIG_BT_HCIUART_BCSP #ifdef CONFIG_BT_HCIUART_BCSP
...@@ -117,3 +155,8 @@ int ath_deinit(void); ...@@ -117,3 +155,8 @@ int ath_deinit(void);
int h5_init(void); int h5_init(void);
int h5_deinit(void); int h5_deinit(void);
#endif #endif
#ifdef CONFIG_BT_HCIUART_BCM
int bcm_init(void);
int bcm_deinit(void);
#endif
...@@ -1173,7 +1173,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw, ...@@ -1173,7 +1173,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw,
} }
static int static int
at86rf230_set_txpower(struct ieee802154_hw *hw, int db) at86rf230_set_txpower(struct ieee802154_hw *hw, s8 db)
{ {
struct at86rf230_local *lp = hw->priv; struct at86rf230_local *lp = hw->priv;
......
...@@ -374,6 +374,7 @@ enum { ...@@ -374,6 +374,7 @@ enum {
/* LE features */ /* LE features */
#define HCI_LE_ENCRYPTION 0x01 #define HCI_LE_ENCRYPTION 0x01
#define HCI_LE_CONN_PARAM_REQ_PROC 0x02 #define HCI_LE_CONN_PARAM_REQ_PROC 0x02
#define HCI_LE_SLAVE_FEATURES 0x08
#define HCI_LE_PING 0x10 #define HCI_LE_PING 0x10
#define HCI_LE_DATA_LEN_EXT 0x20 #define HCI_LE_DATA_LEN_EXT 0x20
#define HCI_LE_EXT_SCAN_POLICY 0x80 #define HCI_LE_EXT_SCAN_POLICY 0x80
...@@ -463,12 +464,14 @@ enum { ...@@ -463,12 +464,14 @@ enum {
#define EIR_NAME_COMPLETE 0x09 /* complete local name */ #define EIR_NAME_COMPLETE 0x09 /* complete local name */
#define EIR_TX_POWER 0x0A /* transmit power level */ #define EIR_TX_POWER 0x0A /* transmit power level */
#define EIR_CLASS_OF_DEV 0x0D /* Class of Device */ #define EIR_CLASS_OF_DEV 0x0D /* Class of Device */
#define EIR_SSP_HASH_C 0x0E /* Simple Pairing Hash C */ #define EIR_SSP_HASH_C192 0x0E /* Simple Pairing Hash C-192 */
#define EIR_SSP_RAND_R 0x0F /* Simple Pairing Randomizer R */ #define EIR_SSP_RAND_R192 0x0F /* Simple Pairing Randomizer R-192 */
#define EIR_DEVICE_ID 0x10 /* device ID */ #define EIR_DEVICE_ID 0x10 /* device ID */
#define EIR_APPEARANCE 0x19 /* Device appearance */ #define EIR_APPEARANCE 0x19 /* Device appearance */
#define EIR_LE_BDADDR 0x1B /* LE Bluetooth device address */ #define EIR_LE_BDADDR 0x1B /* LE Bluetooth device address */
#define EIR_LE_ROLE 0x1C /* LE role */ #define EIR_LE_ROLE 0x1C /* LE role */
#define EIR_SSP_HASH_C256 0x1D /* Simple Pairing Hash C-256 */
#define EIR_SSP_RAND_R256 0x1E /* Simple Pairing Rand R-256 */
#define EIR_LE_SC_CONFIRM 0x22 /* LE SC Confirmation Value */ #define EIR_LE_SC_CONFIRM 0x22 /* LE SC Confirmation Value */
#define EIR_LE_SC_RANDOM 0x23 /* LE SC Random Value */ #define EIR_LE_SC_RANDOM 0x23 /* LE SC Random Value */
...@@ -1374,6 +1377,11 @@ struct hci_cp_le_conn_update { ...@@ -1374,6 +1377,11 @@ struct hci_cp_le_conn_update {
__le16 max_ce_len; __le16 max_ce_len;
} __packed; } __packed;
#define HCI_OP_LE_READ_REMOTE_FEATURES 0x2016
struct hci_cp_le_read_remote_features {
__le16 handle;
} __packed;
#define HCI_OP_LE_START_ENC 0x2019 #define HCI_OP_LE_START_ENC 0x2019
struct hci_cp_le_start_enc { struct hci_cp_le_start_enc {
__le16 handle; __le16 handle;
...@@ -1866,6 +1874,13 @@ struct hci_ev_le_conn_update_complete { ...@@ -1866,6 +1874,13 @@ struct hci_ev_le_conn_update_complete {
__le16 supervision_timeout; __le16 supervision_timeout;
} __packed; } __packed;
#define HCI_EV_LE_REMOTE_FEAT_COMPLETE 0x04
struct hci_ev_le_remote_feat_complete {
__u8 status;
__le16 handle;
__u8 features[8];
} __packed;
#define HCI_EV_LE_LTK_REQ 0x05 #define HCI_EV_LE_LTK_REQ 0x05
struct hci_ev_le_ltk_req { struct hci_ev_le_ltk_req {
__le16 handle; __le16 handle;
......
...@@ -185,7 +185,6 @@ struct amp_assoc { ...@@ -185,7 +185,6 @@ struct amp_assoc {
#define HCI_MAX_PAGES 3 #define HCI_MAX_PAGES 3
#define NUM_REASSEMBLY 4
struct hci_dev { struct hci_dev {
struct list_head list; struct list_head list;
struct mutex lock; struct mutex lock;
...@@ -327,7 +326,6 @@ struct hci_dev { ...@@ -327,7 +326,6 @@ struct hci_dev {
struct sk_buff_head cmd_q; struct sk_buff_head cmd_q;
struct sk_buff *sent_cmd; struct sk_buff *sent_cmd;
struct sk_buff *reassembly[NUM_REASSEMBLY];
struct mutex req_lock; struct mutex req_lock;
wait_queue_head_t req_wait_q; wait_queue_head_t req_wait_q;
...@@ -1012,7 +1010,6 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, ...@@ -1012,7 +1010,6 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb); int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count);
void hci_init_sysfs(struct hci_dev *hdev); void hci_init_sysfs(struct hci_dev *hdev);
void hci_conn_init_sysfs(struct hci_conn *conn); void hci_conn_init_sysfs(struct hci_conn *conn);
......
...@@ -213,7 +213,7 @@ struct ieee802154_ops { ...@@ -213,7 +213,7 @@ struct ieee802154_ops {
int (*set_hw_addr_filt)(struct ieee802154_hw *hw, int (*set_hw_addr_filt)(struct ieee802154_hw *hw,
struct ieee802154_hw_addr_filt *filt, struct ieee802154_hw_addr_filt *filt,
unsigned long changed); unsigned long changed);
int (*set_txpower)(struct ieee802154_hw *hw, int db); int (*set_txpower)(struct ieee802154_hw *hw, s8 dbm);
int (*set_lbt)(struct ieee802154_hw *hw, bool on); int (*set_lbt)(struct ieee802154_hw *hw, bool on);
int (*set_cca_mode)(struct ieee802154_hw *hw, int (*set_cca_mode)(struct ieee802154_hw *hw,
const struct wpan_phy_cca *cca); const struct wpan_phy_cca *cca);
...@@ -247,7 +247,7 @@ static inline void ieee802154_le64_to_be64(void *be64_dst, const void *le64_src) ...@@ -247,7 +247,7 @@ static inline void ieee802154_le64_to_be64(void *be64_dst, const void *le64_src)
__put_unaligned_memmove64(swab64p(le64_src), be64_dst); __put_unaligned_memmove64(swab64p(le64_src), be64_dst);
} }
/* Basic interface to register ieee802154 hwice */ /* Basic interface to register ieee802154 device */
struct ieee802154_hw * struct ieee802154_hw *
ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops); ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops);
void ieee802154_free_hw(struct ieee802154_hw *hw); void ieee802154_free_hw(struct ieee802154_hw *hw);
......
...@@ -3200,7 +3200,7 @@ EXPORT_SYMBOL(hci_register_dev); ...@@ -3200,7 +3200,7 @@ EXPORT_SYMBOL(hci_register_dev);
/* Unregister HCI device */ /* Unregister HCI device */
void hci_unregister_dev(struct hci_dev *hdev) void hci_unregister_dev(struct hci_dev *hdev)
{ {
int i, id; int id;
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
...@@ -3214,9 +3214,6 @@ void hci_unregister_dev(struct hci_dev *hdev) ...@@ -3214,9 +3214,6 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_dev_do_close(hdev); hci_dev_do_close(hdev);
for (i = 0; i < NUM_REASSEMBLY; i++)
kfree_skb(hdev->reassembly[i]);
cancel_work_sync(&hdev->power_on); cancel_work_sync(&hdev->power_on);
if (!test_bit(HCI_INIT, &hdev->flags) && if (!test_bit(HCI_INIT, &hdev->flags) &&
...@@ -3320,149 +3317,6 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -3320,149 +3317,6 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
} }
EXPORT_SYMBOL(hci_recv_frame); EXPORT_SYMBOL(hci_recv_frame);
static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
int count, __u8 index)
{
int len = 0;
int hlen = 0;
int remain = count;
struct sk_buff *skb;
struct bt_skb_cb *scb;
if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) ||
index >= NUM_REASSEMBLY)
return -EILSEQ;
skb = hdev->reassembly[index];
if (!skb) {
switch (type) {
case HCI_ACLDATA_PKT:
len = HCI_MAX_FRAME_SIZE;
hlen = HCI_ACL_HDR_SIZE;
break;
case HCI_EVENT_PKT:
len = HCI_MAX_EVENT_SIZE;
hlen = HCI_EVENT_HDR_SIZE;
break;
case HCI_SCODATA_PKT:
len = HCI_MAX_SCO_SIZE;
hlen = HCI_SCO_HDR_SIZE;
break;
}
skb = bt_skb_alloc(len, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
scb = (void *) skb->cb;
scb->expect = hlen;
scb->pkt_type = type;
hdev->reassembly[index] = skb;
}
while (count) {
scb = (void *) skb->cb;
len = min_t(uint, scb->expect, count);
memcpy(skb_put(skb, len), data, len);
count -= len;
data += len;
scb->expect -= len;
remain = count;
switch (type) {
case HCI_EVENT_PKT:
if (skb->len == HCI_EVENT_HDR_SIZE) {
struct hci_event_hdr *h = hci_event_hdr(skb);
scb->expect = h->plen;
if (skb_tailroom(skb) < scb->expect) {
kfree_skb(skb);
hdev->reassembly[index] = NULL;
return -ENOMEM;
}
}
break;
case HCI_ACLDATA_PKT:
if (skb->len == HCI_ACL_HDR_SIZE) {
struct hci_acl_hdr *h = hci_acl_hdr(skb);
scb->expect = __le16_to_cpu(h->dlen);
if (skb_tailroom(skb) < scb->expect) {
kfree_skb(skb);
hdev->reassembly[index] = NULL;
return -ENOMEM;
}
}
break;
case HCI_SCODATA_PKT:
if (skb->len == HCI_SCO_HDR_SIZE) {
struct hci_sco_hdr *h = hci_sco_hdr(skb);
scb->expect = h->dlen;
if (skb_tailroom(skb) < scb->expect) {
kfree_skb(skb);
hdev->reassembly[index] = NULL;
return -ENOMEM;
}
}
break;
}
if (scb->expect == 0) {
/* Complete frame */
bt_cb(skb)->pkt_type = type;
hci_recv_frame(hdev, skb);
hdev->reassembly[index] = NULL;
return remain;
}
}
return remain;
}
#define STREAM_REASSEMBLY 0
int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
{
int type;
int rem = 0;
while (count) {
struct sk_buff *skb = hdev->reassembly[STREAM_REASSEMBLY];
if (!skb) {
struct { char type; } *pkt;
/* Start of the frame */
pkt = data;
type = pkt->type;
data++;
count--;
} else
type = bt_cb(skb)->pkt_type;
rem = hci_reassembly(hdev, type, data, count,
STREAM_REASSEMBLY);
if (rem < 0)
return rem;
data += (count - rem);
count = rem;
}
return rem;
}
EXPORT_SYMBOL(hci_recv_stream_fragment);
/* ---- Interface to upper protocols ---- */ /* ---- Interface to upper protocols ---- */
int hci_register_cb(struct hci_cb *cb) int hci_register_cb(struct hci_cb *cb)
......
...@@ -2036,6 +2036,33 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status) ...@@ -2036,6 +2036,33 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status)
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static void hci_cs_le_read_remote_features(struct hci_dev *hdev, u8 status)
{
struct hci_cp_le_read_remote_features *cp;
struct hci_conn *conn;
BT_DBG("%s status 0x%2.2x", hdev->name, status);
if (!status)
return;
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_READ_REMOTE_FEATURES);
if (!cp)
return;
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
if (conn) {
if (conn->state == BT_CONFIG) {
hci_connect_cfm(conn, status);
hci_conn_drop(conn);
}
}
hci_dev_unlock(hdev);
}
static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status) static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
{ {
struct hci_cp_le_start_enc *cp; struct hci_cp_le_start_enc *cp;
...@@ -3104,6 +3131,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb, ...@@ -3104,6 +3131,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb,
hci_cs_le_create_conn(hdev, ev->status); hci_cs_le_create_conn(hdev, ev->status);
break; break;
case HCI_OP_LE_READ_REMOTE_FEATURES:
hci_cs_le_read_remote_features(hdev, ev->status);
break;
case HCI_OP_LE_START_ENC: case HCI_OP_LE_START_ENC:
hci_cs_le_start_enc(hdev, ev->status); hci_cs_le_start_enc(hdev, ev->status);
break; break;
...@@ -4515,7 +4546,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -4515,7 +4546,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
conn->sec_level = BT_SECURITY_LOW; conn->sec_level = BT_SECURITY_LOW;
conn->handle = __le16_to_cpu(ev->handle); conn->handle = __le16_to_cpu(ev->handle);
conn->state = BT_CONNECTED; conn->state = BT_CONFIG;
conn->le_conn_interval = le16_to_cpu(ev->interval); conn->le_conn_interval = le16_to_cpu(ev->interval);
conn->le_conn_latency = le16_to_cpu(ev->latency); conn->le_conn_latency = le16_to_cpu(ev->latency);
...@@ -4524,7 +4555,33 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -4524,7 +4555,33 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_debugfs_create_conn(conn); hci_debugfs_create_conn(conn);
hci_conn_add_sysfs(conn); hci_conn_add_sysfs(conn);
if (!ev->status) {
/* The remote features procedure is defined for master
* role only. So only in case of an initiated connection
* request the remote features.
*
* If the local controller supports slave-initiated features
* exchange, then requesting the remote features in slave
* role is possible. Otherwise just transition into the
* connected state without requesting the remote features.
*/
if (conn->out ||
(hdev->le_features[0] & HCI_LE_SLAVE_FEATURES)) {
struct hci_cp_le_read_remote_features cp;
cp.handle = __cpu_to_le16(conn->handle);
hci_send_cmd(hdev, HCI_OP_LE_READ_REMOTE_FEATURES,
sizeof(cp), &cp);
hci_conn_hold(conn);
} else {
conn->state = BT_CONNECTED;
hci_connect_cfm(conn, ev->status);
}
} else {
hci_connect_cfm(conn, ev->status); hci_connect_cfm(conn, ev->status);
}
params = hci_pend_le_action_lookup(&hdev->pend_le_conns, &conn->dst, params = hci_pend_le_action_lookup(&hdev->pend_le_conns, &conn->dst,
conn->dst_type); conn->dst_type);
...@@ -4826,6 +4883,48 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -4826,6 +4883,48 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static void hci_le_remote_feat_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_ev_le_remote_feat_complete *ev = (void *)skb->data;
struct hci_conn *conn;
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn) {
if (!ev->status)
memcpy(conn->features[0], ev->features, 8);
if (conn->state == BT_CONFIG) {
__u8 status;
/* If the local controller supports slave-initiated
* features exchange, but the remote controller does
* not, then it is possible that the error code 0x1a
* for unsupported remote feature gets returned.
*
* In this specific case, allow the connection to
* transition into connected state and mark it as
* successful.
*/
if ((hdev->le_features[0] & HCI_LE_SLAVE_FEATURES) &&
!conn->out && ev->status == 0x1a)
status = 0x00;
else
status = ev->status;
conn->state = BT_CONNECTED;
hci_connect_cfm(conn, status);
hci_conn_drop(conn);
}
}
hci_dev_unlock(hdev);
}
static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_ev_le_ltk_req *ev = (void *) skb->data; struct hci_ev_le_ltk_req *ev = (void *) skb->data;
...@@ -4999,6 +5098,10 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -4999,6 +5098,10 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_le_adv_report_evt(hdev, skb); hci_le_adv_report_evt(hdev, skb);
break; break;
case HCI_EV_LE_REMOTE_FEAT_COMPLETE:
hci_le_remote_feat_complete_evt(hdev, skb);
break;
case HCI_EV_LE_LTK_REQ: case HCI_EV_LE_LTK_REQ:
hci_le_ltk_request_evt(hdev, skb); hci_le_ltk_request_evt(hdev, skb);
break; break;
......
...@@ -6466,6 +6466,145 @@ static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, ...@@ -6466,6 +6466,145 @@ static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
return eir_len; return eir_len;
} }
static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status,
u16 opcode, struct sk_buff *skb)
{
const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp;
struct mgmt_rp_read_local_oob_ext_data *mgmt_rp;
u8 *h192, *r192, *h256, *r256;
struct mgmt_pending_cmd *cmd;
u16 eir_len;
int err;
BT_DBG("%s status %u", hdev->name, status);
cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev);
if (!cmd)
return;
mgmt_cp = cmd->param;
if (status) {
status = mgmt_status(status);
eir_len = 0;
h192 = NULL;
r192 = NULL;
h256 = NULL;
r256 = NULL;
} else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) {
struct hci_rp_read_local_oob_data *rp;
if (skb->len != sizeof(*rp)) {
status = MGMT_STATUS_FAILED;
eir_len = 0;
} else {
status = MGMT_STATUS_SUCCESS;
rp = (void *)skb->data;
eir_len = 5 + 18 + 18;
h192 = rp->hash;
r192 = rp->rand;
h256 = NULL;
r256 = NULL;
}
} else {
struct hci_rp_read_local_oob_ext_data *rp;
if (skb->len != sizeof(*rp)) {
status = MGMT_STATUS_FAILED;
eir_len = 0;
} else {
status = MGMT_STATUS_SUCCESS;
rp = (void *)skb->data;
if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
eir_len = 5 + 18 + 18;
h192 = NULL;
r192 = NULL;
} else {
eir_len = 5 + 18 + 18 + 18 + 18;
h192 = rp->hash192;
r192 = rp->rand192;
}
h256 = rp->hash256;
r256 = rp->rand256;
}
}
mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL);
if (!mgmt_rp)
goto done;
if (status)
goto send_rsp;
eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV,
hdev->dev_class, 3);
if (h192 && r192) {
eir_len = eir_append_data(mgmt_rp->eir, eir_len,
EIR_SSP_HASH_C192, h192, 16);
eir_len = eir_append_data(mgmt_rp->eir, eir_len,
EIR_SSP_RAND_R192, r192, 16);
}
if (h256 && r256) {
eir_len = eir_append_data(mgmt_rp->eir, eir_len,
EIR_SSP_HASH_C256, h256, 16);
eir_len = eir_append_data(mgmt_rp->eir, eir_len,
EIR_SSP_RAND_R256, r256, 16);
}
send_rsp:
mgmt_rp->type = mgmt_cp->type;
mgmt_rp->eir_len = cpu_to_le16(eir_len);
err = mgmt_cmd_complete(cmd->sk, hdev->id,
MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status,
mgmt_rp, sizeof(*mgmt_rp) + eir_len);
if (err < 0 || status)
goto done;
hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS);
err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
mgmt_rp, sizeof(*mgmt_rp) + eir_len,
HCI_MGMT_OOB_DATA_EVENTS, cmd->sk);
done:
kfree(mgmt_rp);
mgmt_pending_remove(cmd);
}
static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk,
struct mgmt_cp_read_local_oob_ext_data *cp)
{
struct mgmt_pending_cmd *cmd;
struct hci_request req;
int err;
cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev,
cp, sizeof(*cp));
if (!cmd)
return -ENOMEM;
hci_req_init(&req, hdev);
if (bredr_sc_enabled(hdev))
hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL);
else
hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
err = hci_req_run_skb(&req, read_local_oob_ext_data_complete);
if (err < 0) {
mgmt_pending_remove(cmd);
return err;
}
return 0;
}
static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev, static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
void *data, u16 data_len) void *data, u16 data_len)
{ {
...@@ -6517,8 +6656,19 @@ static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev, ...@@ -6517,8 +6656,19 @@ static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
eir_len = 0; eir_len = 0;
switch (cp->type) { switch (cp->type) {
case BIT(BDADDR_BREDR): case BIT(BDADDR_BREDR):
eir_len = eir_append_data(rp->eir, eir_len, EIR_CLASS_OF_DEV, if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
err = read_local_ssp_oob_req(hdev, sk, cp);
hci_dev_unlock(hdev);
if (!err)
goto done;
status = MGMT_STATUS_FAILED;
goto complete;
} else {
eir_len = eir_append_data(rp->eir, eir_len,
EIR_CLASS_OF_DEV,
hdev->dev_class, 3); hdev->dev_class, 3);
}
break; break;
case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)): case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) && if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment