]> www.infradead.org Git - nvme.git/commitdiff
Bluetooth: Add vendor-specific packet classification for ISO data
authorYing Hsu <yinghsu@chromium.org>
Wed, 29 May 2024 08:00:00 +0000 (08:00 +0000)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Mon, 15 Jul 2024 01:34:32 +0000 (21:34 -0400)
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.

Signed-off-by: Ying Hsu <yinghsu@chromium.org>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
drivers/bluetooth/btintel.c
include/net/bluetooth/hci_core.h
net/bluetooth/hci_core.c

index 27e03951e68b6a8fa0ef545abb45004d8c0f9bbb..ff33e1aa29298d54a712e59ec874ae4cfe5bae72 100644 (file)
@@ -2549,6 +2549,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)
 {
@@ -2989,11 +3007,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);
index c43716edf2056607936181319e527ada210597dc..f7de2681d457e8b606937feeae43fd47ca630aa0 100644 (file)
@@ -649,6 +649,7 @@ struct hci_dev {
        int (*get_codec_config_data)(struct hci_dev *hdev, __u8 type,
                                     struct bt_codec *codec, __u8 *vnd_len,
                                     __u8 **vnd_data);
+       u8 (*classify_pkt_type)(struct hci_dev *hdev, struct sk_buff *skb);
 };
 
 #define HCI_PHY_HANDLE(handle) (handle & 0xff)
index 55bdc365916fdc73a03b8f400158476e196221bf..144e85ebfbdbc8de8c5b043dfcdcc081043a62e8 100644 (file)
@@ -2909,15 +2909,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;