| From 654781e3b0fc5dd5d417b7495230475d3d99ef9a Mon Sep 17 00:00:00 2001 |
| From: Ying Hsu <yinghsu@chromium.org> |
| Date: Thu, 21 Mar 2024 05:58:15 +0000 |
| Subject: [PATCH] FROMLIST: Bluetooth: Add vendor-specific packet |
| classification for ISO data |
| |
| When HCI raw sockets are opened, the Bluetooth kernel module doesn't |
| track CIS/BIS connections. User-space applications have to identify |
| ISO data by maintaining connection information and look up the mapping |
| for each ACL data packet received. Besides, btsnoop log captured in |
| kernel couldn't tell ISO data from ACL data in this case. |
| |
| To avoid additional lookups, this patch introduces vendor-specific |
| packet classification for Intel BT controllers to distinguish |
| ISO data packets from ACL data packets. |
| |
| (am from https://patchwork.kernel.org/project/bluetooth/patch/20240529080123.2146946-1-yinghsu@chromium.org/) |
| |
| BUG=b:327542945 |
| BUG=b:343096662 |
| UPSTREAM-TASK=b:342515326 |
| TEST=LE audio unicast recording on a ChromeOS device with Intel AX211 |
| TEST=LE keyboard and A2DP on brya |
| |
| Change-Id: Iec7d6355d82b2408b13259b7f2d4c36386455e61 |
| Signed-off-by: Ying Hsu <yinghsu@chromium.org> |
| Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/5579902 |
| Reviewed-by: Sean Paul <sean@poorly.run> |
| Reviewed-by: Archie Pusaka <apusaka@chromium.org> |
| --- |
| drivers/bluetooth/btintel.c | 25 +++++++++++++++++++++++-- |
| include/net/bluetooth/hci_core.h | 1 + |
| net/bluetooth/hci_core.c | 16 ++++++++++++++++ |
| 3 files changed, 40 insertions(+), 2 deletions(-) |
| |
| diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c |
| index 0923c996f738d22e0ed0d56c2d3a9717aa8476be..7f071daedae859c7744a32e3d4b014b5833e2e26 100644 |
| --- a/drivers/bluetooth/btintel.c |
| +++ b/drivers/bluetooth/btintel.c |
| @@ -2644,6 +2644,24 @@ static void btintel_set_dsm_reset_method(struct hci_dev *hdev, |
| data->acpi_reset_method = btintel_acpi_reset_method; |
| } |
| |
| +#define BTINTEL_ISODATA_HANDLE_BASE 0x900 |
| + |
| +static u8 btintel_classify_pkt_type(struct hci_dev *hdev, struct sk_buff *skb) |
| +{ |
| + /* |
| + * Distinguish ISO data packets form ACL data packets |
| + * based on their connection handle value range. |
| + */ |
| + if (hci_skb_pkt_type(skb) == HCI_ACLDATA_PKT) { |
| + __u16 handle = __le16_to_cpu(hci_acl_hdr(skb)->handle); |
| + |
| + if (hci_handle(handle) >= BTINTEL_ISODATA_HANDLE_BASE) |
| + return HCI_ISODATA_PKT; |
| + } |
| + |
| + return hci_skb_pkt_type(skb); |
| +} |
| + |
| int btintel_bootloader_setup_tlv(struct hci_dev *hdev, |
| struct intel_version_tlv *ver) |
| { |
| @@ -3091,11 +3109,14 @@ static int btintel_setup_combined(struct hci_dev *hdev) |
| err = btintel_bootloader_setup(hdev, &ver); |
| btintel_register_devcoredump_support(hdev); |
| break; |
| + case 0x18: /* GfP2 */ |
| + case 0x1c: /* GaP */ |
| + /* Re-classify packet type for controllers with LE audio */ |
| + hdev->classify_pkt_type = btintel_classify_pkt_type; |
| + fallthrough; |
| case 0x17: |
| - case 0x18: |
| case 0x19: |
| case 0x1b: |
| - case 0x1c: |
| case 0x1e: |
| /* Display version information of TLV type */ |
| btintel_version_info_tlv(hdev, &ver_tlv); |
| diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h |
| index 5c5d394935b54dffe03ac8af286a71f85110f4c9..fa09c5e21d53b3de019f3f21c78001754b61c8a0 100644 |
| --- a/include/net/bluetooth/hci_core.h |
| +++ b/include/net/bluetooth/hci_core.h |
| @@ -655,6 +655,7 @@ struct hci_dev { |
| bool (*is_quality_report_evt)(struct sk_buff *skb); |
| bool (*pull_quality_report_data)(struct sk_buff *skb); |
| void (*do_wakeup)(struct hci_dev *hdev); |
| + u8 (*classify_pkt_type)(struct hci_dev *hdev, struct sk_buff *skb); |
| }; |
| |
| #define HCI_PHY_HANDLE(handle) (handle & 0xff) |
| diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c |
| index 60f067802a8788df2fba54f841a167927f9ca3d7..564e2f2c209357d55959ad79e43717da6d3b1ae1 100644 |
| --- a/net/bluetooth/hci_core.c |
| +++ b/net/bluetooth/hci_core.c |
| @@ -2954,15 +2954,31 @@ int hci_reset_dev(struct hci_dev *hdev) |
| } |
| EXPORT_SYMBOL(hci_reset_dev); |
| |
| +static u8 hci_dev_classify_pkt_type(struct hci_dev *hdev, struct sk_buff *skb) |
| +{ |
| + if (hdev->classify_pkt_type) |
| + return hdev->classify_pkt_type(hdev, skb); |
| + |
| + return hci_skb_pkt_type(skb); |
| +} |
| + |
| /* Receive frame from HCI drivers */ |
| int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb) |
| { |
| + u8 dev_pkt_type; |
| + |
| if (!hdev || (!test_bit(HCI_UP, &hdev->flags) |
| && !test_bit(HCI_INIT, &hdev->flags))) { |
| kfree_skb(skb); |
| return -ENXIO; |
| } |
| |
| + /* Check if the driver agree with packet type classification */ |
| + dev_pkt_type = hci_dev_classify_pkt_type(hdev, skb); |
| + if (hci_skb_pkt_type(skb) != dev_pkt_type) { |
| + hci_skb_pkt_type(skb) = dev_pkt_type; |
| + } |
| + |
| switch (hci_skb_pkt_type(skb)) { |
| case HCI_EVENT_PKT: |
| break; |
| -- |
| 2.45.2.627.g7a2c4fd464-goog |
| |