]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Bluetooth: hci_core: Detect if an ISO link has stalled
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 13 Aug 2025 19:57:39 +0000 (15:57 -0400)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Sat, 27 Sep 2025 15:37:01 +0000 (11:37 -0400)
This attempts to detect if an ISO link has been waiting for an ISO
buffer for longer than the maximum allowed transport latency then
proceed to use hci_link_tx_to which prints an error and disconnects.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
net/bluetooth/hci_core.c

index df1847b74e55e96567cb09582a84f2569a6e5044..9ecc70baaca97a9748a4b2f36aa8de2ce30b4978 100644 (file)
@@ -488,6 +488,7 @@ enum {
 #define HCI_AUTO_OFF_TIMEOUT   msecs_to_jiffies(2000)  /* 2 seconds */
 #define HCI_ACL_CONN_TIMEOUT   msecs_to_jiffies(20000) /* 20 seconds */
 #define HCI_LE_CONN_TIMEOUT    msecs_to_jiffies(20000) /* 20 seconds */
+#define HCI_ISO_TX_TIMEOUT     usecs_to_jiffies(0x7fffff) /* 8388607 usecs */
 
 /* HCI data types */
 #define HCI_COMMAND_PKT                0x01
index a068beae93186955e8277cc7612a1de896d55d86..2924c2bf2a983d4ae241a9489edeb8629db02f6f 100644 (file)
@@ -487,6 +487,7 @@ struct hci_dev {
 
        unsigned long   acl_last_tx;
        unsigned long   le_last_tx;
+       unsigned long   iso_last_tx;
 
        __u8            le_tx_def_phys;
        __u8            le_rx_def_phys;
index e2bffad9816f1288cf1b08f98989cdc3fb34dadd..4cf4bb1187dc326ba6b02a7240705653e744963b 100644 (file)
@@ -3585,24 +3585,37 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
 
 static void __check_timeout(struct hci_dev *hdev, unsigned int cnt, u8 type)
 {
-       unsigned long last_tx;
+       unsigned long timeout;
 
        if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
                return;
 
        switch (type) {
+       case ACL_LINK:
+               /* tx timeout must be longer than maximum link supervision
+                * timeout (40.9 seconds)
+                */
+               timeout = hdev->acl_last_tx + HCI_ACL_TX_TIMEOUT;
+               break;
        case LE_LINK:
-               last_tx = hdev->le_last_tx;
+               /* tx timeout must be longer than maximum link supervision
+                * timeout (40.9 seconds)
+                */
+               timeout = hdev->le_last_tx + HCI_ACL_TX_TIMEOUT;
                break;
-       default:
-               last_tx = hdev->acl_last_tx;
+       case CIS_LINK:
+       case BIS_LINK:
+       case PA_LINK:
+               /* tx timeout must be longer than the maximum transport latency
+                * (8.388607 seconds)
+                */
+               timeout = hdev->iso_last_tx + HCI_ISO_TX_TIMEOUT;
                break;
+       default:
+               return;
        }
 
-       /* tx timeout must be longer than maximum link supervision timeout
-        * (40.9 seconds)
-        */
-       if (!cnt && time_after(jiffies, last_tx + HCI_ACL_TX_TIMEOUT))
+       if (!cnt && time_after(jiffies, timeout))
                hci_link_tx_to(hdev, type);
 }
 
@@ -3759,10 +3772,15 @@ static void hci_sched_iso(struct hci_dev *hdev, __u8 type)
                return;
 
        cnt = &hdev->iso_cnt;
+
+       __check_timeout(hdev, *cnt, type);
+
        while (*cnt && (conn = hci_low_sent(hdev, type, &quote))) {
                while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
                        BT_DBG("skb %p len %d", skb, skb->len);
+
                        hci_send_conn_frame(hdev, conn, skb);
+                       hdev->iso_last_tx = jiffies;
 
                        conn->sent++;
                        if (conn->sent == ~0)