Convert the generic bt_iso_qos structure into dedicated ISO QoS structures for unicast or broadcast. --- tools/iso-tester.c | 270 +++++++++++++++++++++++++++++++++------------ 1 file changed, 200 insertions(+), 70 deletions(-) diff --git a/tools/iso-tester.c b/tools/iso-tester.c index e4582573a..a763c6a09 100644 --- a/tools/iso-tester.c +++ b/tools/iso-tester.c @@ -4,6 +4,7 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2022 Intel Corporation. + * Copyright 2023 NXP * */ @@ -119,10 +120,52 @@ #define QOS_48_5_2 QOS_OUT(7500, 75, 117, 0x02, 13) #define QOS_48_6_2 QOS_OUT(10000, 100, 155, 0x02, 13) -#define QOS_OUT_16_2_1 QOS_OUT(10000, 10, 40, 0x02, 2) -#define QOS_OUT_1_16_2_1 QOS_OUT_1(10000, 10, 40, 0x02, 2) -#define QOS_OUT_1_1_16_2_1 QOS_OUT_1_1(10000, 10, 40, 0x02, 2) -#define QOS_IN_16_2_1 QOS_IN(10000, 10, 40, 0x02, 2) +#define QOS_SINK_FULL(_big, _in) \ +{ \ + .options = 0x00, \ + .skip = 0x0000, \ + .sync_timeout = 0x4000, \ + .sync_cte_type = 0x00, \ + .big = _big, \ + .encryption = 0x00, \ + .bcode = {0}, \ + .mse = 0x00, \ + .timeout = 0x4000, \ + .in = _in, \ +} + +#define QOS_SOURCE_FULL(_big, _bis, _out) \ +{ \ + .sync_interval = 0x07, \ + .big = _big, \ + .bis = _bis, \ + .packing = 0x00, \ + .framing = 0x00, \ + .encryption = 0x00, \ + .bcode = {0}, \ + .out = _out, \ +} + +#define BCAST_QOS_OUT(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_SOURCE_FULL(BT_ISO_QOS_BIG_UNSET, BT_ISO_QOS_BIS_UNSET, \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn)) + +#define BCAST_QOS_OUT_1(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_SOURCE_FULL(0x01, BT_ISO_QOS_BIS_UNSET, \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn)) + +#define BCAST_QOS_OUT_1_1(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_SOURCE_FULL(0x01, 0x01, \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn)) + +#define BCAST_QOS_IN(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_SINK_FULL(BT_ISO_QOS_BIG_UNSET, \ + QOS_IO(_interval, _latency, _sdu, _phy, _rtn)) + +#define QOS_OUT_16_2_1 BCAST_QOS_OUT(10000, 10, 40, 0x02, 2) +#define QOS_OUT_1_16_2_1 BCAST_QOS_OUT_1(10000, 10, 40, 0x02, 2) +#define QOS_OUT_1_1_16_2_1 BCAST_QOS_OUT_1_1(10000, 10, 40, 0x02, 2) +#define QOS_IN_16_2_1 BCAST_QOS_IN(10000, 10, 40, 0x02, 2) struct test_data { const void *test_data; @@ -141,7 +184,9 @@ struct test_data { }; struct iso_client_data { - struct bt_iso_qos qos; + struct bt_iso_unicast_qos unicast_qos; + struct bt_iso_bcast_sink_qos sink_qos; + struct bt_iso_bcast_source_qos source_qos; int expect_err; const struct iovec *send; const struct iovec *recv; @@ -369,182 +414,182 @@ static void test_data_free(void *test_data) test_iso_full(name, data, setup, func, 1, reason) static const struct iso_client_data connect_8_1_1 = { - .qos = QOS_8_1_1, + .unicast_qos = QOS_8_1_1, .expect_err = 0 }; static const struct iso_client_data connect_8_2_1 = { - .qos = QOS_8_2_1, + .unicast_qos = QOS_8_2_1, .expect_err = 0 }; static const struct iso_client_data connect_16_1_1 = { - .qos = QOS_16_1_1, + .unicast_qos = QOS_16_1_1, .expect_err = 0 }; static const struct iso_client_data connect_16_2_1 = { - .qos = QOS_16_2_1, + .unicast_qos = QOS_16_2_1, .expect_err = 0 }; static const struct iso_client_data connect_1_16_2_1 = { - .qos = QOS_1_16_2_1, + .unicast_qos = QOS_1_16_2_1, .expect_err = 0 }; static const struct iso_client_data connect_1_1_16_2_1 = { - .qos = QOS_1_1_16_2_1, + .unicast_qos = QOS_1_1_16_2_1, .expect_err = 0 }; static const struct iso_client_data connect_24_1_1 = { - .qos = QOS_24_1_1, + .unicast_qos = QOS_24_1_1, .expect_err = 0 }; static const struct iso_client_data connect_24_2_1 = { - .qos = QOS_24_2_1, + .unicast_qos = QOS_24_2_1, .expect_err = 0 }; static const struct iso_client_data connect_32_1_1 = { - .qos = QOS_32_1_1, + .unicast_qos = QOS_32_1_1, .expect_err = 0 }; static const struct iso_client_data connect_32_2_1 = { - .qos = QOS_32_2_1, + .unicast_qos = QOS_32_2_1, .expect_err = 0 }; static const struct iso_client_data connect_44_1_1 = { - .qos = QOS_44_1_1, + .unicast_qos = QOS_44_1_1, .expect_err = 0 }; static const struct iso_client_data connect_44_2_1 = { - .qos = QOS_44_2_1, + .unicast_qos = QOS_44_2_1, .expect_err = 0 }; static const struct iso_client_data connect_48_1_1 = { - .qos = QOS_48_1_1, + .unicast_qos = QOS_48_1_1, .expect_err = 0 }; static const struct iso_client_data connect_48_2_1 = { - .qos = QOS_48_2_1, + .unicast_qos = QOS_48_2_1, .expect_err = 0 }; static const struct iso_client_data connect_48_3_1 = { - .qos = QOS_48_3_1, + .unicast_qos = QOS_48_3_1, .expect_err = 0 }; static const struct iso_client_data connect_48_4_1 = { - .qos = QOS_48_4_1, + .unicast_qos = QOS_48_4_1, .expect_err = 0 }; static const struct iso_client_data connect_48_5_1 = { - .qos = QOS_48_5_1, + .unicast_qos = QOS_48_5_1, .expect_err = 0 }; static const struct iso_client_data connect_48_6_1 = { - .qos = QOS_48_6_1, + .unicast_qos = QOS_48_6_1, .expect_err = 0 }; static const struct iso_client_data connect_8_1_2 = { - .qos = QOS_8_1_2, + .unicast_qos = QOS_8_1_2, .expect_err = 0 }; static const struct iso_client_data connect_8_2_2 = { - .qos = QOS_8_2_2, + .unicast_qos = QOS_8_2_2, .expect_err = 0 }; static const struct iso_client_data connect_16_1_2 = { - .qos = QOS_16_1_2, + .unicast_qos = QOS_16_1_2, .expect_err = 0 }; static const struct iso_client_data connect_16_2_2 = { - .qos = QOS_16_2_2, + .unicast_qos = QOS_16_2_2, .expect_err = 0 }; static const struct iso_client_data connect_24_1_2 = { - .qos = QOS_24_1_2, + .unicast_qos = QOS_24_1_2, .expect_err = 0 }; static const struct iso_client_data connect_24_2_2 = { - .qos = QOS_24_2_2, + .unicast_qos = QOS_24_2_2, .expect_err = 0 }; static const struct iso_client_data connect_32_1_2 = { - .qos = QOS_32_1_2, + .unicast_qos = QOS_32_1_2, .expect_err = 0 }; static const struct iso_client_data connect_32_2_2 = { - .qos = QOS_32_2_2, + .unicast_qos = QOS_32_2_2, .expect_err = 0 }; static const struct iso_client_data connect_44_1_2 = { - .qos = QOS_44_1_2, + .unicast_qos = QOS_44_1_2, .expect_err = 0 }; static const struct iso_client_data connect_44_2_2 = { - .qos = QOS_44_2_2, + .unicast_qos = QOS_44_2_2, .expect_err = 0 }; static const struct iso_client_data connect_48_1_2 = { - .qos = QOS_48_1_2, + .unicast_qos = QOS_48_1_2, .expect_err = 0 }; static const struct iso_client_data connect_48_2_2 = { - .qos = QOS_48_2_2, + .unicast_qos = QOS_48_2_2, .expect_err = 0 }; static const struct iso_client_data connect_48_3_2 = { - .qos = QOS_48_3_2, + .unicast_qos = QOS_48_3_2, .expect_err = 0 }; static const struct iso_client_data connect_48_4_2 = { - .qos = QOS_48_4_2, + .unicast_qos = QOS_48_4_2, .expect_err = 0 }; static const struct iso_client_data connect_48_5_2 = { - .qos = QOS_48_5_2, + .unicast_qos = QOS_48_5_2, .expect_err = 0 }; static const struct iso_client_data connect_48_6_2 = { - .qos = QOS_48_6_2, + .unicast_qos = QOS_48_6_2, .expect_err = 0 }; static const struct iso_client_data connect_invalid = { - .qos = QOS(0, 0, 0, 0, 0), + .unicast_qos = QOS(0, 0, 0, 0, 0), .expect_err = -EINVAL }; static const struct iso_client_data connect_reject = { - .qos = QOS_16_1_2, + .unicast_qos = QOS_16_1_2, .expect_err = -ENOSYS }; @@ -561,20 +606,20 @@ static const struct iovec send_48_2_1 = { }; static const struct iso_client_data connect_16_2_1_send = { - .qos = QOS_16_2_1, + .unicast_qos = QOS_16_2_1, .expect_err = 0, .send = &send_16_2_1, }; static const struct iso_client_data listen_16_2_1_recv = { - .qos = QOS_16_2_1, + .unicast_qos = QOS_16_2_1, .expect_err = 0, .recv = &send_16_2_1, .server = true, }; static const struct iso_client_data listen_16_2_1_recv_ts = { - .qos = QOS_16_2_1, + .unicast_qos = QOS_16_2_1, .expect_err = 0, .recv = &send_16_2_1, .server = true, @@ -582,27 +627,27 @@ static const struct iso_client_data listen_16_2_1_recv_ts = { }; static const struct iso_client_data defer_16_2_1 = { - .qos = QOS_16_2_1, + .unicast_qos = QOS_16_2_1, .expect_err = 0, .defer = true, }; static const struct iso_client_data connect_16_2_1_defer_send = { - .qos = QOS_16_2_1, + .unicast_qos = QOS_16_2_1, .expect_err = 0, .send = &send_16_2_1, .defer = true, }; static const struct iso_client_data connect_48_2_1_defer_send = { - .qos = QOS_48_2_1, + .unicast_qos = QOS_48_2_1, .expect_err = 0, .send = &send_16_2_1, .defer = true, }; static const struct iso_client_data listen_16_2_1_defer_recv = { - .qos = QOS_16_2_1, + .unicast_qos = QOS_16_2_1, .expect_err = 0, .recv = &send_16_2_1, .server = true, @@ -610,7 +655,7 @@ static const struct iso_client_data listen_16_2_1_defer_recv = { }; static const struct iso_client_data listen_48_2_1_defer_recv = { - .qos = QOS_48_2_1, + .unicast_qos = QOS_48_2_1, .expect_err = 0, .recv = &send_48_2_1, .server = true, @@ -618,7 +663,7 @@ static const struct iso_client_data listen_48_2_1_defer_recv = { }; static const struct iso_client_data listen_16_2_1_defer_reject = { - .qos = QOS_16_2_1, + .unicast_qos = QOS_16_2_1, .expect_err = -1, .recv = &send_16_2_1, .server = true, @@ -626,50 +671,51 @@ static const struct iso_client_data listen_16_2_1_defer_reject = { }; static const struct iso_client_data connect_16_2_1_send_recv = { - .qos = QOS_16_2_1, + .unicast_qos = QOS_16_2_1, .expect_err = 0, .send = &send_16_2_1, .recv = &send_16_2_1, }; static const struct iso_client_data disconnect_16_2_1 = { - .qos = QOS_16_2_1, + .unicast_qos = QOS_16_2_1, .expect_err = 0, .disconnect = true, }; static const struct iso_client_data reconnect_16_2_1 = { - .qos = QOS_16_2_1, + .unicast_qos = QOS_16_2_1, .expect_err = 0, .disconnect = true, }; static const struct iso_client_data bcast_16_2_1_send = { - .qos = QOS_OUT_16_2_1, + .source_qos = QOS_OUT_16_2_1, .expect_err = 0, .send = &send_16_2_1, .bcast = true, }; static const struct iso_client_data bcast_1_16_2_1_send = { - .qos = QOS_OUT_1_16_2_1, + .source_qos = QOS_OUT_1_16_2_1, .expect_err = 0, .send = &send_16_2_1, .bcast = true, }; static const struct iso_client_data bcast_1_1_16_2_1_send = { - .qos = QOS_OUT_1_1_16_2_1, + .source_qos = QOS_OUT_1_1_16_2_1, .expect_err = 0, .send = &send_16_2_1, .bcast = true, }; static const struct iso_client_data bcast_16_2_1_recv = { - .qos = QOS_IN_16_2_1, + .sink_qos = QOS_IN_16_2_1, .expect_err = 0, .recv = &send_16_2_1, .bcast = true, + .server = true, }; static void client_connectable_complete(uint16_t opcode, uint8_t status, @@ -854,7 +900,7 @@ static void test_getsockopt(const void *test_data) { int sk, err; socklen_t len; - struct bt_iso_qos qos; + struct bt_iso_unicast_qos qos; sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO); if (sk < 0) { @@ -867,7 +913,7 @@ static void test_getsockopt(const void *test_data) len = sizeof(qos); memset(&qos, 0, len); - err = getsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &qos, &len); + err = getsockopt(sk, SOL_BLUETOOTH, BT_ISO_UNICAST_QOS, &qos, &len); if (err < 0) { tester_warn("Can't get socket option : %s (%d)", strerror(errno), errno); @@ -885,7 +931,7 @@ static void test_setsockopt(const void *test_data) { int sk, err; socklen_t len; - struct bt_iso_qos qos = QOS_16_1_2; + struct bt_iso_unicast_qos qos = QOS_16_1_2; sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO); if (sk < 0) { @@ -895,7 +941,8 @@ static void test_setsockopt(const void *test_data) goto end; } - err = setsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &qos, sizeof(qos)); + err = setsockopt(sk, SOL_BLUETOOTH, BT_ISO_UNICAST_QOS, + &qos, sizeof(qos)); if (err < 0) { tester_warn("Can't set socket option : %s (%d)", strerror(errno), errno); @@ -906,7 +953,7 @@ static void test_setsockopt(const void *test_data) len = sizeof(qos); memset(&qos, 0, len); - err = getsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &qos, &len); + err = getsockopt(sk, SOL_BLUETOOTH, BT_ISO_UNICAST_QOS, &qos, &len); if (err < 0) { tester_warn("Can't get socket option : %s (%d)", strerror(errno), errno); @@ -1004,8 +1051,14 @@ static int connect_iso_sock(struct test_data *data, uint8_t num, int sk) } } - err = setsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &isodata->qos, - sizeof(isodata->qos)); + if (!isodata->bcast) + err = setsockopt(sk, SOL_BLUETOOTH, BT_ISO_UNICAST_QOS, + &isodata->unicast_qos, sizeof(isodata->unicast_qos)); + else { + err = setsockopt(sk, SOL_BLUETOOTH, BT_ISO_BCAST_SOURCE_QOS, + &isodata->source_qos, sizeof(isodata->source_qos)); + } + if (err < 0) { tester_warn("Can't set socket BT_ISO_QOS option : %s (%d)", strerror(errno), errno); @@ -1080,8 +1133,8 @@ static bool check_io_qos(const struct bt_iso_io_qos *io1, return true; } -static bool check_qos(const struct bt_iso_qos *qos1, - const struct bt_iso_qos *qos2) +static bool check_unicast_qos(const struct bt_iso_unicast_qos *qos1, + const struct bt_iso_unicast_qos *qos2) { if (qos1->cig != BT_ISO_QOS_CIG_UNSET && qos2->cig != BT_ISO_QOS_CIG_UNSET && @@ -1124,6 +1177,62 @@ static bool check_qos(const struct bt_iso_qos *qos1, return true; } +static bool check_bcast_source_qos(const struct bt_iso_bcast_source_qos *qos1, + const struct bt_iso_bcast_source_qos *qos2) +{ + if (qos1->sync_interval != qos2->sync_interval) { + tester_warn("Unexpected QoS sync interval: 0x%02x != 0x%02x", + qos1->sync_interval, qos2->sync_interval); + return false; + } + + if (qos1->big != BT_ISO_QOS_BIG_UNSET && + qos2->big != BT_ISO_QOS_BIG_UNSET && + qos1->big != qos2->big) { + tester_warn("Unexpected BIG ID: 0x%02x != 0x%02x", + qos1->big, qos2->big); + return false; + } + + if (qos1->bis != BT_ISO_QOS_BIS_UNSET && + qos2->bis != BT_ISO_QOS_BIS_UNSET && + qos1->bis != qos2->bis) { + tester_warn("Unexpected BIS ID: 0x%02x != 0x%02x", + qos1->bis, qos2->bis); + return false; + } + + if (qos1->packing != qos2->packing) { + tester_warn("Unexpected QoS packing: 0x%02x != 0x%02x", + qos1->packing, qos2->packing); + return false; + } + + if (qos1->framing != qos2->framing) { + tester_warn("Unexpected QoS framing: 0x%02x != 0x%02x", + qos1->framing, qos2->framing); + return false; + } + + if (qos1->encryption != qos2->encryption) { + tester_warn("Unexpected QoS encryption: 0x%02x != 0x%02x", + qos1->encryption, qos2->encryption); + return false; + } + + if (memcmp(qos1->bcode, qos2->bcode, sizeof(qos1->bcode))) { + tester_warn("Unexpected QoS Broadcast Code"); + return false; + } + + if (!check_io_qos(&qos1->out, &qos2->out)) { + tester_warn("Unexpected Output QoS"); + return false; + } + + return true; +} + static gboolean iso_recv_data(GIOChannel *io, GIOCondition cond, gpointer user_data) { @@ -1249,14 +1358,28 @@ static gboolean iso_connect(GIOChannel *io, GIOCondition cond, const struct iso_client_data *isodata = data->test_data; int err, sk_err, sk; socklen_t len; - struct bt_iso_qos qos; + int optname; + bool ret = true; + + union { + struct bt_iso_unicast_qos unicast_qos; + struct bt_iso_bcast_sink_qos sink_qos; + struct bt_iso_bcast_source_qos source_qos; + } qos; sk = g_io_channel_unix_get_fd(io); + if (!isodata->bcast) + optname = BT_ISO_UNICAST_QOS; + else if (isodata->server) + optname = BT_ISO_BCAST_SINK_QOS; + else + optname = BT_ISO_BCAST_SOURCE_QOS; + len = sizeof(qos); memset(&qos, 0, len); - err = getsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &qos, &len); + err = getsockopt(sk, SOL_BLUETOOTH, optname, &qos, &len); if (err < 0) { tester_warn("Can't get socket option : %s (%d)", strerror(errno), errno); @@ -1264,7 +1387,14 @@ static gboolean iso_connect(GIOChannel *io, GIOCondition cond, return FALSE; } - if (!check_qos(&qos, &isodata->qos)) { + if (!isodata->bcast) + ret = check_unicast_qos(&qos.unicast_qos, + &isodata->unicast_qos); + else if (!isodata->server) + ret = check_bcast_source_qos(&qos.source_qos, + &isodata->source_qos); + + if (!ret) { tester_warn("Unexpected QoS parameter"); tester_test_failed(); return FALSE; @@ -1579,7 +1709,7 @@ static void setup_listen(struct test_data *data, uint8_t num, GIOFunc func) client = hciemu_get_client(data->hciemu, 0); host = hciemu_client_host(client); - bthost_set_cig_params(host, 0x01, 0x01, &isodata->qos); + bthost_set_cig_params(host, 0x01, 0x01, &isodata->unicast_qos); bthost_create_cis(host, 257, data->acl_handle); } } -- 2.34.1