Bluetooth: ISO: Do not emit LE BIG Create Sync if previous is pending

The Bluetooth Core spec does not allow a LE BIG Create sync command to be
sent to Controller if another one is pending (Vol 4, Part E, page 2586).

In order to avoid this issue, the HCI_CONN_CREATE_BIG_SYNC was added
to mark that the LE BIG Create Sync command has been sent for a hcon.
Once the BIG Sync Established event is received, the hcon flag is
erased and the next pending hcon is handled.

Signed-off-by: Iulia Tanasescu <iulia.tanasescu@nxp.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Iulia Tanasescu 2024-11-01 10:23:38 +02:00 committed by Luiz Augusto von Dentz
parent 79321b06a0
commit 42ecf19471
5 changed files with 125 additions and 16 deletions

View File

@ -29,6 +29,7 @@
#define HCI_MAX_ACL_SIZE 1024
#define HCI_MAX_SCO_SIZE 255
#define HCI_MAX_ISO_SIZE 251
#define HCI_MAX_ISO_BIS 31
#define HCI_MAX_EVENT_SIZE 260
#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4)

View File

@ -711,6 +711,9 @@ struct hci_conn {
__s8 tx_power;
__s8 max_tx_power;
struct bt_iso_qos iso_qos;
__u8 num_bis;
__u8 bis[HCI_MAX_ISO_BIS];
unsigned long flags;
enum conn_reasons conn_reason;
@ -946,6 +949,7 @@ enum {
HCI_CONN_PER_ADV,
HCI_CONN_BIG_CREATED,
HCI_CONN_CREATE_CIS,
HCI_CONN_CREATE_BIG_SYNC,
HCI_CONN_BIG_SYNC,
HCI_CONN_BIG_SYNC_FAILED,
HCI_CONN_CREATE_PA_SYNC,
@ -1295,6 +1299,30 @@ static inline struct hci_conn *hci_conn_hash_lookup_big(struct hci_dev *hdev,
return NULL;
}
static inline struct hci_conn *
hci_conn_hash_lookup_big_sync_pend(struct hci_dev *hdev,
__u8 handle, __u8 num_bis)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
if (c->type != ISO_LINK)
continue;
if (handle == c->iso_qos.bcast.big && num_bis == c->num_bis) {
rcu_read_unlock();
return c;
}
}
rcu_read_unlock();
return NULL;
}
static inline struct hci_conn *
hci_conn_hash_lookup_big_state(struct hci_dev *hdev, __u8 handle, __u16 state)
{
@ -1479,6 +1507,7 @@ 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);
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,

View File

@ -2180,34 +2180,93 @@ 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;
}
int hci_le_big_create_sync_pending(struct hci_dev *hdev)
{
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(struct hci_dev *hdev, struct hci_conn *hcon,
struct bt_iso_qos *qos,
__u16 sync_handle, __u8 num_bis, __u8 bis[])
{
DEFINE_FLEX(struct hci_cp_le_big_create_sync, pdu, bis, num_bis, 0x11);
int err;
if (num_bis < 0x01 || num_bis > pdu->num_bis)
if (num_bis < 0x01 || num_bis > ISO_MAX_NUM_BIS)
return -EINVAL;
err = qos_set_big(hdev, qos);
if (err)
return err;
if (hcon)
hcon->iso_qos.bcast.big = qos->bcast.big;
if (hcon) {
/* Update hcon QoS */
hcon->iso_qos = *qos;
pdu->handle = qos->bcast.big;
pdu->sync_handle = cpu_to_le16(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 = num_bis;
memcpy(pdu->bis, bis, num_bis);
hcon->num_bis = num_bis;
memcpy(hcon->bis, bis, num_bis);
}
return hci_send_cmd(hdev, HCI_OP_LE_BIG_CREATE_SYNC,
struct_size(pdu, bis, num_bis), pdu);
return hci_le_big_create_sync_pending(hdev);
}
static void create_big_complete(struct hci_dev *hdev, void *data, int err)

View File

@ -6920,7 +6920,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)
{
struct hci_evt_le_big_sync_estabilished *ev = data;
struct hci_conn *bis;
struct hci_conn *bis, *conn;
int i;
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
@ -6931,6 +6931,20 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_big_sync_pend(hdev, ev->handle,
ev->num_bis);
if (!conn) {
bt_dev_err(hdev,
"Unable to find connection for big 0x%2.2x",
ev->handle);
goto unlock;
}
clear_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags);
conn->num_bis = 0;
memset(conn->bis, 0, sizeof(conn->num_bis));
for (i = 0; i < ev->num_bis; i++) {
u16 handle = le16_to_cpu(ev->bis[i]);
__le32 interval;
@ -6980,6 +6994,10 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
hci_connect_cfm(bis, ev->status);
}
unlock:
/* Handle any other pending BIG sync command */
hci_le_big_create_sync_pending(hdev);
hci_dev_unlock(hdev);
}

View File

@ -1957,6 +1957,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
if (sk) {
int err;
struct hci_conn *hcon = iso_pi(sk)->conn->hcon;
iso_pi(sk)->qos.bcast.encryption = ev2->encryption;
@ -1965,7 +1966,8 @@ 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, NULL,
err = hci_le_big_create_sync(hdev,
hcon,
&iso_pi(sk)->qos,
iso_pi(sk)->sync_handle,
iso_pi(sk)->bc_num_bis,