Re: [PATCH v2 untested] Bluetooth: Add framework for Microsoft vendor extension

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Mar 26, 2020 at 2:05 AM Marcel Holtmann <marcel@xxxxxxxxxxxx> wrote:
>
> From: Miao-chen Chou <mcchou@xxxxxxxxxxxx>
>
> Micrsoft defined a set for HCI vendor extensions. Check the following
> link for details:
>
> https://docs.microsoft.com/en-us/windows-hardware/drivers/bluetooth/microsoft-defined-bluetooth-hci-commands-and-events
>
> This provides the basic framework to enable the extension and read its
> supported features. Drivers still have to declare support for this
> extension before it can be utilized by the host stack.
>
> Signed-off-by: Miao-chen Chou <mcchou@xxxxxxxxxxxx>
> Signed-off-by: Marcel Holtmann <marcel@xxxxxxxxxxxx>
> ---
>  include/net/bluetooth/hci_core.h |   5 ++
>  net/bluetooth/Kconfig            |   7 ++
>  net/bluetooth/Makefile           |   1 +
>  net/bluetooth/hci_core.c         |   5 ++
>  net/bluetooth/hci_event.c        |   5 ++
>  net/bluetooth/msft.c             | 150 +++++++++++++++++++++++++++++++
>  net/bluetooth/msft.h             |  20 +++++
>  7 files changed, 193 insertions(+)
>  create mode 100644 net/bluetooth/msft.c
>  create mode 100644 net/bluetooth/msft.h
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index d4e28773d378..59ddcd3a52cc 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -484,6 +484,11 @@ struct hci_dev {
>         struct led_trigger      *power_led;
>  #endif
>
> +#if IS_ENABLED(CONFIG_BT_MSFTEXT)
> +       __u16                   msft_opcode;
> +       void                    *msft_data;
> +#endif
> +
>         int (*open)(struct hci_dev *hdev);
>         int (*close)(struct hci_dev *hdev);
>         int (*flush)(struct hci_dev *hdev);
> diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig
> index 165148c7c4ce..d439be5c534e 100644
> --- a/net/bluetooth/Kconfig
> +++ b/net/bluetooth/Kconfig
> @@ -93,6 +93,13 @@ config BT_LEDS
>           This option selects a few LED triggers for different
>           Bluetooth events.
>
> +config BT_MSFTEXT
> +       bool "Enable Microsoft extensions"
> +       depends on BT
> +       help
> +         This options enables support for the Microsoft defined HCI
> +         vendor extensions.
> +
>  config BT_SELFTEST
>         bool "Bluetooth self testing support"
>         depends on BT && DEBUG_KERNEL
> diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
> index fda41c0b4781..41dd541a44a5 100644
> --- a/net/bluetooth/Makefile
> +++ b/net/bluetooth/Makefile
> @@ -19,5 +19,6 @@ bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
>  bluetooth-$(CONFIG_BT_BREDR) += sco.o
>  bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
>  bluetooth-$(CONFIG_BT_LEDS) += leds.o
> +bluetooth-$(CONFIG_BT_MSFTEXT) += msft.o
>  bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o
>  bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o
> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> index 2e7bc2da8371..09625e2cb02a 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -44,6 +44,7 @@
>  #include "hci_debugfs.h"
>  #include "smp.h"
>  #include "leds.h"
> +#include "msft.h"
>
>  static void hci_rx_work(struct work_struct *work);
>  static void hci_cmd_work(struct work_struct *work);
> @@ -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 0a591be8b0ae..ed2a96f1ef55 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -35,6 +35,7 @@
>  #include "a2mp.h"
>  #include "amp.h"
>  #include "smp.h"
> +#include "msft.h"
>
>  #define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
>                  "\x00\x00\x00\x00\x00\x00\x00\x00"
> @@ -6145,6 +6146,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
> new file mode 100644
> index 000000000000..6f2af20507a1
> --- /dev/null
> +++ b/net/bluetooth/msft.c
> @@ -0,0 +1,150 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2020 Google Corporation
> + */
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +
> +#include "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;
> +
> +       bt_dev_info(hdev, "Enabling MSFT extensions with opcode 0x%2.2x",
> +                   hdev->msft_opcode);
> +}
> +
> +static bool read_supported_features(struct hci_dev *hdev)
> +{
> +       struct msft_data *msft = hdev->msft_data;
> +       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 false;
> +       }
> +
> +       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;
> +
> +       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 true;
> +
> +failed:
> +       kfree_skb(skb);
> +       return false;
> +}
> +
> +void msft_do_open(struct hci_dev *hdev)
> +{
> +       struct msft_data *msft;
> +
> +       if (hdev->msft_opcode == HCI_OP_NOP)
> +               return;
> +
> +       bt_dev_dbg(hdev, "Initialize MSFT extension");
> +
> +       msft = kzalloc(sizeof(*msft), GFP_KERNEL);
> +       if (!msft)
> +               return;
> +
> +       if (!read_supported_features(hdev)) {
> +               kfree(msft);
> +               return;
> +       }
> +
> +       hdev->msft_data = msft;
> +}
> +
> +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.
> +        */
> +       if (skb->len < 1)
> +               return;
> +
> +       event = *skb->data;
> +       skb_pull(skb, 1);
> +
> +       bt_dev_dbg(hdev, "MSFT vendor event %u", event);
> +}
> diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h
> new file mode 100644
> index 000000000000..f3cf404457a8
> --- /dev/null
> +++ b/net/bluetooth/msft.h
> @@ -0,0 +1,20 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2020 Google Corporation
> + */
> +
> +#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
> --
> 2.25.1
>
Thanks for spending time brainstorming the framework. Somehow I
received email only from your example patches v1 but not v2. I will
upload v4 shortly based on v2.

Regards,
Miao



[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux