Bluetooth: hci_conn: Fix not setting conn_timeout for Broadcast Receiver

Broadcast Receiver requires creating PA sync but the command just
generates a status so this makes use of __hci_cmd_sync_status_sk to wait
for HCI_EV_LE_PA_SYNC_ESTABLISHED, also because of this chance it is not
longer necessary to use a custom method to serialize the process of
creating the PA sync since the cmd_work_sync itself ensures only one
command would be pending which now awaits for
HCI_EV_LE_PA_SYNC_ESTABLISHED before proceeding to next connection.

Fixes: 4a5e0ba686 ("Bluetooth: ISO: Do not emit LE PA Create Sync if previous is pending")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Luiz Augusto von Dentz 2025-04-09 16:08:48 -04:00
parent 49ba1ca2e0
commit 6d0417e4e1
6 changed files with 95 additions and 107 deletions

View File

@ -1931,6 +1931,8 @@ struct hci_cp_le_pa_create_sync {
__u8 sync_cte_type;
} __packed;
#define HCI_OP_LE_PA_CREATE_SYNC_CANCEL 0x2045
#define HCI_OP_LE_PA_TERM_SYNC 0x2046
struct hci_cp_le_pa_term_sync {
__le16 handle;

View File

@ -1113,10 +1113,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_bis(struct hci_dev *hdev,
return NULL;
}
static inline struct hci_conn *hci_conn_hash_lookup_sid(struct hci_dev *hdev,
__u8 sid,
bdaddr_t *dst,
__u8 dst_type)
static inline struct hci_conn *
hci_conn_hash_lookup_create_pa_sync(struct hci_dev *hdev)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
@ -1124,8 +1122,10 @@ static inline struct hci_conn *hci_conn_hash_lookup_sid(struct hci_dev *hdev,
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
if (c->type != ISO_LINK || bacmp(&c->dst, dst) ||
c->dst_type != dst_type || c->sid != sid)
if (c->type != ISO_LINK)
continue;
if (!test_bit(HCI_CONN_CREATE_PA_SYNC, &c->flags))
continue;
rcu_read_unlock();
@ -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_pa_create_sync_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);

View File

@ -185,3 +185,5 @@ int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn);
int hci_cancel_connect_sync(struct hci_dev *hdev, struct hci_conn *conn);
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);

View File

@ -2064,95 +2064,6 @@ static int create_big_sync(struct hci_dev *hdev, void *data)
return hci_le_create_big(conn, &conn->iso_qos);
}
static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
{
bt_dev_dbg(hdev, "");
if (err)
bt_dev_err(hdev, "Unable to create PA: %d", err);
}
static bool hci_conn_check_create_pa_sync(struct hci_conn *conn)
{
if (conn->type != ISO_LINK || conn->sid == HCI_SID_INVALID)
return false;
return true;
}
static int create_pa_sync(struct hci_dev *hdev, void *data)
{
struct hci_cp_le_pa_create_sync cp = {0};
struct hci_conn *conn;
int err = 0;
hci_dev_lock(hdev);
rcu_read_lock();
/* The spec allows only one pending LE Periodic Advertising Create
* Sync command at a time. If the command is pending now, don't do
* anything. We check for pending connections after each PA Sync
* Established event.
*
* BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E
* page 2493:
*
* If the Host issues this command when another HCI_LE_Periodic_
* Advertising_Create_Sync command is pending, 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_PA_SYNC, &conn->flags))
goto unlock;
}
list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
if (hci_conn_check_create_pa_sync(conn)) {
struct bt_iso_qos *qos = &conn->iso_qos;
cp.options = qos->bcast.options;
cp.sid = conn->sid;
cp.addr_type = conn->dst_type;
bacpy(&cp.addr, &conn->dst);
cp.skip = cpu_to_le16(qos->bcast.skip);
cp.sync_timeout = cpu_to_le16(qos->bcast.sync_timeout);
cp.sync_cte_type = qos->bcast.sync_cte_type;
break;
}
}
unlock:
rcu_read_unlock();
hci_dev_unlock(hdev);
if (bacmp(&cp.addr, BDADDR_ANY)) {
hci_dev_set_flag(hdev, HCI_PA_SYNC);
set_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags);
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_PA_CREATE_SYNC,
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
if (!err)
err = hci_update_passive_scan_sync(hdev);
if (err) {
hci_dev_clear_flag(hdev, HCI_PA_SYNC);
clear_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags);
}
}
return err;
}
int hci_pa_create_sync_pending(struct hci_dev *hdev)
{
/* Queue start pa_create_sync and scan */
return hci_cmd_sync_queue(hdev, create_pa_sync,
NULL, create_pa_complete);
}
struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst,
__u8 dst_type, __u8 sid,
struct bt_iso_qos *qos)
@ -2167,10 +2078,11 @@ struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst,
conn->dst_type = dst_type;
conn->sid = sid;
conn->state = BT_LISTEN;
conn->conn_timeout = msecs_to_jiffies(qos->bcast.sync_timeout * 10);
hci_conn_hold(conn);
hci_pa_create_sync_pending(hdev);
hci_connect_pa_sync(hdev, conn);
return conn;
}

View File

@ -6378,8 +6378,7 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data,
hci_dev_clear_flag(hdev, HCI_PA_SYNC);
conn = hci_conn_hash_lookup_sid(hdev, ev->sid, &ev->bdaddr,
ev->bdaddr_type);
conn = hci_conn_hash_lookup_create_pa_sync(hdev);
if (!conn) {
bt_dev_err(hdev,
"Unable to find connection for dst %pMR sid 0x%2.2x",
@ -6418,9 +6417,6 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data,
}
unlock:
/* Handle any other pending PA sync command */
hci_pa_create_sync_pending(hdev);
hci_dev_unlock(hdev);
}

View File

@ -2693,16 +2693,16 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
/* Force address filtering if PA Sync is in progress */
if (hci_dev_test_flag(hdev, HCI_PA_SYNC)) {
struct hci_cp_le_pa_create_sync *sent;
struct hci_conn *conn;
sent = hci_sent_cmd_data(hdev, HCI_OP_LE_PA_CREATE_SYNC);
if (sent) {
conn = hci_conn_hash_lookup_create_pa_sync(hdev);
if (conn) {
struct conn_params pa;
memset(&pa, 0, sizeof(pa));
bacpy(&pa.addr, &sent->addr);
pa.addr_type = sent->addr_type;
bacpy(&pa.addr, &conn->dst);
pa.addr_type = conn->dst_type;
/* Clear first since there could be addresses left
* behind.
@ -6895,3 +6895,80 @@ int hci_le_conn_update_sync(struct hci_dev *hdev, struct hci_conn *conn,
return __hci_cmd_sync_status(hdev, HCI_OP_LE_CONN_UPDATE,
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
}
static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
{
bt_dev_dbg(hdev, "err %d", err);
if (!err)
return;
hci_dev_clear_flag(hdev, HCI_PA_SYNC);
if (err == -ECANCELED)
return;
hci_dev_lock(hdev);
hci_update_passive_scan_sync(hdev);
hci_dev_unlock(hdev);
}
static int hci_le_pa_create_sync(struct hci_dev *hdev, void *data)
{
struct hci_cp_le_pa_create_sync cp;
struct hci_conn *conn = data;
struct bt_iso_qos *qos = &conn->iso_qos;
int err;
if (!hci_conn_valid(hdev, conn))
return -ECANCELED;
if (hci_dev_test_and_set_flag(hdev, HCI_PA_SYNC))
return -EBUSY;
/* Mark HCI_CONN_CREATE_PA_SYNC so hci_update_passive_scan_sync can
* program the address in the allow list so PA advertisements can be
* received.
*/
set_bit(HCI_CONN_CREATE_PA_SYNC, &conn->flags);
hci_update_passive_scan_sync(hdev);
memset(&cp, 0, sizeof(cp));
cp.options = qos->bcast.options;
cp.sid = conn->sid;
cp.addr_type = conn->dst_type;
bacpy(&cp.addr, &conn->dst);
cp.skip = cpu_to_le16(qos->bcast.skip);
cp.sync_timeout = cpu_to_le16(qos->bcast.sync_timeout);
cp.sync_cte_type = qos->bcast.sync_cte_type;
/* The spec allows only one pending LE Periodic Advertising Create
* Sync command at a time so we forcefully wait for PA 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 2493:
*
* If the Host issues this command when another HCI_LE_Periodic_
* Advertising_Create_Sync command is pending, the Controller shall
* return the error code Command Disallowed (0x0C).
*/
err = __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_PA_CREATE_SYNC,
sizeof(cp), &cp,
HCI_EV_LE_PA_SYNC_ESTABLISHED,
conn->conn_timeout, NULL);
if (err == -ETIMEDOUT)
__hci_cmd_sync_status(hdev, HCI_OP_LE_PA_CREATE_SYNC_CANCEL,
0, NULL, HCI_CMD_TIMEOUT);
return err;
}
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);
}