]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
Bluetooth: hci_conn: Fix not setting timeout for BIG Create Sync
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 16 Apr 2025 19:43:32 +0000 (15:43 -0400)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Fri, 25 Apr 2025 19:03:19 +0000 (15:03 -0400)
BIG Create Sync requires the command to just generates a status so this
makes use of __hci_cmd_sync_status_sk to wait for
HCI_EVT_LE_BIG_SYNC_ESTABLISHED, also because of this chance it is not
longer necessary to use a custom method to serialize the process of
creating the BIG sync since the cmd_work_sync itself ensures only one
command would be pending which now awaits for
HCI_EVT_LE_BIG_SYNC_ESTABLISHED before proceeding to next connection.

Fixes: 42ecf1947135 ("Bluetooth: ISO: Do not emit LE BIG Create Sync if previous is pending")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/hci_sync.h
net/bluetooth/hci_conn.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sync.c
net/bluetooth/iso.c

index 8ea7a063cc651056114325577941f97b723c4af0..797992019f9ee5ea22b13677ae1885158355b687 100644 (file)
@@ -2832,7 +2832,7 @@ struct hci_evt_le_create_big_complete {
        __le16  bis_handle[];
 } __packed;
 
-#define HCI_EVT_LE_BIG_SYNC_ESTABILISHED 0x1d
+#define HCI_EVT_LE_BIG_SYNC_ESTABLISHED 0x1d
 struct hci_evt_le_big_sync_estabilished {
        __u8    status;
        __u8    handle;
index f20368b9a5d20036fd05c076bbbbd8e8ff3c893d..522d837a23fa461703ddc5567e3257c6306318e6 100644 (file)
@@ -1524,7 +1524,6 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle);
 void hci_sco_setup(struct hci_conn *conn, __u8 status);
 bool hci_iso_setup_path(struct hci_conn *conn);
 int hci_le_create_cis_pending(struct hci_dev *hdev);
-int hci_le_big_create_sync_pending(struct hci_dev *hdev);
 int hci_conn_check_create_cis(struct hci_conn *conn);
 
 struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
@@ -1565,9 +1564,9 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
                                 __u8 data_len, __u8 *data);
 struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst,
                       __u8 dst_type, __u8 sid, struct bt_iso_qos *qos);
-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[]);
+int hci_conn_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon,
+                            struct bt_iso_qos *qos, __u16 sync_handle,
+                            __u8 num_bis, __u8 bis[]);
 int hci_conn_check_link_mode(struct hci_conn *conn);
 int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level);
 int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type,
index 93dac4c7f9e3efd630fa60eae017ee0dc2f5237b..72558c826aa1b40feb2345230b0f1e324b369c27 100644 (file)
@@ -187,3 +187,4 @@ int hci_le_conn_update_sync(struct hci_dev *hdev, struct hci_conn *conn,
                            struct hci_conn_params *params);
 
 int hci_connect_pa_sync(struct hci_dev *hdev, struct hci_conn *conn);
+int hci_connect_big_sync(struct hci_dev *hdev, struct hci_conn *conn);
index c3112ce39f6724a76df8e547eeac12adad59c999..6533e281ada3334b4f8d8fe36798140239aa33bd 100644 (file)
@@ -2087,89 +2087,9 @@ struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst,
        return conn;
 }
 
-static bool hci_conn_check_create_big_sync(struct hci_conn *conn)
-{
-       if (!conn->num_bis)
-               return false;
-
-       return true;
-}
-
-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;
-
-       rcu_read_lock();
-
-       pdu->num_bis = 0;
-
-       /* The spec allows only one pending LE BIG Create Sync command at
-        * a time. If the command is pending now, don't do anything. We
-        * check for pending connections after each BIG Sync Established
-        * event.
-        *
-        * BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E
-        * page 2586:
-        *
-        * If the Host sends this command when the Controller is in the
-        * process of synchronizing to any BIG, i.e. the HCI_LE_BIG_Sync_
-        * Established event has not been generated, the Controller shall
-        * return the error code Command Disallowed (0x0C).
-        */
-       list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
-               if (test_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags))
-                       goto unlock;
-       }
-
-       list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
-               if (hci_conn_check_create_big_sync(conn)) {
-                       struct bt_iso_qos *qos = &conn->iso_qos;
-
-                       set_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags);
-
-                       pdu->handle = qos->bcast.big;
-                       pdu->sync_handle = cpu_to_le16(conn->sync_handle);
-                       pdu->encryption = qos->bcast.encryption;
-                       memcpy(pdu->bcode, qos->bcast.bcode,
-                              sizeof(pdu->bcode));
-                       pdu->mse = qos->bcast.mse;
-                       pdu->timeout = cpu_to_le16(qos->bcast.timeout);
-                       pdu->num_bis = conn->num_bis;
-                       memcpy(pdu->bis, conn->bis, conn->num_bis);
-
-                       break;
-               }
-       }
-
-unlock:
-       rcu_read_unlock();
-
-       if (!pdu->num_bis)
-               return 0;
-
-       return hci_send_cmd(hdev, HCI_OP_LE_BIG_CREATE_SYNC,
-                           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[])
+int hci_conn_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon,
+                            struct bt_iso_qos *qos, __u16 sync_handle,
+                            __u8 num_bis, __u8 bis[])
 {
        int err;
 
@@ -2186,9 +2106,10 @@ int hci_le_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon,
 
                hcon->num_bis = num_bis;
                memcpy(hcon->bis, bis, num_bis);
+               hcon->conn_timeout = msecs_to_jiffies(qos->bcast.timeout * 10);
        }
 
-       return hci_le_big_create_sync_pending(hdev);
+       return hci_connect_big_sync(hdev, hcon);
 }
 
 static void create_big_complete(struct hci_dev *hdev, void *data, int err)
index ea7ccafd055a76b95773d17efab4b66b1dc0e195..6d6061111ac5679f019ba4c8212ea1979b8f3a99 100644 (file)
@@ -6928,7 +6928,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
 
        bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
 
-       if (!hci_le_ev_skb_pull(hdev, skb, HCI_EVT_LE_BIG_SYNC_ESTABILISHED,
+       if (!hci_le_ev_skb_pull(hdev, skb, HCI_EVT_LE_BIG_SYNC_ESTABLISHED,
                                flex_array_size(ev, bis, ev->num_bis)))
                return;
 
@@ -6999,9 +6999,6 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
                }
 
 unlock:
-       /* Handle any other pending BIG sync command */
-       hci_le_big_create_sync_pending(hdev);
-
        hci_dev_unlock(hdev);
 }
 
@@ -7123,8 +7120,8 @@ static const struct hci_le_ev {
                     hci_le_create_big_complete_evt,
                     sizeof(struct hci_evt_le_create_big_complete),
                     HCI_MAX_EVENT_SIZE),
-       /* [0x1d = HCI_EV_LE_BIG_SYNC_ESTABILISHED] */
-       HCI_LE_EV_VL(HCI_EVT_LE_BIG_SYNC_ESTABILISHED,
+       /* [0x1d = HCI_EV_LE_BIG_SYNC_ESTABLISHED] */
+       HCI_LE_EV_VL(HCI_EVT_LE_BIG_SYNC_ESTABLISHED,
                     hci_le_big_sync_established_evt,
                     sizeof(struct hci_evt_le_big_sync_estabilished),
                     HCI_MAX_EVENT_SIZE),
index 99c116b056ceebbec06a494da834a8a5c525861f..e56b1cbedab908c3ddf740fead04a1cb224b7d9c 100644 (file)
@@ -6972,3 +6972,66 @@ int hci_connect_pa_sync(struct hci_dev *hdev, struct hci_conn *conn)
        return hci_cmd_sync_queue_once(hdev, hci_le_pa_create_sync, conn,
                                       create_pa_complete);
 }
+
+static void create_big_complete(struct hci_dev *hdev, void *data, int err)
+{
+       struct hci_conn *conn = data;
+
+       bt_dev_dbg(hdev, "err %d", err);
+
+       if (err == -ECANCELED)
+               return;
+
+       if (hci_conn_valid(hdev, conn))
+               clear_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags);
+}
+
+static int hci_le_big_create_sync(struct hci_dev *hdev, void *data)
+{
+       DEFINE_FLEX(struct hci_cp_le_big_create_sync, cp, bis, num_bis, 0x11);
+       struct hci_conn *conn = data;
+       struct bt_iso_qos *qos = &conn->iso_qos;
+       int err;
+
+       if (!hci_conn_valid(hdev, conn))
+               return -ECANCELED;
+
+       set_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags);
+
+       memset(cp, 0, sizeof(*cp));
+       cp->handle = qos->bcast.big;
+       cp->sync_handle = cpu_to_le16(conn->sync_handle);
+       cp->encryption = qos->bcast.encryption;
+       memcpy(cp->bcode, qos->bcast.bcode, sizeof(cp->bcode));
+       cp->mse = qos->bcast.mse;
+       cp->timeout = cpu_to_le16(qos->bcast.timeout);
+       cp->num_bis = conn->num_bis;
+       memcpy(cp->bis, conn->bis, conn->num_bis);
+
+       /* The spec allows only one pending LE BIG Create Sync command at
+        * a time, so we forcefully wait for BIG Sync Established event since
+        * cmd_work can only schedule one command at a time.
+        *
+        * BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E
+        * page 2586:
+        *
+        * If the Host sends this command when the Controller is in the
+        * process of synchronizing to any BIG, i.e. the HCI_LE_BIG_Sync_
+        * Established event has not been generated, the Controller shall
+        * return the error code Command Disallowed (0x0C).
+        */
+       err = __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_BIG_CREATE_SYNC,
+                                      struct_size(cp, bis, cp->num_bis), cp,
+                                      HCI_EVT_LE_BIG_SYNC_ESTABLISHED,
+                                      conn->conn_timeout, NULL);
+       if (err == -ETIMEDOUT)
+               hci_le_big_terminate_sync(hdev, cp->handle);
+
+       return err;
+}
+
+int hci_connect_big_sync(struct hci_dev *hdev, struct hci_conn *conn)
+{
+       return hci_cmd_sync_queue_once(hdev, hci_le_big_create_sync, conn,
+                                      create_big_complete);
+}
index 3501a991f1c64ec2720dfa747ac5201e759b381e..2819cda616bce8214d72073a14fcb38cf2516369 100644 (file)
@@ -1462,14 +1462,13 @@ static void iso_conn_big_sync(struct sock *sk)
        lock_sock(sk);
 
        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,
-                                            iso_pi(sk)->sync_handle,
-                                            iso_pi(sk)->bc_num_bis,
-                                            iso_pi(sk)->bc_bis);
+               err = hci_conn_big_create_sync(hdev, iso_pi(sk)->conn->hcon,
+                                              &iso_pi(sk)->qos,
+                                              iso_pi(sk)->sync_handle,
+                                              iso_pi(sk)->bc_num_bis,
+                                              iso_pi(sk)->bc_bis);
                if (err)
-                       bt_dev_err(hdev, "hci_le_big_create_sync: %d",
-                                  err);
+                       bt_dev_err(hdev, "hci_big_create_sync: %d", err);
        }
 
        release_sock(sk);
@@ -1922,7 +1921,7 @@ static void iso_conn_ready(struct iso_conn *conn)
                                              hcon);
                } else if (test_bit(HCI_CONN_BIG_SYNC_FAILED, &hcon->flags)) {
                        ev = hci_recv_event_data(hcon->hdev,
-                                                HCI_EVT_LE_BIG_SYNC_ESTABILISHED);
+                                                HCI_EVT_LE_BIG_SYNC_ESTABLISHED);
 
                        /* Get reference to PA sync parent socket, if it exists */
                        parent = iso_get_sock(&hcon->src, &hcon->dst,
@@ -2113,12 +2112,11 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
 
                        if (!test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags) &&
                            !test_and_set_bit(BT_SK_BIG_SYNC, &iso_pi(sk)->flags)) {
-                               err = hci_le_big_create_sync(hdev,
-                                                            hcon,
-                                                            &iso_pi(sk)->qos,
-                                                            iso_pi(sk)->sync_handle,
-                                                            iso_pi(sk)->bc_num_bis,
-                                                            iso_pi(sk)->bc_bis);
+                               err = hci_conn_big_create_sync(hdev, hcon,
+                                                              &iso_pi(sk)->qos,
+                                                              iso_pi(sk)->sync_handle,
+                                                              iso_pi(sk)->bc_num_bis,
+                                                              iso_pi(sk)->bc_bis);
                                if (err) {
                                        bt_dev_err(hdev, "hci_le_big_create_sync: %d",
                                                   err);