Hi Marcel and Luiz,
The standard HCI does not provide commands/events regarding to
advertisement monitoring with content filter while there are few vendors
providing this feature. Chrome OS BT would like to introduce the use of
vendor specific features where Microsoft vendor extension is targeted at
this moment.
Chrome OS BT would like to utilize Microsoft vendor extension's
advertisement monitoring feature which is not yet a part of standard
Bluetooth specification. This series introduces the driver information for
Microsoft vendor extension, and this was verified with kernel 4.4 on Atlas
Chromebook.
Thanks
Miao
Changes in v5:
- Extract the changes on btusb as a different commit.
- Update the include line of msft.h.
- Extract the changes on btusb as a different commit.
Changes in v4:
- Introduce CONFIG_BT_MSFTEXT as a starting point of providing a
framework to use Microsoft extension
- Create include/net/bluetooth/msft.h and net/bluetooth/msft.c to
facilitate functions of Microsoft extension.
- Move MSFT's do_open() and do_close() from net/bluetooth/hci_core.c to
net/bluetooth/msft.c.
- Other than msft opcode, define struct msft_data to host the rest of
information of Microsoft extension and leave a void* pointing to a
msft_data in struct hci_dev.
- Introduce CONFIG_BT_MSFTEXT as a starting point of providing a
framework to use Microsoft extension
- Create include/net/bluetooth/msft.h and net/bluetooth/msft.c to
facilitate functions of Microsoft extension.
Changes in v3:
- Create net/bluetooth/msft.c with struct msft_vnd_ext defined internally
and change the hdev->msft_ext field to void*.
- Define and expose msft_vnd_ext_set_opcode() for btusb use.
- Init hdev->msft_ext in hci_alloc_dev() and deinit it in hci_free_dev().
- Introduce msft_vnd_ext_do_open() and msft_vnd_ext_do_close().
- Create net/bluetooth/msft.c with struct msft_vnd_ext defined internally
and change the hdev->msft_ext field to void*.
- Define and expose msft_vnd_ext_set_opcode() for btusb use.
- Init hdev->msft_ext in hci_alloc_dev() and deinit it in hci_free_dev().
Changes in v2:
- Define struct msft_vnd_ext and add a field of this type to struct
hci_dev to facilitate the support of Microsoft vendor extension.
- Issue a HCI_VS_MSFT_Read_Supported_Features command with
__hci_cmd_sync() instead of constructing a request.
- Define struct msft_vnd_ext and add a field of this type to struct
hci_dev to facilitate the support of Microsoft vendor extension.
Miao-chen Chou (3):
Bluetooth: Add the framework of using Microsoft vendor extension
Bluetooth: Read the supported features of Microsoft vendor extension
Bluetooth: btusb: Indicate Microsoft vendor extension for Intel
9160/9260
drivers/bluetooth/btusb.c | 11 ++-
include/net/bluetooth/hci_core.h | 5 ++
include/net/bluetooth/msft.h | 26 ++++++
net/bluetooth/Kconfig | 7 ++
net/bluetooth/Makefile | 1 +
net/bluetooth/hci_core.c | 5 ++
net/bluetooth/hci_event.c | 5 ++
net/bluetooth/msft.c | 140 +++++++++++++++++++++++++++++++
8 files changed, 199 insertions(+), 1 deletion(-)
create mode 100644 include/net/bluetooth/msft.h
create mode 100644 net/bluetooth/msft.c
--
2.24.1
This defines an opcode and packet structures of Microsoft vendor extension.
For now, we add only the HCI_VS_MSFT_Read_Supported_Features command. See
https://docs.microsoft.com/en-us/windows-hardware/drivers/bluetooth/
microsoft-defined-bluetooth-hci-commands-and-events#microsoft-defined-
bluetooth-hci-events for more details.
Upon initialization of a hci_dev, we issue a
HCI_VS_MSFT_Read_Supported_Features command to read the supported features
of Microsoft vendor extension if the opcode of Microsoft vendor extension
is valid. See https://docs.microsoft.com/en-us/windows-hardware/drivers/
bluetooth/microsoft-defined-bluetooth-hci-commands-and-events#
hci_vs_msft_read_supported_features for more details.
This was verified on a device with Intel ThunderPeak BT controller where
the Microsoft vendor extension features are 0x000000000000003f.
Signed-off-by: Marcel Holtmann <[email protected]>
Signed-off-by: Miao-chen Chou <[email protected]>
---
Changes in v5:
- Update the include line of msft.h.
Changes in v4:
- Move MSFT's do_open() and do_close() from net/bluetooth/hci_core.c to
net/bluetooth/msft.c.
- Other than msft opcode, define struct msft_data to host the rest of
information of Microsoft extension and leave a void* pointing to a
msft_data in struct hci_dev.
Changes in v3:
- Introduce msft_vnd_ext_do_open() and msft_vnd_ext_do_close().
Changes in v2:
- Issue a HCI_VS_MSFT_Read_Supported_Features command with
__hci_cmd_sync() instead of constructing a request.
include/net/bluetooth/hci_core.h | 1 +
include/net/bluetooth/msft.h | 7 ++
net/bluetooth/hci_core.c | 5 ++
net/bluetooth/hci_event.c | 5 ++
net/bluetooth/msft.c | 125 +++++++++++++++++++++++++++++++
5 files changed, 143 insertions(+)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 239cae2d99986..59ddcd3a52ccd 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -486,6 +486,7 @@ struct hci_dev {
#if IS_ENABLED(CONFIG_BT_MSFTEXT)
__u16 msft_opcode;
+ void *msft_data;
#endif
int (*open)(struct hci_dev *hdev);
diff --git a/include/net/bluetooth/msft.h b/include/net/bluetooth/msft.h
index 7218ea759dde4..6cd5e6b3fb784 100644
--- a/include/net/bluetooth/msft.h
+++ b/include/net/bluetooth/msft.h
@@ -4,15 +4,22 @@
#ifndef __MSFT_H
#define __MSFT_H
+#include <linux/errno.h>
#include <net/bluetooth/hci_core.h>
#if IS_ENABLED(CONFIG_BT_MSFTEXT)
void msft_set_opcode(struct hci_dev *hdev, __u16 opcode);
+void msft_do_open(struct hci_dev *hdev);
+void msft_do_close(struct hci_dev *hdev);
+void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb);
#else
static inline void msft_set_opcode(struct hci_dev *hdev, __u16 opcode) {}
+static inline void msft_do_open(struct hci_dev *hdev) {}
+static inline void msft_do_close(struct hci_dev *hdev) {}
+static inline void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb) {}
#endif
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index dbd2ad3a26eda..738b20a731a79 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -39,6 +39,7 @@
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/mgmt.h>
+#include <net/bluetooth/msft.h>
#include "hci_request.h"
#include "hci_debugfs.h"
@@ -1563,6 +1564,8 @@ static int hci_dev_do_open(struct hci_dev *hdev)
hci_dev_test_flag(hdev, HCI_VENDOR_DIAG) && hdev->set_diag)
ret = hdev->set_diag(hdev, true);
+ msft_do_open(hdev);
+
clear_bit(HCI_INIT, &hdev->flags);
if (!ret) {
@@ -1758,6 +1761,8 @@ int hci_dev_do_close(struct hci_dev *hdev)
hci_sock_dev_event(hdev, HCI_DEV_DOWN);
+ msft_do_close(hdev);
+
if (hdev->flush)
hdev->flush(hdev);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 20408d3862683..da42e7f6bcef3 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -29,6 +29,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/mgmt.h>
+#include <net/bluetooth/msft.h>
#include "hci_request.h"
#include "hci_debugfs.h"
@@ -6144,6 +6145,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_num_comp_blocks_evt(hdev, skb);
break;
+ case HCI_EV_VENDOR:
+ msft_vendor_evt(hdev, skb);
+ break;
+
default:
BT_DBG("%s event 0x%2.2x", hdev->name, event);
break;
diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index 04dad4ac7bf78..b1f476ec3fcc5 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -5,6 +5,24 @@
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/msft.h>
+#define MSFT_OP_READ_SUPPORTED_FEATURES 0x00
+struct msft_cp_read_supported_features {
+ __u8 sub_opcode;
+} __packed;
+struct msft_rp_read_supported_features {
+ __u8 status;
+ __u8 sub_opcode;
+ __le64 features;
+ __u8 evt_prefix_len;
+ __u8 evt_prefix[0];
+} __packed;
+
+struct msft_data {
+ __u64 features;
+ __u8 evt_prefix_len;
+ __u8 *evt_prefix;
+};
+
void msft_set_opcode(struct hci_dev *hdev, __u16 opcode)
{
hdev->msft_opcode = opcode;
@@ -13,3 +31,110 @@ void msft_set_opcode(struct hci_dev *hdev, __u16 opcode)
hdev->msft_opcode);
}
EXPORT_SYMBOL(msft_set_opcode);
+
+static struct msft_data *read_supported_features(struct hci_dev *hdev)
+{
+ struct msft_data *msft;
+ struct msft_cp_read_supported_features cp;
+ struct msft_rp_read_supported_features *rp;
+ struct sk_buff *skb;
+
+ cp.sub_opcode = MSFT_OP_READ_SUPPORTED_FEATURES;
+
+ skb = __hci_cmd_sync(hdev, hdev->msft_opcode, sizeof(cp), &cp,
+ HCI_CMD_TIMEOUT);
+ if (IS_ERR(skb)) {
+ bt_dev_err(hdev, "Failed to read MSFT supported features (%ld)",
+ PTR_ERR(skb));
+ return NULL;
+ }
+
+ if (skb->len < sizeof(*rp)) {
+ bt_dev_err(hdev, "MSFT supported features length mismatch");
+ goto failed;
+ }
+
+ rp = (struct msft_rp_read_supported_features *)skb->data;
+
+ if (rp->sub_opcode != MSFT_OP_READ_SUPPORTED_FEATURES)
+ goto failed;
+
+ msft = kzalloc(sizeof(*msft), GFP_KERNEL);
+ if (!msft)
+ goto failed;
+
+ if (rp->evt_prefix_len > 0) {
+ msft->evt_prefix = kmemdup(rp->evt_prefix, rp->evt_prefix_len,
+ GFP_KERNEL);
+ if (!msft->evt_prefix)
+ goto failed;
+ }
+
+ msft->evt_prefix_len = rp->evt_prefix_len;
+ msft->features = __le64_to_cpu(rp->features);
+ kfree_skb(skb);
+
+ bt_dev_info(hdev, "MSFT supported features %llx", msft->features);
+ return msft;
+
+failed:
+ kfree_skb(skb);
+ return NULL;
+}
+
+void msft_do_open(struct hci_dev *hdev)
+{
+ if (hdev->msft_opcode == HCI_OP_NOP)
+ return;
+
+ bt_dev_dbg(hdev, "Initialize MSFT extension");
+ hdev->msft_data = read_supported_features(hdev);
+}
+
+void msft_do_close(struct hci_dev *hdev)
+{
+ struct msft_data *msft = hdev->msft_data;
+
+ if (!msft)
+ return;
+
+ bt_dev_dbg(hdev, "Cleanup of MSFT extension");
+
+ hdev->msft_data = NULL;
+
+ kfree(msft->evt_prefix);
+ kfree(msft);
+}
+
+void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct msft_data *msft = hdev->msft_data;
+ u8 event;
+
+ if (!msft)
+ return;
+
+ /* When the extension has defined an event prefix, check that it
+ * matches, and otherwise just return.
+ */
+ if (msft->evt_prefix_len > 0) {
+ if (skb->len < msft->evt_prefix_len)
+ return;
+
+ if (memcmp(skb->data, msft->evt_prefix, msft->evt_prefix_len))
+ return;
+
+ skb_pull(skb, msft->evt_prefix_len);
+ }
+
+ /* Every event starts at least with an event code and the rest of
+ * the data is variable and depends on the event code. Returns true
+ */
+ if (skb->len < 1)
+ return;
+
+ event = *skb->data;
+ skb_pull(skb, 1);
+
+ bt_dev_dbg(hdev, "MSFT vendor event %u", event);
+}
--
2.24.1
This adds a bit mask of driver_info for Microsoft vendor extension and
indicates the support for Intel 9160/9260. This was verified with Intel
ThunderPeak BT controller where msft_opcode is 0xFC1E.
Signed-off-by: Marcel Holtmann <[email protected]>
Signed-off-by: Miao-chen Chou <[email protected]>
---
Changes in v5:
- Extract the changes on btusb as a different commit.
Changes in v4:
- Introduce CONFIG_BT_MSFTEXT as a starting point of providing a
framework to use Microsoft extension
- Create include/net/bluetooth/msft.h and net/bluetooth/msft.c to
facilitate functions of Microsoft extension.
Changes in v3:
- Create net/bluetooth/msft.c with struct msft_vnd_ext defined internally
and change the hdev->msft_ext field to void*.
- Define and expose msft_vnd_ext_set_opcode() for btusb use.
- Init hdev->msft_ext in hci_alloc_dev() and deinit it in hci_free_dev().
Changes in v2:
- Define struct msft_vnd_ext and add a field of this type to struct
hci_dev to facilitate the support of Microsoft vendor extension.
drivers/bluetooth/btusb.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 3bdec42c96123..f73ad18c04559 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -20,6 +20,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/msft.h>
#include "btintel.h"
#include "btbcm.h"
@@ -58,6 +59,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_CW6622 0x100000
#define BTUSB_MEDIATEK 0x200000
#define BTUSB_WIDEBAND_SPEECH 0x400000
+#define BTUSB_MSFT_VND_EXT 0x800000
static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
@@ -335,7 +337,8 @@ static const struct usb_device_id blacklist_table[] = {
/* Intel Bluetooth devices */
{ USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_NEW |
- BTUSB_WIDEBAND_SPEECH },
+ BTUSB_WIDEBAND_SPEECH |
+ BTUSB_MSFT_VND_EXT },
{ USB_DEVICE(0x8087, 0x0026), .driver_info = BTUSB_INTEL_NEW |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x8087, 0x0029), .driver_info = BTUSB_INTEL_NEW |
@@ -3800,6 +3803,12 @@ static int btusb_probe(struct usb_interface *intf,
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
+
+ /* All Intel controllers that support the Microsoft
+ * vendor extension are using 0xFC1E for VsMsftOpCode.
+ */
+ if (id->driver_info & BTUSB_MSFT_VND_EXT)
+ msft_set_opcode(hdev, 0xFC1E);
}
if (id->driver_info & BTUSB_MARVELL)
--
2.24.1