]> git.ipfire.org Git - thirdparty/kernel/stable.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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 24 Nov 2025 09:37:30 +0000 (10:37 +0100)
[ Upstream commit 485e0626e58768f3c53ba61ab9e09d6b60a455f4 ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
include/net/bluetooth/hci.h
net/bluetooth/hci_event.c

index dca650cede3c4781b1cbe6b7cf67c9a46e25433e..63160cfcf2b22e9935a5ad18e21da4855206a766 100644 (file)
@@ -2782,6 +2782,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 0380d2f596c973298f7598799c75fae5675f40f4..a9a5d12943fa0515ee94ade382a9ee6feb84c9fa 100644 (file)
@@ -5853,6 +5853,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)
 {
@@ -7056,29 +7079,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);
@@ -7192,6 +7210,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)),