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

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

index c021c6cb3d9a5ec75766d2753c9433facc9b9f86..5846b4bae77a368e47dcf3f914bd5bdd25317706 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);
        }
 }
 
@@ -995,19 +999,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 7ee8bc7ac5a2a27cd77c1eca02ba367b1c93f4f6..0380d2f596c973298f7598799c75fae5675f40f4 100644 (file)
@@ -7011,14 +7011,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)