This patch adds support for additional ISO broadcast QoS parameters,
that the user can set before performing broadcast procedures
using an ISO socket.
This patch splits the "bt_iso_qos" structure into dedicated
unicast and broadcast structures, so that ISO sockets
can be configured with dedicated QoS options depending
on the type of ISO procedures to run.
This patch depends on the BlueZ patch
[BlueZ,v2,1/1] Split bt_iso_qos into dedicated structures.
Iulia Tanasescu (1):
Split bt_iso_qos into dedicated structures
include/net/bluetooth/bluetooth.h | 56 ++++++--
include/net/bluetooth/hci_core.h | 17 +--
net/bluetooth/hci_conn.c | 104 +++++++++------
net/bluetooth/hci_event.c | 38 +++---
net/bluetooth/iso.c | 205 ++++++++++++++++++++++++------
5 files changed, 305 insertions(+), 115 deletions(-)
base-commit: db0fc80ec686774f1ca4606e752bf42af1f1cd97
--
2.34.1
Split bt_iso_qos into dedicated unicast and broadcast
structures and add additional broadcast parameters.
Signed-off-by: Iulia Tanasescu <[email protected]>
---
include/net/bluetooth/bluetooth.h | 56 ++++++--
include/net/bluetooth/hci_core.h | 17 +--
net/bluetooth/hci_conn.c | 104 +++++++++------
net/bluetooth/hci_event.c | 38 +++---
net/bluetooth/iso.c | 205 ++++++++++++++++++++++++------
5 files changed, 305 insertions(+), 115 deletions(-)
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index bcc5a4cd2c17..bc2503d9c3cd 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -1,6 +1,7 @@
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2000-2001 Qualcomm Incorporated
+ Copyright 2023 NXP
Written 2000,2001 by Maxim Krasnyansky <[email protected]>
@@ -171,25 +172,54 @@ struct bt_iso_io_qos {
__u8 rtn;
};
-struct bt_iso_qos {
- union {
- __u8 cig;
- __u8 big;
- };
- union {
- __u8 cis;
- __u8 bis;
- };
- union {
- __u8 sca;
- __u8 sync_interval;
- };
+struct bt_iso_ucast_qos {
+ __u8 cig;
+ __u8 cis;
+ __u8 sca;
__u8 packing;
__u8 framing;
struct bt_iso_io_qos in;
struct bt_iso_io_qos out;
};
+struct bt_iso_bcast_src_qos {
+ __u8 sync_interval;
+ __u8 big;
+ __u8 bis;
+ __u8 packing;
+ __u8 framing;
+ __u8 encryption;
+ __u8 bcode[16];
+ struct bt_iso_io_qos out;
+};
+
+struct bt_iso_bcast_snk_qos {
+ __u8 options;
+ __u16 skip;
+ __u16 sync_timeout;
+ __u8 sync_cte_type;
+ __u8 big;
+ __u8 encryption;
+ __u8 bcode[16];
+ __u8 mse;
+ __u16 timeout;
+ struct bt_iso_io_qos in;
+};
+
+struct bt_iso_bcast_qos {
+union {
+ struct bt_iso_bcast_src_qos bsrc;
+ struct bt_iso_bcast_snk_qos bsnk;
+ };
+};
+
+struct bt_iso_qos {
+ union {
+ struct bt_iso_ucast_qos ucast;
+ struct bt_iso_bcast_qos bcast;
+ };
+};
+
#define BT_ISO_PHY_1M 0x01
#define BT_ISO_PHY_2M 0x02
#define BT_ISO_PHY_CODED 0x04
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 53d3328c2b8b..e6e6217a4509 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1,6 +1,7 @@
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
+ Copyright 2023 NXP
Written 2000,2001 by Maxim Krasnyansky <[email protected]>
@@ -1090,7 +1091,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_bis(struct hci_dev *hdev,
if (bacmp(&c->dst, ba) || c->type != ISO_LINK)
continue;
- if (c->iso_qos.big == big && c->iso_qos.bis == bis) {
+ if (c->iso_qos.bcast.bsrc.big == big && c->iso_qos.bcast.bsrc.bis == bis) {
rcu_read_unlock();
return c;
}
@@ -1199,7 +1200,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_cig(struct hci_dev *hdev,
if (c->type != ISO_LINK)
continue;
- if (handle == c->iso_qos.cig) {
+ if (handle == c->iso_qos.ucast.cig) {
rcu_read_unlock();
return c;
}
@@ -1222,7 +1223,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_big(struct hci_dev *hdev,
if (bacmp(&c->dst, BDADDR_ANY) || c->type != ISO_LINK)
continue;
- if (handle == c->iso_qos.big) {
+ if (handle == c->iso_qos.bcast.bsrc.big) {
rcu_read_unlock();
return c;
}
@@ -1324,15 +1325,15 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
__u16 setting, struct bt_codec *codec);
struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
- __u8 dst_type, struct bt_iso_qos *qos);
+ __u8 dst_type, struct bt_iso_ucast_qos *qos);
struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst,
- __u8 dst_type, struct bt_iso_qos *qos);
+ __u8 dst_type, struct bt_iso_ucast_qos *qos);
struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
- __u8 dst_type, struct bt_iso_qos *qos,
+ __u8 dst_type, struct bt_iso_bcast_src_qos *qos,
__u8 data_len, __u8 *data);
int hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type,
- __u8 sid);
-int hci_le_big_create_sync(struct hci_dev *hdev, struct bt_iso_qos *qos,
+ __u8 sid, struct bt_iso_bcast_snk_qos *qos);
+int hci_le_big_create_sync(struct hci_dev *hdev, struct bt_iso_bcast_snk_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);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 17b946f9ba31..8e12b00b45a2 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1,6 +1,7 @@
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
+ Copyright 2023 NXP
Written 2000,2001 by Maxim Krasnyansky <[email protected]>
@@ -771,13 +772,22 @@ struct iso_list_data {
static void bis_list(struct hci_conn *conn, void *data)
{
struct iso_list_data *d = data;
+ u8 check_big;
+ u8 check_bis = BT_ISO_QOS_BIS_UNSET;
/* Skip if not broadcast/ANY address */
if (bacmp(&conn->dst, BDADDR_ANY))
return;
- if (d->big != conn->iso_qos.big || d->bis == BT_ISO_QOS_BIS_UNSET ||
- d->bis != conn->iso_qos.bis)
+ if (conn->role == HCI_ROLE_MASTER) {
+ check_big = conn->iso_qos.bcast.bsrc.big;
+ check_bis = conn->iso_qos.bcast.bsrc.bis;
+ } else {
+ check_big = conn->iso_qos.bcast.bsnk.big;
+ }
+
+ if (d->big != check_big || d->bis == BT_ISO_QOS_BIS_UNSET ||
+ d->bis != check_bis)
return;
d->count++;
@@ -897,10 +907,10 @@ static void bis_cleanup(struct hci_conn *conn)
if (!test_and_clear_bit(HCI_CONN_PER_ADV, &conn->flags))
return;
- hci_le_terminate_big(hdev, conn->iso_qos.big,
- conn->iso_qos.bis);
+ hci_le_terminate_big(hdev, conn->iso_qos.bcast.bsrc.big,
+ conn->iso_qos.bcast.bsrc.bis);
} else {
- hci_le_big_terminate(hdev, conn->iso_qos.big,
+ hci_le_big_terminate(hdev, conn->iso_qos.bcast.bsnk.big,
conn->sync_handle);
}
}
@@ -940,7 +950,7 @@ static void cis_cleanup(struct hci_conn *conn)
struct iso_list_data d;
memset(&d, 0, sizeof(d));
- d.cig = conn->iso_qos.cig;
+ d.cig = conn->iso_qos.ucast.cig;
/* Check if ISO connection is a CIS and remove CIG if there are
* no other connections using it.
@@ -949,7 +959,7 @@ static void cis_cleanup(struct hci_conn *conn)
if (d.count)
return;
- hci_le_remove_cig(hdev, conn->iso_qos.cig);
+ hci_le_remove_cig(hdev, conn->iso_qos.ucast.cig);
}
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
@@ -1398,12 +1408,12 @@ static int hci_explicit_conn_params_set(struct hci_dev *hdev,
return 0;
}
-static int qos_set_big(struct hci_dev *hdev, struct bt_iso_qos *qos)
+static int qos_set_big(struct hci_dev *hdev, uint8_t *big)
{
struct iso_list_data data;
/* Allocate a BIG if not set */
- if (qos->big == BT_ISO_QOS_BIG_UNSET) {
+ if (*big == BT_ISO_QOS_BIG_UNSET) {
for (data.big = 0x00; data.big < 0xef; data.big++) {
data.count = 0;
data.bis = 0xff;
@@ -1418,13 +1428,14 @@ static int qos_set_big(struct hci_dev *hdev, struct bt_iso_qos *qos)
return -EADDRNOTAVAIL;
/* Update BIG */
- qos->big = data.big;
+ *big = data.big;
}
return 0;
}
-static int qos_set_bis(struct hci_dev *hdev, struct bt_iso_qos *qos)
+static int qos_set_bis(struct hci_dev *hdev,
+ struct bt_iso_bcast_src_qos *qos)
{
struct iso_list_data data;
@@ -1455,7 +1466,7 @@ static int qos_set_bis(struct hci_dev *hdev, struct bt_iso_qos *qos)
/* This function requires the caller holds hdev->lock */
static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst,
- struct bt_iso_qos *qos)
+ struct bt_iso_bcast_src_qos *qos)
{
struct hci_conn *conn;
struct iso_list_data data;
@@ -1468,7 +1479,7 @@ static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst,
return ERR_PTR(-EOPNOTSUPP);
}
- err = qos_set_big(hdev, qos);
+ err = qos_set_big(hdev, &qos->big);
if (err)
return ERR_PTR(err);
@@ -1636,7 +1647,7 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
return sco;
}
-static void cis_add(struct iso_list_data *d, struct bt_iso_qos *qos)
+static void cis_add(struct iso_list_data *d, struct bt_iso_ucast_qos *qos)
{
struct hci_cis_params *cis = &d->pdu.cis[d->pdu.cp.num_cis];
@@ -1659,8 +1670,8 @@ static void cis_list(struct hci_conn *conn, void *data)
if (!bacmp(&conn->dst, BDADDR_ANY))
return;
- if (d->cig != conn->iso_qos.cig || d->cis == BT_ISO_QOS_CIS_UNSET ||
- d->cis != conn->iso_qos.cis)
+ if (d->cig != conn->iso_qos.ucast.cig || d->cis == BT_ISO_QOS_CIS_UNSET ||
+ d->cis != conn->iso_qos.ucast.cis)
return;
d->count++;
@@ -1669,10 +1680,11 @@ static void cis_list(struct hci_conn *conn, void *data)
d->count >= ARRAY_SIZE(d->pdu.cis))
return;
- cis_add(d, &conn->iso_qos);
+ cis_add(d, &conn->iso_qos.ucast);
}
-static int hci_le_create_big(struct hci_conn *conn, struct bt_iso_qos *qos)
+static int hci_le_create_big(struct hci_conn *conn,
+ struct bt_iso_bcast_src_qos *qos)
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_le_create_big cp;
@@ -1689,13 +1701,14 @@ static int hci_le_create_big(struct hci_conn *conn, struct bt_iso_qos *qos)
cp.bis.phy = qos->out.phy;
cp.bis.packing = qos->packing;
cp.bis.framing = qos->framing;
- cp.bis.encryption = 0x00;
- memset(&cp.bis.bcode, 0, sizeof(cp.bis.bcode));
+ cp.bis.encryption = qos->encryption;
+ memcpy(&cp.bis.bcode, qos->bcode, sizeof(cp.bis.bcode));
return hci_send_cmd(hdev, HCI_OP_LE_CREATE_BIG, sizeof(cp), &cp);
}
-static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos)
+static bool hci_le_set_cig_params(struct hci_conn *conn,
+ struct bt_iso_ucast_qos *qos)
{
struct hci_dev *hdev = conn->hdev;
struct iso_list_data data;
@@ -1779,7 +1792,7 @@ static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos)
}
struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
- __u8 dst_type, struct bt_iso_qos *qos)
+ __u8 dst_type, struct bt_iso_ucast_qos *qos)
{
struct hci_conn *cis;
@@ -1797,7 +1810,7 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
/* Check if CIS has been set and the settings matches */
if (cis->state == BT_BOUND &&
- !memcmp(&cis->iso_qos, qos, sizeof(*qos)))
+ !memcmp(&cis->iso_qos.ucast, qos, sizeof(*qos)))
return cis;
/* Update LINK PHYs according to QoS preference */
@@ -1833,7 +1846,7 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
return ERR_PTR(-EINVAL);
}
- cis->iso_qos = *qos;
+ cis->iso_qos.ucast = *qos;
cis->state = BT_BOUND;
return cis;
@@ -1843,10 +1856,19 @@ bool hci_iso_setup_path(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_le_setup_iso_path cmd;
+ struct bt_iso_io_qos *in = NULL;
+ struct bt_iso_io_qos *out = NULL;
memset(&cmd, 0, sizeof(cmd));
- if (conn->iso_qos.out.sdu) {
+ if (bacmp(&conn->dst, BDADDR_ANY)) {
+ in = &conn->iso_qos.ucast.in;
+ out = &conn->iso_qos.ucast.out;
+ } else {
+ out = &conn->iso_qos.bcast.bsrc.out;
+ }
+
+ if (out->sdu) {
cmd.handle = cpu_to_le16(conn->handle);
cmd.direction = 0x00; /* Input (Host to Controller) */
cmd.path = 0x00; /* HCI path if enabled */
@@ -1857,7 +1879,7 @@ bool hci_iso_setup_path(struct hci_conn *conn)
return false;
}
- if (conn->iso_qos.in.sdu) {
+ if (in && in->sdu) {
cmd.handle = cpu_to_le16(conn->handle);
cmd.direction = 0x01; /* Output (Controller to Host) */
cmd.path = 0x00; /* HCI path if enabled */
@@ -1884,7 +1906,7 @@ static int hci_create_cis_sync(struct hci_dev *hdev, void *data)
cmd.cis[0].acl_handle = cpu_to_le16(conn->link->handle);
cmd.cis[0].cis_handle = cpu_to_le16(conn->handle);
cmd.cp.num_cis++;
- cig = conn->iso_qos.cig;
+ cig = conn->iso_qos.ucast.cig;
hci_dev_lock(hdev);
@@ -1894,7 +1916,7 @@ static int hci_create_cis_sync(struct hci_dev *hdev, void *data)
struct hci_cis *cis = &cmd.cis[cmd.cp.num_cis];
if (conn == data || conn->type != ISO_LINK ||
- conn->state == BT_CONNECTED || conn->iso_qos.cig != cig)
+ conn->state == BT_CONNECTED || conn->iso_qos.ucast.cig != cig)
continue;
/* Check if all CIS(s) belonging to a CIG are ready */
@@ -1991,19 +2013,19 @@ static void hci_iso_qos_setup(struct hci_dev *hdev, struct hci_conn *conn,
}
static void hci_bind_bis(struct hci_conn *conn,
- struct bt_iso_qos *qos)
+ struct bt_iso_bcast_src_qos *qos)
{
/* Update LINK PHYs according to QoS preference */
conn->le_tx_phy = qos->out.phy;
conn->le_tx_phy = qos->out.phy;
- conn->iso_qos = *qos;
+ conn->iso_qos.bcast.bsrc = *qos;
conn->state = BT_BOUND;
}
static int create_big_sync(struct hci_dev *hdev, void *data)
{
struct hci_conn *conn = data;
- struct bt_iso_qos *qos = &conn->iso_qos;
+ struct bt_iso_bcast_src_qos *qos = &conn->iso_qos.bcast.bsrc;
u16 interval, sync_interval = 0;
u32 flags = 0;
int err;
@@ -2023,7 +2045,7 @@ static int create_big_sync(struct hci_dev *hdev, void *data)
if (err)
return err;
- return hci_le_create_big(conn, &conn->iso_qos);
+ return hci_le_create_big(conn, &conn->iso_qos.bcast.bsrc);
}
static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
@@ -2054,7 +2076,7 @@ static int create_pa_sync(struct hci_dev *hdev, void *data)
}
int hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type,
- __u8 sid)
+ __u8 sid, struct bt_iso_bcast_snk_qos *qos)
{
struct hci_cp_le_pa_create_sync *cp;
@@ -2067,15 +2089,19 @@ int hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type,
return -ENOMEM;
}
+ cp->options = qos->options;
cp->sid = sid;
cp->addr_type = dst_type;
+ cp->skip = qos->skip;
+ cp->sync_timeout = qos->sync_timeout;
+ cp->sync_cte_type = qos->sync_cte_type;
bacpy(&cp->addr, dst);
/* Queue start pa_create_sync and scan */
return hci_cmd_sync_queue(hdev, create_pa_sync, cp, create_pa_complete);
}
-int hci_le_big_create_sync(struct hci_dev *hdev, struct bt_iso_qos *qos,
+int hci_le_big_create_sync(struct hci_dev *hdev, struct bt_iso_bcast_snk_qos *qos,
__u16 sync_handle, __u8 num_bis, __u8 bis[])
{
struct _packed {
@@ -2087,13 +2113,17 @@ int hci_le_big_create_sync(struct hci_dev *hdev, struct bt_iso_qos *qos,
if (num_bis > sizeof(pdu.bis))
return -EINVAL;
- err = qos_set_big(hdev, qos);
+ err = qos_set_big(hdev, &qos->big);
if (err)
return err;
memset(&pdu, 0, sizeof(pdu));
pdu.cp.handle = qos->big;
pdu.cp.sync_handle = cpu_to_le16(sync_handle);
+ pdu.cp.encryption = qos->encryption;
+ memcpy(pdu.cp.bcode, qos->bcode, sizeof(pdu.cp.bcode));
+ pdu.cp.mse = qos->mse;
+ pdu.cp.timeout = qos->timeout;
pdu.cp.num_bis = num_bis;
memcpy(pdu.bis, bis, num_bis);
@@ -2115,7 +2145,7 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err)
}
struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
- __u8 dst_type, struct bt_iso_qos *qos,
+ __u8 dst_type, struct bt_iso_bcast_src_qos *qos,
__u8 base_len, __u8 *base)
{
struct hci_conn *conn;
@@ -2151,7 +2181,7 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
}
struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst,
- __u8 dst_type, struct bt_iso_qos *qos)
+ __u8 dst_type, struct bt_iso_ucast_qos *qos)
{
struct hci_conn *le;
struct hci_conn *cis;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 8d8547fa9032..0a7c2c759ac8 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1,6 +1,7 @@
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
+ Copyright 2023 NXP
Written 2000,2001 by Maxim Krasnyansky <[email protected]>
@@ -3843,7 +3844,7 @@ static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data,
rcu_read_lock();
list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
- if (conn->type != ISO_LINK || conn->iso_qos.cig != rp->cig_id ||
+ if (conn->type != ISO_LINK || conn->iso_qos.ucast.cig != rp->cig_id ||
conn->state == BT_CONNECTED)
continue;
@@ -3877,6 +3878,7 @@ static u8 hci_cc_le_setup_iso_path(struct hci_dev *hdev, void *data,
struct hci_rp_le_setup_iso_path *rp = data;
struct hci_cp_le_setup_iso_path *cp;
struct hci_conn *conn;
+ bool cfm;
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
@@ -3900,12 +3902,14 @@ static u8 hci_cc_le_setup_iso_path(struct hci_dev *hdev, void *data,
/* Input (Host to Controller) */
case 0x00:
/* Only confirm connection if output only */
- if (conn->iso_qos.out.sdu && !conn->iso_qos.in.sdu)
+ cfm = !bacmp(&conn->dst, BDADDR_ANY) ||
+ (conn->iso_qos.ucast.out.sdu && !conn->iso_qos.ucast.in.sdu);
+ if (cfm)
hci_connect_cfm(conn, rp->status);
break;
/* Output (Controller to Host) */
case 0x01:
- /* Confirm connection since conn->iso_qos is always configured
+ /* Confirm connection since Output is always configured
* last.
*/
hci_connect_cfm(conn, rp->status);
@@ -6822,15 +6826,15 @@ static void hci_le_cis_estabilished_evt(struct hci_dev *hdev, void *data,
memset(&interval, 0, sizeof(interval));
memcpy(&interval, ev->c_latency, sizeof(ev->c_latency));
- conn->iso_qos.in.interval = le32_to_cpu(interval);
+ conn->iso_qos.ucast.in.interval = le32_to_cpu(interval);
memcpy(&interval, ev->p_latency, sizeof(ev->p_latency));
- conn->iso_qos.out.interval = le32_to_cpu(interval);
- conn->iso_qos.in.latency = le16_to_cpu(ev->interval);
- conn->iso_qos.out.latency = le16_to_cpu(ev->interval);
- conn->iso_qos.in.sdu = le16_to_cpu(ev->c_mtu);
- conn->iso_qos.out.sdu = le16_to_cpu(ev->p_mtu);
- conn->iso_qos.in.phy = ev->c_phy;
- conn->iso_qos.out.phy = ev->p_phy;
+ conn->iso_qos.ucast.out.interval = le32_to_cpu(interval);
+ conn->iso_qos.ucast.in.latency = le16_to_cpu(ev->interval);
+ conn->iso_qos.ucast.out.latency = le16_to_cpu(ev->interval);
+ conn->iso_qos.ucast.in.sdu = le16_to_cpu(ev->c_mtu);
+ conn->iso_qos.ucast.out.sdu = le16_to_cpu(ev->p_mtu);
+ conn->iso_qos.ucast.in.phy = ev->c_phy;
+ conn->iso_qos.ucast.out.phy = ev->p_phy;
}
if (!ev->status) {
@@ -6904,8 +6908,8 @@ static void hci_le_cis_req_evt(struct hci_dev *hdev, void *data,
cis->handle = cis_handle;
}
- cis->iso_qos.cig = ev->cig_id;
- cis->iso_qos.cis = ev->cis_id;
+ cis->iso_qos.ucast.cig = ev->cig_id;
+ cis->iso_qos.ucast.cis = ev->cis_id;
if (!(flags & HCI_PROTO_DEFER)) {
hci_le_accept_cis(hdev, ev->cis_handle);
@@ -6992,13 +6996,13 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
bis->handle = handle;
}
- bis->iso_qos.big = ev->handle;
+ bis->iso_qos.bcast.bsnk.big = ev->handle;
memset(&interval, 0, sizeof(interval));
memcpy(&interval, ev->latency, sizeof(ev->latency));
- bis->iso_qos.in.interval = le32_to_cpu(interval);
+ bis->iso_qos.bcast.bsnk.in.interval = le32_to_cpu(interval);
/* Convert ISO Interval (1.25 ms slots) to latency (ms) */
- bis->iso_qos.in.latency = le16_to_cpu(ev->interval) * 125 / 100;
- bis->iso_qos.in.sdu = le16_to_cpu(ev->max_pdu);
+ bis->iso_qos.bcast.bsnk.in.latency = le16_to_cpu(ev->interval) * 125 / 100;
+ bis->iso_qos.bcast.bsnk.in.sdu = le16_to_cpu(ev->max_pdu);
hci_connect_cfm(bis, ev->status);
}
diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c
index 8d136a730163..4bbac01c84c2 100644
--- a/net/bluetooth/iso.c
+++ b/net/bluetooth/iso.c
@@ -3,6 +3,7 @@
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2022 Intel Corporation
+ * Copyright 2023 NXP
*/
#include <linux/module.h>
@@ -59,11 +60,55 @@ struct iso_pinfo {
__u16 sync_handle;
__u32 flags;
struct bt_iso_qos qos;
+ bool qos_user_set;
__u8 base_len;
__u8 base[BASE_MAX_LENGTH];
struct iso_conn *conn;
};
+#define DEFAULT_IO_QOS \
+{ \
+ .interval = 10000u, \
+ .latency = 10u, \
+ .sdu = 40u, \
+ .phy = BT_ISO_PHY_2M, \
+ .rtn = 2u, \
+}
+
+static struct bt_iso_ucast_qos default_ucast_qos = {
+ .cig = BT_ISO_QOS_CIG_UNSET,
+ .cis = BT_ISO_QOS_CIS_UNSET,
+ .sca = 0x00,
+ .packing = 0x00,
+ .framing = 0x00,
+ .in = DEFAULT_IO_QOS,
+ .out = DEFAULT_IO_QOS,
+};
+
+static struct bt_iso_bcast_snk_qos default_snk_qos = {
+ .options = 0x00,
+ .skip = 0x0000,
+ .sync_timeout = 0x4000,
+ .sync_cte_type = 0x0000,
+ .big = BT_ISO_QOS_BIG_UNSET,
+ .encryption = 0x00,
+ .bcode = {0x00},
+ .mse = 0x00,
+ .timeout = 0x4000,
+ .in = DEFAULT_IO_QOS,
+};
+
+static struct bt_iso_bcast_src_qos default_src_qos = {
+ .sync_interval = 0x07,
+ .big = BT_ISO_QOS_BIG_UNSET,
+ .bis = BT_ISO_QOS_BIS_UNSET,
+ .packing = 0x00,
+ .framing = 0x00,
+ .encryption = 0x00,
+ .bcode = {0x00},
+ .out = DEFAULT_IO_QOS,
+};
+
/* ---- ISO timers ---- */
#define ISO_CONN_TIMEOUT (HZ * 40)
#define ISO_DISCONN_TIMEOUT (HZ * 2)
@@ -243,6 +288,8 @@ static inline u8 le_addr_type(u8 bdaddr_type)
return ADDR_LE_DEV_RANDOM;
}
+static bool check_bcast_src_qos(struct bt_iso_bcast_src_qos *qos);
+
static int iso_connect_bis(struct sock *sk)
{
struct iso_conn *conn;
@@ -264,15 +311,27 @@ static int iso_connect_bis(struct sock *sk)
goto unlock;
}
+ /* Check QoS */
+ if (!check_bcast_src_qos(&iso_pi(sk)->qos.bcast.bsrc)) {
+ if (!iso_pi(sk)->qos_user_set) {
+ /* Set default broadcast source QoS */
+ iso_pi(sk)->qos.bcast.bsrc = default_src_qos;
+ } else {
+ /* Fail if the user provided invalid QoS */
+ err = -EINVAL;
+ goto unlock;
+ }
+ }
+
/* Fail if out PHYs are marked as disabled */
- if (!iso_pi(sk)->qos.out.phy) {
+ if (!iso_pi(sk)->qos.bcast.bsrc.out.phy) {
err = -EINVAL;
goto unlock;
}
hcon = hci_connect_bis(hdev, &iso_pi(sk)->dst,
le_addr_type(iso_pi(sk)->dst_type),
- &iso_pi(sk)->qos, iso_pi(sk)->base_len,
+ &iso_pi(sk)->qos.bcast.bsrc, iso_pi(sk)->base_len,
iso_pi(sk)->base);
if (IS_ERR(hcon)) {
err = PTR_ERR(hcon);
@@ -315,6 +374,8 @@ static int iso_connect_bis(struct sock *sk)
return err;
}
+static bool check_ucast_qos(struct bt_iso_ucast_qos *qos);
+
static int iso_connect_cis(struct sock *sk)
{
struct iso_conn *conn;
@@ -336,8 +397,14 @@ static int iso_connect_cis(struct sock *sk)
goto unlock;
}
+ /* Check QoS */
+ if (!check_ucast_qos(&iso_pi(sk)->qos.ucast)) {
+ err = -EINVAL;
+ goto unlock;
+ }
+
/* Fail if either PHYs are marked as disabled */
- if (!iso_pi(sk)->qos.in.phy && !iso_pi(sk)->qos.out.phy) {
+ if (!iso_pi(sk)->qos.ucast.in.phy && !iso_pi(sk)->qos.ucast.out.phy) {
err = -EINVAL;
goto unlock;
}
@@ -346,7 +413,7 @@ static int iso_connect_cis(struct sock *sk)
if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
hcon = hci_bind_cis(hdev, &iso_pi(sk)->dst,
le_addr_type(iso_pi(sk)->dst_type),
- &iso_pi(sk)->qos);
+ &iso_pi(sk)->qos.ucast);
if (IS_ERR(hcon)) {
err = PTR_ERR(hcon);
goto unlock;
@@ -354,7 +421,7 @@ static int iso_connect_cis(struct sock *sk)
} else {
hcon = hci_connect_cis(hdev, &iso_pi(sk)->dst,
le_addr_type(iso_pi(sk)->dst_type),
- &iso_pi(sk)->qos);
+ &iso_pi(sk)->qos.ucast);
if (IS_ERR(hcon)) {
err = PTR_ERR(hcon);
goto unlock;
@@ -408,16 +475,16 @@ static struct bt_iso_qos *iso_sock_get_qos(struct sock *sk)
return &iso_pi(sk)->qos;
}
-static int iso_send_frame(struct sock *sk, struct sk_buff *skb)
+static int iso_send_frame(struct sock *sk, struct sk_buff *skb,
+ struct bt_iso_io_qos *out)
{
struct iso_conn *conn = iso_pi(sk)->conn;
- struct bt_iso_qos *qos = iso_sock_get_qos(sk);
struct hci_iso_data_hdr *hdr;
int len = 0;
BT_DBG("sk %p len %d", sk, skb->len);
- if (skb->len > qos->out.sdu)
+ if (skb->len > out->sdu)
return -EMSGSIZE;
len = skb->len;
@@ -661,6 +728,13 @@ static void iso_sock_init(struct sock *sk, struct sock *parent)
sk->sk_type = parent->sk_type;
bt_sk(sk)->flags = bt_sk(parent)->flags;
security_sk_clone(parent, sk);
+
+ if (bacmp(&iso_pi(parent)->dst, BDADDR_ANY))
+ iso_pi(sk)->qos.bcast.bsnk = default_snk_qos;
+ else
+ iso_pi(sk)->qos.ucast = default_ucast_qos;
+ } else {
+ iso_pi(sk)->qos.ucast = default_ucast_qos;
}
}
@@ -670,25 +744,6 @@ static struct proto iso_proto = {
.obj_size = sizeof(struct iso_pinfo)
};
-#define DEFAULT_IO_QOS \
-{ \
- .interval = 10000u, \
- .latency = 10u, \
- .sdu = 40u, \
- .phy = BT_ISO_PHY_2M, \
- .rtn = 2u, \
-}
-
-static struct bt_iso_qos default_qos = {
- .cig = BT_ISO_QOS_CIG_UNSET,
- .cis = BT_ISO_QOS_CIS_UNSET,
- .sca = 0x00,
- .packing = 0x00,
- .framing = 0x00,
- .in = DEFAULT_IO_QOS,
- .out = DEFAULT_IO_QOS,
-};
-
static struct sock *iso_sock_alloc(struct net *net, struct socket *sock,
int proto, gfp_t prio, int kern)
{
@@ -712,8 +767,6 @@ static struct sock *iso_sock_alloc(struct net *net, struct socket *sock,
/* Set address type as public as default src address is BDADDR_ANY */
iso_pi(sk)->src_type = BDADDR_LE_PUBLIC;
- iso_pi(sk)->qos = default_qos;
-
bt_sock_link(&iso_sk_list, sk);
return sk;
}
@@ -869,6 +922,8 @@ static int iso_sock_connect(struct socket *sock, struct sockaddr *addr,
return err;
}
+static bool check_bcast_snk_qos(struct bt_iso_bcast_snk_qos *qos);
+
static int iso_listen_bis(struct sock *sk)
{
struct hci_dev *hdev;
@@ -893,9 +948,20 @@ static int iso_listen_bis(struct sock *sk)
if (!hdev)
return -EHOSTUNREACH;
+ /* Check QoS */
+ if (!check_bcast_snk_qos(&iso_pi(sk)->qos.bcast.bsnk)) {
+ if (!iso_pi(sk)->qos_user_set) {
+ /* Set default broadcast sink QoS */
+ iso_pi(sk)->qos.bcast.bsnk = default_snk_qos;
+ } else {
+ /* Fail if the user provided invalid QoS */
+ return -EINVAL;
+ }
+ }
+
err = hci_pa_create_sync(hdev, &iso_pi(sk)->dst,
le_addr_type(iso_pi(sk)->dst_type),
- iso_pi(sk)->bc_sid);
+ iso_pi(sk)->bc_sid, &iso_pi(sk)->qos.bcast.bsnk);
hci_dev_put(hdev);
@@ -1086,10 +1152,15 @@ static int iso_sock_sendmsg(struct socket *sock, struct msghdr *msg,
lock_sock(sk);
- if (sk->sk_state == BT_CONNECTED)
- err = iso_send_frame(sk, skb);
- else
+ if (sk->sk_state == BT_CONNECTED) {
+ if (bacmp(&conn->hcon->dst, BDADDR_ANY))
+ err = iso_send_frame(sk, skb, &iso_pi(sk)->qos.ucast.out);
+ else
+ err = iso_send_frame(sk, skb,
+ &iso_pi(sk)->qos.bcast.bsrc.out);
+ } else {
err = -ENOTCONN;
+ }
release_sock(sk);
@@ -1154,7 +1225,7 @@ static bool check_io_qos(struct bt_iso_io_qos *qos)
return true;
}
-static bool check_qos(struct bt_iso_qos *qos)
+static bool check_ucast_qos(struct bt_iso_ucast_qos *qos)
{
if (qos->sca > 0x07)
return false;
@@ -1174,6 +1245,55 @@ static bool check_qos(struct bt_iso_qos *qos)
return true;
}
+static bool check_bcast_snk_qos(struct bt_iso_bcast_snk_qos *qos)
+{
+ if (qos->options > 0x07)
+ return false;
+
+ if (qos->skip > 0x01f3)
+ return false;
+
+ if (qos->sync_timeout < 0x000a || qos->sync_timeout > 0x4000)
+ return false;
+
+ if (qos->sync_cte_type > 0x1f)
+ return false;
+
+ if (qos->encryption > 0x01)
+ return false;
+
+ if (qos->mse > 0x1f)
+ return false;
+
+ if (qos->timeout < 0x000a || qos->timeout > 0x4000)
+ return false;
+
+ if (!check_io_qos(&qos->in))
+ return false;
+
+ return true;
+}
+
+static bool check_bcast_src_qos(struct bt_iso_bcast_src_qos *qos)
+{
+ if (qos->sync_interval > 0x07)
+ return false;
+
+ if (qos->packing > 0x01)
+ return false;
+
+ if (qos->framing > 0x01)
+ return false;
+
+ if (qos->encryption > 0x01)
+ return false;
+
+ if (!check_io_qos(&qos->out))
+ return false;
+
+ return true;
+}
+
static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int optlen)
{
@@ -1224,12 +1344,17 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}
- if (!check_qos(&qos)) {
- err = -EINVAL;
- break;
- }
+ if (sk->sk_state == BT_BOUND && bacmp(&iso_pi(sk)->dst, BDADDR_ANY))
+ /* If socket is bound with broadcast address,
+ * check broadcast sink QoS
+ */
+ if (!check_bcast_snk_qos(&qos.bcast.bsnk)) {
+ err = -EINVAL;
+ break;
+ }
iso_pi(sk)->qos = qos;
+ iso_pi(sk)->qos_user_set = true;
break;
@@ -1419,7 +1544,7 @@ static bool iso_match_big(struct sock *sk, void *data)
{
struct hci_evt_le_big_sync_estabilished *ev = data;
- return ev->handle == iso_pi(sk)->qos.big;
+ return ev->handle == iso_pi(sk)->qos.bcast.bsnk.big;
}
static void iso_conn_ready(struct iso_conn *conn)
@@ -1550,7 +1675,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
iso_pi(sk)->bc_num_bis = ev2->num_bis;
err = hci_le_big_create_sync(hdev,
- &iso_pi(sk)->qos,
+ &iso_pi(sk)->qos.bcast.bsnk,
iso_pi(sk)->sync_handle,
iso_pi(sk)->bc_num_bis,
iso_pi(sk)->bc_bis);
--
2.34.1
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=734491
---Test result---
Test Summary:
CheckPatch PASS 1.94 seconds
GitLint PASS 0.24 seconds
SubjectPrefix PASS 0.06 seconds
BuildKernel PASS 44.08 seconds
CheckAllWarning PASS 48.31 seconds
CheckSparse WARNING 53.70 seconds
CheckSmatch WARNING 144.02 seconds
BuildKernel32 PASS 42.76 seconds
TestRunnerSetup PASS 607.28 seconds
TestRunner_l2cap-tester PASS 20.13 seconds
TestRunner_iso-tester FAIL 19.69 seconds
TestRunner_bnep-tester PASS 7.10 seconds
TestRunner_mgmt-tester PASS 132.33 seconds
TestRunner_rfcomm-tester PASS 11.07 seconds
TestRunner_sco-tester PASS 10.00 seconds
TestRunner_ioctl-tester PASS 11.91 seconds
TestRunner_mesh-tester PASS 8.81 seconds
TestRunner_smp-tester PASS 9.92 seconds
TestRunner_userchan-tester PASS 7.40 seconds
IncrementalBuild PASS 39.77 seconds
Details
##############################
Test: CheckSparse - WARNING
Desc: Run sparse tool with linux kernel
Output:
net/bluetooth/hci_conn.c:2095:18: warning: incorrect type in assignment (different base types)net/bluetooth/hci_conn.c:2095:18: expected restricted __le16 [usertype] skipnet/bluetooth/hci_conn.c:2095:18: got unsigned short [usertype] skipnet/bluetooth/hci_conn.c:2096:26: warning: incorrect type in assignment (different base types)net/bluetooth/hci_conn.c:2096:26: expected restricted __le16 [usertype] sync_timeoutnet/bluetooth/hci_conn.c:2096:26: got unsigned short [usertype] sync_timeoutnet/bluetooth/hci_conn.c:2126:24: warning: incorrect type in assignment (different base types)net/bluetooth/hci_conn.c:2126:24: expected restricted __le16 [addressable] [assigned] [usertype] timeoutnet/bluetooth/hci_conn.c:2126:24: got unsigned short [usertype] timeoutnet/bluetooth/hci_event.c: note: in included file (through include/net/bluetooth/hci_core.h):
##############################
Test: CheckSmatch - WARNING
Desc: Run smatch tool with source
Output:
net/bluetooth/hci_event.c: note: in included file (through include/net/bluetooth/hci_core.h):
##############################
Test: TestRunner_iso-tester - FAIL
Desc: Run iso-tester with test-runner
Output:
Total: 57, Passed: 10 (17.5%), Failed: 47, Not Run: 0
Failed Test Cases
Basic ISO Set Socket Option - Success Failed 0.184 seconds
ISO QoS 8_1_1 - Success Failed 0.188 seconds
ISO QoS 8_2_1 - Success Failed 0.176 seconds
ISO QoS 16_1_1 - Success Failed 0.184 seconds
ISO QoS 16_2_1 - Success Failed 0.184 seconds
ISO QoS 16_2_1 CIG 0x01 - Success Failed 0.192 seconds
ISO QoS 16_2_1 CIG 0x01 CIS 0x01 - Success Failed 0.184 seconds
ISO QoS 24_1_1 - Success Failed 0.196 seconds
ISO QoS 24_2_1 - Success Failed 0.180 seconds
ISO QoS 32_1_1 - Success Failed 0.176 seconds
ISO QoS 32_2_1 - Success Failed 0.188 seconds
ISO QoS 44_1_1 - Success Failed 0.188 seconds
ISO QoS 44_2_1 - Success Failed 0.184 seconds
ISO QoS 48_1_1 - Success Failed 0.184 seconds
ISO QoS 48_2_1 - Success Failed 0.180 seconds
ISO QoS 48_3_1 - Success Failed 0.176 seconds
ISO QoS 48_4_1 - Success Failed 0.184 seconds
ISO QoS 48_5_1 - Success Failed 0.184 seconds
ISO QoS 48_6_1 - Success Failed 0.200 seconds
ISO QoS 8_1_2 - Success Failed 0.192 seconds
ISO QoS 8_2_2 - Success Failed 0.184 seconds
ISO QoS 16_1_2 - Success Failed 0.176 seconds
ISO QoS 16_2_2 - Success Failed 0.188 seconds
ISO QoS 24_1_2 - Success Failed 0.176 seconds
ISO QoS 24_2_2 - Success Failed 0.192 seconds
ISO QoS 32_1_2 - Success Failed 0.184 seconds
ISO QoS 32_2_2 - Success Failed 0.188 seconds
ISO QoS 44_1_2 - Success Failed 0.184 seconds
ISO QoS 44_2_2 - Success Failed 0.184 seconds
ISO QoS 48_1_2 - Success Failed 0.192 seconds
ISO QoS 48_2_2 - Success Failed 0.188 seconds
ISO QoS 48_3_2 - Success Failed 0.188 seconds
ISO QoS 48_4_2 - Success Failed 0.176 seconds
ISO QoS 48_5_2 - Success Failed 0.192 seconds
ISO QoS 48_6_2 - Success Failed 0.180 seconds
ISO Connect - Reject Failed 0.180 seconds
ISO Connect2 CIG 0x01 - Success Failed 0.188 seconds
ISO Send - Success Failed 0.176 seconds
ISO Defer - Success Failed 0.180 seconds
ISO Defer Send - Success Failed 0.184 seconds
ISO 48_2_1 Defer Send - Success Failed 0.188 seconds
ISO Send and Receive - Success Failed 0.176 seconds
ISO Disconnect - Success Failed 0.172 seconds
ISO Reconnect - Success Failed 0.172 seconds
ISO Broadcaster - Success Failed 0.180 seconds
ISO Broadcaster BIG 0x01 - Success Failed 0.184 seconds
ISO Broadcaster BIG 0x01 BIS 0x01 - Success Failed 0.188 seconds
---
Regards,
Linux Bluetooth