Commit 6d0417e4 authored by Luiz Augusto von Dentz's avatar Luiz Augusto von Dentz
Browse files

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: 4a5e0ba6 ("Bluetooth: ISO: Do not emit LE PA Create Sync if previous is pending")
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
parent 49ba1ca2
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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;
+6 −7
Original line number Diff line number Diff line
@@ -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);

+2 −0
Original line number Diff line number Diff line
@@ -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);
+2 −90
Original line number Diff line number Diff line
@@ -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;
}
+1 −5
Original line number Diff line number Diff line
@@ -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);
}

Loading