]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Bluetooth: ISO: Send BIG Create Sync via hci_sync
authorIulia Tanasescu <iulia.tanasescu@nxp.com>
Mon, 11 Nov 2024 11:47:08 +0000 (13:47 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Dec 2024 12:53:27 +0000 (13:53 +0100)
[ Upstream commit 07a9342b94a91b306ed1cf6aa8254aea210764c9 ]

Before issuing the LE BIG Create Sync command, an available BIG handle
is chosen by iterating through the conn_hash list and finding the first
unused value.

If a BIG is terminated, the associated hcons are removed from the list
and the LE BIG Terminate Sync command is sent via hci_sync queue.
However, a new LE BIG Create sync command might be issued via
hci_send_cmd, before the previous BIG sync was terminated. This
can cause the same BIG handle to be reused and the LE BIG Create Sync
to fail with Command Disallowed.

< HCI Command: LE Broadcast Isochronous Group Create Sync (0x08|0x006b)
        BIG Handle: 0x00
        BIG Sync Handle: 0x0002
        Encryption: Unencrypted (0x00)
        Broadcast Code[16]: 00000000000000000000000000000000
        Maximum Number Subevents: 0x00
        Timeout: 20000 ms (0x07d0)
        Number of BIS: 1
        BIS ID: 0x01
> HCI Event: Command Status (0x0f) plen 4
      LE Broadcast Isochronous Group Create Sync (0x08|0x006b) ncmd 1
        Status: Command Disallowed (0x0c)
< HCI Command: LE Broadcast Isochronous Group Terminate Sync (0x08|0x006c)
        BIG Handle: 0x00

This commit fixes the ordering of the LE BIG Create Sync/LE BIG Terminate
Sync commands, to make sure that either the previous BIG sync is
terminated before reusing the handle, or that a new handle is chosen
for a new sync.

Fixes: eca0ae4aea66 ("Bluetooth: Add initial implementation of BIS connections")
Signed-off-by: Iulia Tanasescu <iulia.tanasescu@nxp.com>
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/iso.c

index b2bb14055a75922a49472cd74c0f51ceffe820e9..cc3253e9d41d035c88222dfb7907da58fa45877b 100644 (file)
@@ -2189,7 +2189,15 @@ static bool hci_conn_check_create_big_sync(struct hci_conn *conn)
        return true;
 }
 
-int hci_le_big_create_sync_pending(struct hci_dev *hdev)
+static void big_create_sync_complete(struct hci_dev *hdev, void *data, int err)
+{
+       bt_dev_dbg(hdev, "");
+
+       if (err)
+               bt_dev_err(hdev, "Unable to create BIG sync: %d", err);
+}
+
+static int big_create_sync(struct hci_dev *hdev, void *data)
 {
        DEFINE_FLEX(struct hci_cp_le_big_create_sync, pdu, bis, num_bis, 0x11);
        struct hci_conn *conn;
@@ -2246,6 +2254,13 @@ unlock:
                            struct_size(pdu, bis, pdu->num_bis), pdu);
 }
 
+int hci_le_big_create_sync_pending(struct hci_dev *hdev)
+{
+       /* Queue big_create_sync */
+       return hci_cmd_sync_queue_once(hdev, big_create_sync,
+                                      NULL, big_create_sync_complete);
+}
+
 int hci_le_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon,
                           struct bt_iso_qos *qos,
                           __u16 sync_handle, __u8 num_bis, __u8 bis[])
index 463c61712b249a88490b92dbcb7b728437c39394..5e2d9758bd3c1c85ef74c5e4ace346632d3a7ed9 100644 (file)
@@ -1392,6 +1392,13 @@ static void iso_conn_big_sync(struct sock *sk)
        if (!hdev)
                return;
 
+       /* hci_le_big_create_sync requires hdev lock to be held, since
+        * it enqueues the HCI LE BIG Create Sync command via
+        * hci_cmd_sync_queue_once, which checks hdev flags that might
+        * change.
+        */
+       hci_dev_lock(hdev);
+
        if (!test_and_set_bit(BT_SK_BIG_SYNC, &iso_pi(sk)->flags)) {
                err = hci_le_big_create_sync(hdev, iso_pi(sk)->conn->hcon,
                                             &iso_pi(sk)->qos,
@@ -1402,6 +1409,8 @@ static void iso_conn_big_sync(struct sock *sk)
                        bt_dev_err(hdev, "hci_le_big_create_sync: %d",
                                   err);
        }
+
+       hci_dev_unlock(hdev);
 }
 
 static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,