]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
Bluetooth: hci_conn: Fix not waiting for HCI_EVT_LE_CIS_ESTABLISHED
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thu, 13 Apr 2023 00:45:51 +0000 (17:45 -0700)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Mon, 24 Apr 2023 05:04:01 +0000 (22:04 -0700)
When submitting HCI_OP_LE_CREATE_CIS the code shall wait for
HCI_EVT_LE_CIS_ESTABLISHED thus enforcing the serialization of
HCI_OP_LE_CREATE_CIS as the Core spec does not allow to send them in
parallel:

  BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E page 2566:

  If the Host issues this command before all the HCI_LE_CIS_Established
  events from the previous use of the command have been generated, the
  Controller shall return the error code Command Disallowed (0x0C).

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
include/net/bluetooth/hci_sync.h
net/bluetooth/hci_conn.c
net/bluetooth/hci_sync.c

index 17f5a4c32f36ee1bfeff1b0bf5950e132bf218bb..f61b249787fca806af602289b2cd7498493accc2 100644 (file)
@@ -122,6 +122,8 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason);
 
 int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn);
 
+int hci_le_create_cis_sync(struct hci_dev *hdev, struct hci_conn *conn);
+
 int hci_le_remove_cig_sync(struct hci_dev *hdev, u8 handle);
 
 int hci_le_terminate_big_sync(struct hci_dev *hdev, u8 handle, u8 reason);
index c215e983e28740c76b5b38008031e12b17ff4380..640b951bf40a1149357357ae198c0b7b3bb0ba94 100644 (file)
@@ -1932,63 +1932,7 @@ bool hci_iso_setup_path(struct hci_conn *conn)
 
 static int hci_create_cis_sync(struct hci_dev *hdev, void *data)
 {
-       struct {
-               struct hci_cp_le_create_cis cp;
-               struct hci_cis cis[0x1f];
-       } cmd;
-       struct hci_conn *conn = data;
-       u8 cig;
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.cis[0].acl_handle = cpu_to_le16(conn->parent->handle);
-       cmd.cis[0].cis_handle = cpu_to_le16(conn->handle);
-       cmd.cp.num_cis++;
-       cig = conn->iso_qos.ucast.cig;
-
-       hci_dev_lock(hdev);
-
-       rcu_read_lock();
-
-       list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
-               struct hci_cis *cis = &cmd.cis[cmd.cp.num_cis];
-
-               if (conn == data || conn->type != ISO_LINK ||
-                   conn->state == BT_CONNECTED ||
-                   conn->iso_qos.ucast.cig != cig)
-                       continue;
-
-               /* Check if all CIS(s) belonging to a CIG are ready */
-               if (!conn->parent || conn->parent->state != BT_CONNECTED ||
-                   conn->state != BT_CONNECT) {
-                       cmd.cp.num_cis = 0;
-                       break;
-               }
-
-               /* Group all CIS with state BT_CONNECT since the spec don't
-                * allow to send them individually:
-                *
-                * BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E
-                * page 2566:
-                *
-                * If the Host issues this command before all the
-                * HCI_LE_CIS_Established events from the previous use of the
-                * command have been generated, the Controller shall return the
-                * error code Command Disallowed (0x0C).
-                */
-               cis->acl_handle = cpu_to_le16(conn->parent->handle);
-               cis->cis_handle = cpu_to_le16(conn->handle);
-               cmd.cp.num_cis++;
-       }
-
-       rcu_read_unlock();
-
-       hci_dev_unlock(hdev);
-
-       if (!cmd.cp.num_cis)
-               return 0;
-
-       return hci_send_cmd(hdev, HCI_OP_LE_CREATE_CIS, sizeof(cmd.cp) +
-                           sizeof(cmd.cis[0]) * cmd.cp.num_cis, &cmd);
+       return hci_le_create_cis_sync(hdev, data);
 }
 
 int hci_le_create_cis(struct hci_conn *conn)
index 00017f75cd419fc11e2bf3b215c0990e58b2ce60..6f060d00a70afbcf0becea10c8b71b9ae56238d1 100644 (file)
@@ -6137,6 +6137,71 @@ done:
        return err;
 }
 
+int hci_le_create_cis_sync(struct hci_dev *hdev, struct hci_conn *conn)
+{
+       struct {
+               struct hci_cp_le_create_cis cp;
+               struct hci_cis cis[0x1f];
+       } cmd;
+       u8 cig;
+       struct hci_conn *hcon = conn;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.cis[0].acl_handle = cpu_to_le16(conn->parent->handle);
+       cmd.cis[0].cis_handle = cpu_to_le16(conn->handle);
+       cmd.cp.num_cis++;
+       cig = conn->iso_qos.ucast.cig;
+
+       hci_dev_lock(hdev);
+
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
+               struct hci_cis *cis = &cmd.cis[cmd.cp.num_cis];
+
+               if (conn == hcon || conn->type != ISO_LINK ||
+                   conn->state == BT_CONNECTED ||
+                   conn->iso_qos.ucast.cig != cig)
+                       continue;
+
+               /* Check if all CIS(s) belonging to a CIG are ready */
+               if (!conn->parent || conn->parent->state != BT_CONNECTED ||
+                   conn->state != BT_CONNECT) {
+                       cmd.cp.num_cis = 0;
+                       break;
+               }
+
+               /* Group all CIS with state BT_CONNECT since the spec don't
+                * allow to send them individually:
+                *
+                * BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E
+                * page 2566:
+                *
+                * If the Host issues this command before all the
+                * HCI_LE_CIS_Established events from the previous use of the
+                * command have been generated, the Controller shall return the
+                * error code Command Disallowed (0x0C).
+                */
+               cis->acl_handle = cpu_to_le16(conn->parent->handle);
+               cis->cis_handle = cpu_to_le16(conn->handle);
+               cmd.cp.num_cis++;
+       }
+
+       rcu_read_unlock();
+
+       hci_dev_unlock(hdev);
+
+       if (!cmd.cp.num_cis)
+               return 0;
+
+       /* Wait for HCI_LE_CIS_Established */
+       return __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_CREATE_CIS,
+                                       sizeof(cmd.cp) + sizeof(cmd.cis[0]) *
+                                       cmd.cp.num_cis, &cmd,
+                                       HCI_EVT_LE_CIS_ESTABLISHED,
+                                       conn->conn_timeout, NULL);
+}
+
 int hci_le_remove_cig_sync(struct hci_dev *hdev, u8 handle)
 {
        struct hci_cp_le_remove_cig cp;