blob: fe7149f6af46c623a0db50280ce8f084b8ec0ebf [file] [log] [blame]
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