diff options
author | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2023-04-13 03:45:51 +0300 |
---|---|---|
committer | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2023-04-24 08:04:01 +0300 |
commit | c09b80be6ffc338634b2f5f8cfa12b6843410834 (patch) | |
tree | 685f077dfc44cf41c38c0fa1b19fbc2d9c870c32 /net/bluetooth | |
parent | c14516faede33c2c31da45cf950d55dbff42962e (diff) | |
download | linux-c09b80be6ffc338634b2f5f8cfa12b6843410834.tar.xz |
Bluetooth: hci_conn: Fix not waiting for HCI_EVT_LE_CIS_ESTABLISHED
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>
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/hci_conn.c | 58 | ||||
-rw-r--r-- | net/bluetooth/hci_sync.c | 65 |
2 files changed, 66 insertions, 57 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index c215e983e287..640b951bf40a 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -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) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 00017f75cd41..6f060d00a70a 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -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; |