]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
Bluetooth: hci_conn: Fix not cleaning up PA_LINK connections
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Tue, 4 Nov 2025 22:02:04 +0000 (17:02 -0500)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Mon, 10 Nov 2025 21:09:00 +0000 (16:09 -0500)
Contrary to what was stated on d36349ea73d8 ("Bluetooth: hci_conn:
Fix running bis_cleanup for hci_conn->type PA_LINK") the PA_LINK does
in fact needs to run bis_cleanup in order to terminate the PA Sync,
since that is bond to the listening socket which is the entity that
controls the lifetime of PA Sync, so if it is closed/released the PA
Sync shall be terminated, terminating the PA Sync shall not result in
the BIG Sync being terminated since once the later is established it
doesn't depend on the former anymore.

If the use user wants to reconnect/rebind a number of BIS(s) it shall
keep the socket open until it no longer needs the PA Sync, which means
it retains full control of the lifetime of both PA and BIG Syncs.

Fixes: d36349ea73d8 ("Bluetooth: hci_conn: Fix running bis_cleanup for hci_conn->type PA_LINK")
Fixes: a7bcffc673de ("Bluetooth: Add PA_LINK to distinguish BIG sync and PA sync connections")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
net/bluetooth/hci_conn.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sync.c

index c5dedf39a1293f3cf20b1120e41318d9a701e322..6fc0692abf0576889b4f28b2522b6582e8ba331b 100644 (file)
@@ -769,21 +769,23 @@ static void find_bis(struct hci_conn *conn, void *data)
        d->count++;
 }
 
-static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *conn)
+static int hci_le_big_terminate(struct hci_dev *hdev, struct hci_conn *conn)
 {
        struct iso_list_data *d;
        int ret;
 
-       bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", big, conn->sync_handle);
+       bt_dev_dbg(hdev, "hcon %p big 0x%2.2x sync_handle 0x%4.4x", conn,
+                  conn->iso_qos.bcast.big, conn->sync_handle);
 
        d = kzalloc(sizeof(*d), GFP_KERNEL);
        if (!d)
                return -ENOMEM;
 
-       d->big = big;
+       d->big = conn->iso_qos.bcast.big;
        d->sync_handle = conn->sync_handle;
 
-       if (test_and_clear_bit(HCI_CONN_PA_SYNC, &conn->flags)) {
+       if (conn->type == PA_LINK &&
+           test_and_clear_bit(HCI_CONN_PA_SYNC, &conn->flags)) {
                hci_conn_hash_list_flag(hdev, find_bis, PA_LINK,
                                        HCI_CONN_PA_SYNC, d);
 
@@ -801,6 +803,9 @@ static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *c
                        d->big_sync_term = true;
        }
 
+       if (!d->pa_sync_term && !d->big_sync_term)
+               return 0;
+
        ret = hci_cmd_sync_queue(hdev, big_terminate_sync, d,
                                 terminate_big_destroy);
        if (ret)
@@ -852,8 +857,7 @@ static void bis_cleanup(struct hci_conn *conn)
 
                hci_le_terminate_big(hdev, conn);
        } else {
-               hci_le_big_terminate(hdev, conn->iso_qos.bcast.big,
-                                    conn);
+               hci_le_big_terminate(hdev, conn);
        }
 }
 
@@ -994,19 +998,20 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t
                conn->mtu = hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu;
                break;
        case CIS_LINK:
-       case BIS_LINK:
-       case PA_LINK:
                /* conn->src should reflect the local identity address */
                hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
 
-               /* set proper cleanup function */
-               if (!bacmp(dst, BDADDR_ANY))
-                       conn->cleanup = bis_cleanup;
-               else if (conn->role == HCI_ROLE_MASTER)
+               if (conn->role == HCI_ROLE_MASTER)
                        conn->cleanup = cis_cleanup;
 
-               conn->mtu = hdev->iso_mtu ? hdev->iso_mtu :
-                           hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu;
+               conn->mtu = hdev->iso_mtu;
+               break;
+       case PA_LINK:
+       case BIS_LINK:
+               /* conn->src should reflect the local identity address */
+               hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
+               conn->cleanup = bis_cleanup;
+               conn->mtu = hdev->iso_mtu;
                break;
        case SCO_LINK:
                if (lmp_esco_capable(hdev))
index f20c826509b6fe0d52375bae4e6b17459981fff6..03328c1dd0906624857c21508641ca498b823b8f 100644 (file)
@@ -7001,14 +7001,9 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
                                continue;
                }
 
-               if (ev->status != 0x42) {
+               if (ev->status != 0x42)
                        /* Mark PA sync as established */
                        set_bit(HCI_CONN_PA_SYNC, &bis->flags);
-                       /* Reset cleanup callback of PA Sync so it doesn't
-                        * terminate the sync when deleting the connection.
-                        */
-                       conn->cleanup = NULL;
-               }
 
                bis->sync_handle = conn->sync_handle;
                bis->iso_qos.bcast.big = ev->handle;
index 73fc41b68b6870ac54e8a7e1a70d203137b47239..6e76798ec786b1bd0844971eb24d2e1242373601 100644 (file)
@@ -6999,7 +6999,7 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
 
        hci_dev_lock(hdev);
 
-       if (!hci_conn_valid(hdev, conn))
+       if (hci_conn_valid(hdev, conn))
                clear_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags);
 
        if (!err)