]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
Bluetooth: hci_event: Fix not handling PA Sync Lost event
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thu, 6 Nov 2025 18:05:35 +0000 (13:05 -0500)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Tue, 11 Nov 2025 13:55:18 +0000 (08:55 -0500)
This handles PA Sync Lost event which previously was assumed to be
handled with BIG Sync Lost but their lifetime are not the same thus why
there are 2 different events to inform when each sync is lost.

Fixes: b2a5f2e1c127 ("Bluetooth: hci_event: Add support for handling LE BIG Sync Lost event")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
include/net/bluetooth/hci.h
net/bluetooth/hci_event.c

index 8d0e703bc929e870ef15d1c385e62474fe2f7895..cb4c02d0075904119627c1f4d8195b37c536fad5 100644 (file)
@@ -2783,6 +2783,11 @@ struct hci_ev_le_per_adv_report {
        __u8     data[];
 } __packed;
 
+#define HCI_EV_LE_PA_SYNC_LOST         0x10
+struct hci_ev_le_pa_sync_lost {
+       __le16 handle;
+} __packed;
+
 #define LE_PA_DATA_COMPLETE    0x00
 #define LE_PA_DATA_MORE_TO_COME        0x01
 #define LE_PA_DATA_TRUNCATED   0x02
index 03328c1dd0906624857c21508641ca498b823b8f..3838b90343d910bbb0f695c995f6e5a19ac78467 100644 (file)
@@ -5843,6 +5843,29 @@ static void hci_le_enh_conn_complete_evt(struct hci_dev *hdev, void *data,
                             le16_to_cpu(ev->supervision_timeout));
 }
 
+static void hci_le_pa_sync_lost_evt(struct hci_dev *hdev, void *data,
+                                   struct sk_buff *skb)
+{
+       struct hci_ev_le_pa_sync_lost *ev = data;
+       u16 handle = le16_to_cpu(ev->handle);
+       struct hci_conn *conn;
+
+       bt_dev_dbg(hdev, "sync handle 0x%4.4x", handle);
+
+       hci_dev_lock(hdev);
+
+       /* Delete the pa sync connection */
+       conn = hci_conn_hash_lookup_pa_sync_handle(hdev, handle);
+       if (conn) {
+               clear_bit(HCI_CONN_BIG_SYNC, &conn->flags);
+               clear_bit(HCI_CONN_PA_SYNC, &conn->flags);
+               hci_disconn_cfm(conn, HCI_ERROR_REMOTE_USER_TERM);
+               hci_conn_del(conn);
+       }
+
+       hci_dev_unlock(hdev);
+}
+
 static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, void *data,
                                    struct sk_buff *skb)
 {
@@ -7046,29 +7069,24 @@ static void hci_le_big_sync_lost_evt(struct hci_dev *hdev, void *data,
                                     struct sk_buff *skb)
 {
        struct hci_evt_le_big_sync_lost *ev = data;
-       struct hci_conn *bis, *conn;
-       bool mgmt_conn;
+       struct hci_conn *bis;
+       bool mgmt_conn = false;
 
        bt_dev_dbg(hdev, "big handle 0x%2.2x", ev->handle);
 
        hci_dev_lock(hdev);
 
-       /* Delete the pa sync connection */
-       bis = hci_conn_hash_lookup_pa_sync_big_handle(hdev, ev->handle);
-       if (bis) {
-               conn = hci_conn_hash_lookup_pa_sync_handle(hdev,
-                                                          bis->sync_handle);
-               if (conn)
-                       hci_conn_del(conn);
-       }
-
        /* Delete each bis connection */
        while ((bis = hci_conn_hash_lookup_big_state(hdev, ev->handle,
                                                     BT_CONNECTED,
                                                     HCI_ROLE_SLAVE))) {
-               mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &bis->flags);
-               mgmt_device_disconnected(hdev, &bis->dst, bis->type, bis->dst_type,
-                                        ev->reason, mgmt_conn);
+               if (!mgmt_conn) {
+                       mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED,
+                                                      &bis->flags);
+                       mgmt_device_disconnected(hdev, &bis->dst, bis->type,
+                                                bis->dst_type, ev->reason,
+                                                mgmt_conn);
+               }
 
                clear_bit(HCI_CONN_BIG_SYNC, &bis->flags);
                hci_disconn_cfm(bis, ev->reason);
@@ -7182,6 +7200,9 @@ static const struct hci_le_ev {
                                 hci_le_per_adv_report_evt,
                                 sizeof(struct hci_ev_le_per_adv_report),
                                 HCI_MAX_EVENT_SIZE),
+       /* [0x10 = HCI_EV_LE_PA_SYNC_LOST] */
+       HCI_LE_EV(HCI_EV_LE_PA_SYNC_LOST, hci_le_pa_sync_lost_evt,
+                 sizeof(struct hci_ev_le_pa_sync_lost)),
        /* [0x12 = HCI_EV_LE_EXT_ADV_SET_TERM] */
        HCI_LE_EV(HCI_EV_LE_EXT_ADV_SET_TERM, hci_le_ext_adv_term_evt,
                  sizeof(struct hci_evt_le_ext_adv_set_term)),