2022-01-27 17:56:41

by Joseph Hwang

[permalink] [raw]
Subject: [PATCH v2 1/2] Bluetooth: aosp: surface AOSP quality report through mgmt

When receiving a HCI vendor event, the kernel checks if it is an
AOSP bluetooth quality report. If yes, the event is sent to bluez
user space through the mgmt socket.

Signed-off-by: Joseph Hwang <[email protected]>
Reviewed-by: Archie Pusaka <[email protected]>
---

Changes in v2:
- Scrap the two structures defined in aosp.c and use constants for
size check.
- Do a basic size check about the quality report event. Do not pull
data from the event in which the kernel has no interest.
- Define vendor event prefixes with which vendor events of distinct
vendor specifications can be clearly differentiated.
- Use mgmt helpers to add the header and data to a mgmt skb.

include/net/bluetooth/hci_core.h | 2 +
include/net/bluetooth/mgmt.h | 7 +++
net/bluetooth/aosp.c | 19 +++++++
net/bluetooth/aosp.h | 6 ++
net/bluetooth/hci_event.c | 96 +++++++++++++++++++++++++++++++-
net/bluetooth/mgmt.c | 19 +++++++
net/bluetooth/msft.c | 14 +++++
net/bluetooth/msft.h | 12 ++++
8 files changed, 174 insertions(+), 1 deletion(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 21eadb113a31..b726fd595895 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1861,6 +1861,8 @@ int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle,
bdaddr_t *bdaddr, u8 addr_type);
+int mgmt_quality_report(struct hci_dev *hdev, void *data, u32 data_len,
+ u8 quality_spec);

u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
u16 to_multiplier);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 99266f7aebdc..03204b4ba641 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -1120,3 +1120,10 @@ struct mgmt_ev_adv_monitor_device_lost {
__le16 monitor_handle;
struct mgmt_addr_info addr;
} __packed;
+
+#define MGMT_EV_QUALITY_REPORT 0x0031
+struct mgmt_ev_quality_report {
+ __u8 quality_spec;
+ __u32 data_len;
+ __u8 data[];
+} __packed;
diff --git a/net/bluetooth/aosp.c b/net/bluetooth/aosp.c
index 432ae3aac9e3..9ec845a098bd 100644
--- a/net/bluetooth/aosp.c
+++ b/net/bluetooth/aosp.c
@@ -199,3 +199,22 @@ int aosp_set_quality_report(struct hci_dev *hdev, bool enable)
else
return disable_quality_report(hdev);
}
+
+#define BLUETOOTH_QUALITY_REPORT_EV 0x58
+
+/* The following LEN = 1-byte Sub-event code + 48-byte Sub-event Parameters */
+#define BLUETOOTH_QUALITY_REPORT_LEN 49
+
+bool aosp_check_quality_report_len(struct sk_buff *skb)
+{
+ /* skb->len is allowed to be larger than BLUETOOTH_QUALITY_REPORT_LEN
+ * to accommodate an additional Vendor Specific Parameter (vsp) field.
+ */
+ if (skb->len < BLUETOOTH_QUALITY_REPORT_LEN) {
+ BT_ERR("AOSP evt data len %d too short (%u expected)",
+ skb->len, BLUETOOTH_QUALITY_REPORT_LEN);
+ return false;
+ }
+
+ return true;
+}
diff --git a/net/bluetooth/aosp.h b/net/bluetooth/aosp.h
index 2fd8886d51b2..fdb6264b8ea7 100644
--- a/net/bluetooth/aosp.h
+++ b/net/bluetooth/aosp.h
@@ -10,6 +10,7 @@ void aosp_do_close(struct hci_dev *hdev);

bool aosp_has_quality_report(struct hci_dev *hdev);
int aosp_set_quality_report(struct hci_dev *hdev, bool enable);
+bool aosp_check_quality_report_len(struct sk_buff *skb);

#else

@@ -26,4 +27,9 @@ static inline int aosp_set_quality_report(struct hci_dev *hdev, bool enable)
return -EOPNOTSUPP;
}

+static inline bool aosp_check_quality_report_len(struct sk_buff *skb)
+{
+ return false;
+}
+
#endif
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 681c623aa380..1b69d3efd415 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -37,6 +37,7 @@
#include "smp.h"
#include "msft.h"
#include "eir.h"
+#include "aosp.h"

#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00"
@@ -4225,6 +4226,99 @@ static void hci_num_comp_blocks_evt(struct hci_dev *hdev, void *data,
queue_work(hdev->workqueue, &hdev->tx_work);
}

+#define QUALITY_SPEC_NA 0x0
+#define QUALITY_SPEC_INTEL_TELEMETRY 0x1
+#define QUALITY_SPEC_AOSP_BQR 0x2
+
+static void aosp_quality_report_evt(struct hci_dev *hdev, void *data,
+ struct sk_buff *skb)
+{
+ if (aosp_has_quality_report(hdev) && aosp_check_quality_report_len(skb))
+ mgmt_quality_report(hdev, skb->data, skb->len,
+ QUALITY_SPEC_AOSP_BQR);
+}
+
+/* Define the fixed vendor event prefixes below.
+ * Note: AOSP HCI Requirements use 0x54 and up as sub-event codes without
+ * actually defining a vendor prefix. Refer to
+ * https://source.android.com/devices/bluetooth/hci_requirements
+ * Hence, the other vendor event prefixes should not use the same
+ * space to avoid collision.
+ */
+static unsigned char AOSP_BQR_PREFIX[] = { 0x58 };
+
+/* Some vendor prefixes are fixed values and lengths. */
+#define FIXED_EVT_PREFIX(_prefix, _vendor_func) \
+{ \
+ .prefix = _prefix, \
+ .prefix_len = sizeof(_prefix), \
+ .vendor_func = _vendor_func, \
+ .get_prefix = NULL, \
+ .get_prefix_len = NULL, \
+}
+
+/* Some vendor prefixes are only available at run time. The
+ * values and lengths are variable.
+ */
+#define DYNAMIC_EVT_PREFIX(_prefix_func, _prefix_len_func, _vendor_func)\
+{ \
+ .prefix = NULL, \
+ .prefix_len = 0, \
+ .vendor_func = _vendor_func, \
+ .get_prefix = _prefix_func, \
+ .get_prefix_len = _prefix_len_func, \
+}
+
+/* Every distinct vendor specification must have a well-defined vendor
+ * event prefix to determine if a vendor event meets the specification.
+ * If an event prefix is fixed, it should be delcared with FIXED_EVT_PREFIX.
+ * Otherwise, DYNAMIC_EVT_PREFIX should be used for variable prefixes.
+ */
+struct vendor_event_prefix {
+ __u8 *prefix;
+ __u8 prefix_len;
+ void (*vendor_func)(struct hci_dev *hdev, void *data,
+ struct sk_buff *skb);
+ __u8 *(*get_prefix)(struct hci_dev *hdev);
+ __u8 (*get_prefix_len)(struct hci_dev *hdev);
+} evt_prefixes[] = {
+ FIXED_EVT_PREFIX(AOSP_BQR_PREFIX, aosp_quality_report_evt),
+ DYNAMIC_EVT_PREFIX(get_msft_evt_prefix, get_msft_evt_prefix_len,
+ msft_vendor_evt),
+
+ /* end with a null entry */
+ {},
+};
+
+static void hci_vendor_evt(struct hci_dev *hdev, void *data,
+ struct sk_buff *skb)
+{
+ int i;
+ __u8 *prefix;
+ __u8 prefix_len;
+
+ for (i = 0; evt_prefixes[i].vendor_func; i++) {
+ if (evt_prefixes[i].get_prefix)
+ prefix = evt_prefixes[i].get_prefix(hdev);
+ else
+ prefix = evt_prefixes[i].prefix;
+
+ if (evt_prefixes[i].get_prefix_len)
+ prefix_len = evt_prefixes[i].get_prefix_len(hdev);
+ else
+ prefix_len = evt_prefixes[i].prefix_len;
+
+ if (!prefix || prefix_len == 0)
+ continue;
+
+ /* Compare the raw prefix data directly. */
+ if (!memcmp(prefix, skb->data, prefix_len)) {
+ evt_prefixes[i].vendor_func(hdev, data, skb);
+ break;
+ }
+ }
+}
+
static void hci_mode_change_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
@@ -6811,7 +6905,7 @@ static const struct hci_ev {
HCI_EV(HCI_EV_NUM_COMP_BLOCKS, hci_num_comp_blocks_evt,
sizeof(struct hci_ev_num_comp_blocks)),
/* [0xff = HCI_EV_VENDOR] */
- HCI_EV(HCI_EV_VENDOR, msft_vendor_evt, 0),
+ HCI_EV(HCI_EV_VENDOR, hci_vendor_evt, 0),
};

static void hci_event_func(struct hci_dev *hdev, u8 event, struct sk_buff *skb,
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 08d6494f1b34..5388018cd738 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -4389,6 +4389,25 @@ static int set_exp_feature(struct sock *sk, struct hci_dev *hdev,
MGMT_STATUS_NOT_SUPPORTED);
}

+int mgmt_quality_report(struct hci_dev *hdev, void *data, u32 data_len,
+ u8 quality_spec)
+{
+ struct mgmt_ev_quality_report *ev;
+ struct sk_buff *skb;
+
+ skb = mgmt_alloc_skb(hdev, MGMT_EV_QUALITY_REPORT,
+ sizeof(*ev) + data_len);
+ if (!skb)
+ return -ENOMEM;
+
+ ev = skb_put(skb, sizeof(*ev));
+ ev->quality_spec = quality_spec;
+ ev->data_len = data_len;
+ skb_put_data(skb, data, data_len);
+
+ return mgmt_event_skb(skb, NULL);
+}
+
static int get_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len)
{
diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index 484540855863..92fd7fca5889 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -729,6 +729,20 @@ static void msft_monitor_device_evt(struct hci_dev *hdev, struct sk_buff *skb)
handle_data->mgmt_handle);
}

+__u8 *get_msft_evt_prefix(struct hci_dev *hdev)
+{
+ struct msft_data *msft = hdev->msft_data;
+
+ return msft->evt_prefix;
+}
+
+__u8 get_msft_evt_prefix_len(struct hci_dev *hdev)
+{
+ struct msft_data *msft = hdev->msft_data;
+
+ return msft->evt_prefix_len;
+}
+
void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb)
{
struct msft_data *msft = hdev->msft_data;
diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h
index afcaf7d3b1cb..a354ebf61fed 100644
--- a/net/bluetooth/msft.h
+++ b/net/bluetooth/msft.h
@@ -27,6 +27,8 @@ int msft_set_filter_enable(struct hci_dev *hdev, bool enable);
int msft_suspend_sync(struct hci_dev *hdev);
int msft_resume_sync(struct hci_dev *hdev);
bool msft_curve_validity(struct hci_dev *hdev);
+__u8 *get_msft_evt_prefix(struct hci_dev *hdev);
+__u8 get_msft_evt_prefix_len(struct hci_dev *hdev);

#else

@@ -77,4 +79,14 @@ static inline bool msft_curve_validity(struct hci_dev *hdev)
return false;
}

+static inline __u8 *get_msft_evt_prefix(struct hci_dev *hdev)
+{
+ return NULL;
+}
+
+static inline __u8 get_msft_evt_prefix_len(struct hci_dev *hdev)
+{
+ return 0;
+}
+
#endif
--
2.35.0.rc0.227.g00780c9af4-goog


2022-01-27 17:56:42

by Joseph Hwang

[permalink] [raw]
Subject: [PATCH v2 2/2] Bluetooth: btintel: surface Intel telemetry events through mgmt

When receiving a HCI vendor event, the kernel checks if it is an
Intel telemetry event. If yes, the event is sent to bluez user
space through the mgmt socket.

Signed-off-by: Joseph Hwang <[email protected]>
Reviewed-by: Archie Pusaka <[email protected]>
---

Changes in v2:
- Drop the pull_quality_report_data function from hci_dev.
Do not bother hci_dev with it. Do not bleed the details
into the core.

drivers/bluetooth/btintel.c | 27 ++++++++++++++++++++++++++-
drivers/bluetooth/btintel.h | 7 +++++++
include/net/bluetooth/hci_core.h | 1 +
net/bluetooth/hci_event.c | 12 ++++++++++++
4 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 1a4f8b227eac..9e1fdb68b669 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -2401,8 +2401,9 @@ static int btintel_setup_combined(struct hci_dev *hdev)
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);

- /* Set up the quality report callback for Intel devices */
+ /* Set up the quality report callbacks for Intel devices */
hdev->set_quality_report = btintel_set_quality_report;
+ hdev->is_quality_report_evt = btintel_is_quality_report_evt;

/* For Legacy device, check the HW platform value and size */
if (skb->len == sizeof(ver) && skb->data[1] == 0x37) {
@@ -2645,6 +2646,30 @@ void btintel_secure_send_result(struct hci_dev *hdev,
}
EXPORT_SYMBOL_GPL(btintel_secure_send_result);

+#define INTEL_PREFIX 0x8087
+#define TELEMETRY_CODE 0x03
+
+struct intel_prefix_evt_data {
+ __le16 vendor_prefix;
+ __u8 code;
+ __u8 data[]; /* a number of struct intel_tlv subevents */
+} __packed;
+
+bool btintel_is_quality_report_evt(struct sk_buff *skb)
+{
+ struct intel_prefix_evt_data *ev;
+ u16 vendor_prefix;
+
+ if (skb->len < sizeof(struct intel_prefix_evt_data))
+ return false;
+
+ ev = (struct intel_prefix_evt_data *)skb->data;
+ vendor_prefix = __le16_to_cpu(ev->vendor_prefix);
+
+ return vendor_prefix == INTEL_PREFIX && ev->code == TELEMETRY_CODE;
+}
+EXPORT_SYMBOL_GPL(btintel_is_quality_report_evt);
+
MODULE_AUTHOR("Marcel Holtmann <[email protected]>");
MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION);
MODULE_VERSION(VERSION);
diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h
index c9b24e9299e2..6dd4695b8b86 100644
--- a/drivers/bluetooth/btintel.h
+++ b/drivers/bluetooth/btintel.h
@@ -210,6 +210,7 @@ void btintel_bootup(struct hci_dev *hdev, const void *ptr, unsigned int len);
void btintel_secure_send_result(struct hci_dev *hdev,
const void *ptr, unsigned int len);
int btintel_set_quality_report(struct hci_dev *hdev, bool enable);
+bool btintel_is_quality_report_evt(struct sk_buff *skb);
#else

static inline int btintel_check_bdaddr(struct hci_dev *hdev)
@@ -305,4 +306,10 @@ static inline int btintel_set_quality_report(struct hci_dev *hdev, bool enable)
{
return -ENODEV;
}
+
+static inline bool btintel_is_quality_report_evt(struct sk_buff *skb)
+{
+ return false;
+}
+
#endif
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index b726fd595895..9d855ac1cb29 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -632,6 +632,7 @@ struct hci_dev {
void (*cmd_timeout)(struct hci_dev *hdev);
bool (*wakeup)(struct hci_dev *hdev);
int (*set_quality_report)(struct hci_dev *hdev, bool enable);
+ bool (*is_quality_report_evt)(struct sk_buff *skb);
int (*get_data_path_id)(struct hci_dev *hdev, __u8 *data_path);
int (*get_codec_config_data)(struct hci_dev *hdev, __u8 type,
struct bt_codec *codec, __u8 *vnd_len,
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 1b69d3efd415..892a48d2f6be 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -4238,6 +4238,16 @@ static void aosp_quality_report_evt(struct hci_dev *hdev, void *data,
QUALITY_SPEC_AOSP_BQR);
}

+static void intel_vendor_evt(struct hci_dev *hdev, void *data,
+ struct sk_buff *skb)
+{
+ /* Only interested in the telemetry event for now. */
+ if (hdev->set_quality_report &&
+ hdev->is_quality_report_evt && hdev->is_quality_report_evt(skb))
+ mgmt_quality_report(hdev, skb->data, skb->len,
+ QUALITY_SPEC_INTEL_TELEMETRY);
+}
+
/* Define the fixed vendor event prefixes below.
* Note: AOSP HCI Requirements use 0x54 and up as sub-event codes without
* actually defining a vendor prefix. Refer to
@@ -4246,6 +4256,7 @@ static void aosp_quality_report_evt(struct hci_dev *hdev, void *data,
* space to avoid collision.
*/
static unsigned char AOSP_BQR_PREFIX[] = { 0x58 };
+static unsigned char INTEL_PREFIX[] = { 0x87, 0x80 };

/* Some vendor prefixes are fixed values and lengths. */
#define FIXED_EVT_PREFIX(_prefix, _vendor_func) \
@@ -4283,6 +4294,7 @@ struct vendor_event_prefix {
__u8 (*get_prefix_len)(struct hci_dev *hdev);
} evt_prefixes[] = {
FIXED_EVT_PREFIX(AOSP_BQR_PREFIX, aosp_quality_report_evt),
+ FIXED_EVT_PREFIX(INTEL_PREFIX, intel_vendor_evt),
DYNAMIC_EVT_PREFIX(get_msft_evt_prefix, get_msft_evt_prefix_len,
msft_vendor_evt),

--
2.35.0.rc0.227.g00780c9af4-goog

2022-01-28 17:20:20

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] Bluetooth: btintel: surface Intel telemetry events through mgmt

Hi Jospeh,

> When receiving a HCI vendor event, the kernel checks if it is an
> Intel telemetry event. If yes, the event is sent to bluez user
> space through the mgmt socket.
>
> Signed-off-by: Joseph Hwang <[email protected]>
> Reviewed-by: Archie Pusaka <[email protected]>
> ---
>
> Changes in v2:
> - Drop the pull_quality_report_data function from hci_dev.
> Do not bother hci_dev with it. Do not bleed the details
> into the core.
>
> drivers/bluetooth/btintel.c | 27 ++++++++++++++++++++++++++-
> drivers/bluetooth/btintel.h | 7 +++++++
> include/net/bluetooth/hci_core.h | 1 +
> net/bluetooth/hci_event.c | 12 ++++++++++++
> 4 files changed, 46 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
> index 1a4f8b227eac..9e1fdb68b669 100644
> --- a/drivers/bluetooth/btintel.c
> +++ b/drivers/bluetooth/btintel.c
> @@ -2401,8 +2401,9 @@ static int btintel_setup_combined(struct hci_dev *hdev)
> set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
> set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
>
> - /* Set up the quality report callback for Intel devices */
> + /* Set up the quality report callbacks for Intel devices */
> hdev->set_quality_report = btintel_set_quality_report;
> + hdev->is_quality_report_evt = btintel_is_quality_report_evt;
>
> /* For Legacy device, check the HW platform value and size */
> if (skb->len == sizeof(ver) && skb->data[1] == 0x37) {
> @@ -2645,6 +2646,30 @@ void btintel_secure_send_result(struct hci_dev *hdev,
> }
> EXPORT_SYMBOL_GPL(btintel_secure_send_result);
>
> +#define INTEL_PREFIX 0x8087
> +#define TELEMETRY_CODE 0x03
> +
> +struct intel_prefix_evt_data {
> + __le16 vendor_prefix;
> + __u8 code;
> + __u8 data[]; /* a number of struct intel_tlv subevents */
> +} __packed;
> +
> +bool btintel_is_quality_report_evt(struct sk_buff *skb)
> +{
> + struct intel_prefix_evt_data *ev;
> + u16 vendor_prefix;
> +
> + if (skb->len < sizeof(struct intel_prefix_evt_data))
> + return false;
> +
> + ev = (struct intel_prefix_evt_data *)skb->data;
> + vendor_prefix = __le16_to_cpu(ev->vendor_prefix);
> +
> + return vendor_prefix == INTEL_PREFIX && ev->code == TELEMETRY_CODE;
> +}
> +EXPORT_SYMBOL_GPL(btintel_is_quality_report_evt);
> +
> MODULE_AUTHOR("Marcel Holtmann <[email protected]>");
> MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION);
> MODULE_VERSION(VERSION);
> diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h
> index c9b24e9299e2..6dd4695b8b86 100644
> --- a/drivers/bluetooth/btintel.h
> +++ b/drivers/bluetooth/btintel.h
> @@ -210,6 +210,7 @@ void btintel_bootup(struct hci_dev *hdev, const void *ptr, unsigned int len);
> void btintel_secure_send_result(struct hci_dev *hdev,
> const void *ptr, unsigned int len);
> int btintel_set_quality_report(struct hci_dev *hdev, bool enable);
> +bool btintel_is_quality_report_evt(struct sk_buff *skb);
> #else
>
> static inline int btintel_check_bdaddr(struct hci_dev *hdev)
> @@ -305,4 +306,10 @@ static inline int btintel_set_quality_report(struct hci_dev *hdev, bool enable)
> {
> return -ENODEV;
> }
> +
> +static inline bool btintel_is_quality_report_evt(struct sk_buff *skb)
> +{
> + return false;
> +}
> +
> #endif
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index b726fd595895..9d855ac1cb29 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -632,6 +632,7 @@ struct hci_dev {
> void (*cmd_timeout)(struct hci_dev *hdev);
> bool (*wakeup)(struct hci_dev *hdev);
> int (*set_quality_report)(struct hci_dev *hdev, bool enable);
> + bool (*is_quality_report_evt)(struct sk_buff *skb);
> int (*get_data_path_id)(struct hci_dev *hdev, __u8 *data_path);
> int (*get_codec_config_data)(struct hci_dev *hdev, __u8 type,
> struct bt_codec *codec, __u8 *vnd_len,
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index 1b69d3efd415..892a48d2f6be 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -4238,6 +4238,16 @@ static void aosp_quality_report_evt(struct hci_dev *hdev, void *data,
> QUALITY_SPEC_AOSP_BQR);
> }
>
> +static void intel_vendor_evt(struct hci_dev *hdev, void *data,
> + struct sk_buff *skb)
> +{
> + /* Only interested in the telemetry event for now. */
> + if (hdev->set_quality_report &&
> + hdev->is_quality_report_evt && hdev->is_quality_report_evt(skb))
> + mgmt_quality_report(hdev, skb->data, skb->len,
> + QUALITY_SPEC_INTEL_TELEMETRY);
> +}
> +

this is not workable like this. Intel specific stuff has to stay out of net/bluetooth/. Frankly I am also confused why this is this way in the first place.

So if a driver sets aosp_capable, then we can check the AOSP range and hand it to net/bluetooth/aosp.c for further processing. For the MSFT extensions, we can already map them accordingly due to the event prefix. And everything other event has to go to the driver as raw event to do whatever it wants with it.

Regards

Marcel