From c4d9b99db5a6b8efb7b710818a5261634086824b Mon Sep 17 00:00:00 2001 From: Iulia Tanasescu Date: Fri, 31 Mar 2023 18:39:27 +0300 Subject: Split bt_iso_qos into dedicated structures Split bt_iso_qos into dedicated unicast and broadcast structures and add additional broadcast parameters. --- tools/btiotest.c | 17 +++-- tools/iso-tester.c | 199 +++++++++++++++++++++++++++++++++++++++++++++-------- tools/isotest.c | 157 +++++++++++++++++++++++++++++------------- 3 files changed, 291 insertions(+), 82 deletions(-) (limited to 'tools') diff --git a/tools/btiotest.c b/tools/btiotest.c index 193e1395b..75af90543 100644 --- a/tools/btiotest.c +++ b/tools/btiotest.c @@ -5,6 +5,7 @@ * * Copyright (C) 2009-2010 Marcel Holtmann * Copyright (C) 2009-2010 Nokia Corporation + * Copyright 2023 NXP * * */ @@ -39,13 +40,15 @@ static int opt_update_sec = 0; } struct bt_iso_qos qos = { - .cig = BT_ISO_QOS_CIG_UNSET, - .cis = BT_ISO_QOS_CIG_UNSET, - .sca = 0x07, - .packing = 0x00, - .framing = 0x00, - .in = DEFAULT_IO_QOS, - .out = DEFAULT_IO_QOS, + .ucast = { + .cig = BT_ISO_QOS_CIG_UNSET, + .cis = BT_ISO_QOS_CIG_UNSET, + .sca = 0x07, + .packing = 0x00, + .framing = 0x00, + .in = DEFAULT_IO_QOS, + .out = DEFAULT_IO_QOS, + }, }; struct io_data { diff --git a/tools/iso-tester.c b/tools/iso-tester.c index e4582573a..0f10f8940 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 * */ @@ -42,13 +43,15 @@ #define QOS_FULL(_cig, _cis, _in, _out) \ { \ - .cig = _cig, \ - .cis = _cis, \ - .sca = 0x07, \ - .packing = 0x00, \ - .framing = 0x00, \ - .in = _in, \ - .out = _out, \ + .ucast = { \ + .cig = _cig, \ + .cis = _cis, \ + .sca = 0x07, \ + .packing = 0x00, \ + .framing = 0x00, \ + .in = _in, \ + .out = _out, \ + },\ } #define QOS(_interval, _latency, _sdu, _phy, _rtn) \ @@ -119,10 +122,47 @@ #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_BCAST_FULL(_big, _bis, _in, _out) \ +{ \ + .bcast = { \ + .big = _big, \ + .bis = _bis, \ + .sync_interval = 0x07, \ + .packing = 0x00, \ + .framing = 0x00, \ + .in = _in, \ + .out = _out, \ + .encryption = 0x00, \ + .bcode = {0}, \ + .options = 0x00, \ + .skip = 0x0000, \ + .sync_timeout = 0x4000, \ + .sync_cte_type = 0x00, \ + .mse = 0x00, \ + .timeout = 0x4000, \ + }, \ +} + +#define BCAST_QOS_OUT(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_BCAST_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_BCAST_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_BCAST_FULL(0x01, 0x01, \ + {}, QOS_IO(_interval, _latency, _sdu, _phy, _rtn)) + +#define BCAST_QOS_IN(_interval, _latency, _sdu, _phy, _rtn) \ + QOS_BCAST_FULL(BT_ISO_QOS_BIG_UNSET, BT_ISO_QOS_BIS_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; @@ -670,6 +710,7 @@ static const struct iso_client_data bcast_16_2_1_recv = { .expect_err = 0, .recv = &send_16_2_1, .bcast = true, + .server = true, }; static void client_connectable_complete(uint16_t opcode, uint8_t status, @@ -1080,43 +1121,43 @@ static bool check_io_qos(const struct bt_iso_io_qos *io1, return true; } -static bool check_qos(const struct bt_iso_qos *qos1, +static bool check_ucast_qos(const struct bt_iso_qos *qos1, const struct bt_iso_qos *qos2) { - if (qos1->cig != BT_ISO_QOS_CIG_UNSET && - qos2->cig != BT_ISO_QOS_CIG_UNSET && - qos1->cig != qos2->cig) { + if (qos1->ucast.cig != BT_ISO_QOS_CIG_UNSET && + qos2->ucast.cig != BT_ISO_QOS_CIG_UNSET && + qos1->ucast.cig != qos2->ucast.cig) { tester_warn("Unexpected CIG ID: 0x%02x != 0x%02x", - qos1->cig, qos2->cig); + qos1->ucast.cig, qos2->ucast.cig); return false; } - if (qos1->cis != BT_ISO_QOS_CIS_UNSET && - qos2->cis != BT_ISO_QOS_CIS_UNSET && - qos1->cis != qos2->cis) { + if (qos1->ucast.cis != BT_ISO_QOS_CIS_UNSET && + qos2->ucast.cis != BT_ISO_QOS_CIS_UNSET && + qos1->ucast.cis != qos2->ucast.cis) { tester_warn("Unexpected CIS ID: 0x%02x != 0x%02x", - qos1->cis, qos2->cis); + qos1->ucast.cis, qos2->ucast.cis); return false; } - if (qos1->packing != qos2->packing) { + if (qos1->ucast.packing != qos2->ucast.packing) { tester_warn("Unexpected QoS packing: 0x%02x != 0x%02x", - qos1->packing, qos2->packing); + qos1->ucast.packing, qos2->ucast.packing); return false; } - if (qos1->framing != qos2->framing) { + if (qos1->ucast.framing != qos2->ucast.framing) { tester_warn("Unexpected QoS framing: 0x%02x != 0x%02x", - qos1->framing, qos2->framing); + qos1->ucast.framing, qos2->ucast.framing); return false; } - if (!check_io_qos(&qos1->in, &qos2->in)) { + if (!check_io_qos(&qos1->ucast.in, &qos2->ucast.in)) { tester_warn("Unexpected Input QoS"); return false; } - if (!check_io_qos(&qos1->out, &qos2->out)) { + if (!check_io_qos(&qos1->ucast.out, &qos2->ucast.out)) { tester_warn("Unexpected Output QoS"); return false; } @@ -1124,6 +1165,104 @@ static bool check_qos(const struct bt_iso_qos *qos1, return true; } +static bool check_bcast_qos(const struct bt_iso_qos *qos1, + const struct bt_iso_qos *qos2) +{ + if (qos1->bcast.big != BT_ISO_QOS_BIG_UNSET && + qos2->bcast.big != BT_ISO_QOS_BIG_UNSET && + qos1->bcast.big != qos2->bcast.big) { + tester_warn("Unexpected BIG ID: 0x%02x != 0x%02x", + qos1->bcast.big, qos2->bcast.big); + return false; + } + + if (qos1->bcast.bis != BT_ISO_QOS_BIS_UNSET && + qos2->bcast.bis != BT_ISO_QOS_BIS_UNSET && + qos1->bcast.bis != qos2->bcast.bis) { + tester_warn("Unexpected BIS ID: 0x%02x != 0x%02x", + qos1->bcast.bis, qos2->bcast.bis); + return false; + } + + if (qos1->bcast.sync_interval != qos2->bcast.sync_interval) { + tester_warn("Unexpected QoS sync interval: 0x%02x != 0x%02x", + qos1->bcast.sync_interval, qos2->bcast.sync_interval); + return false; + } + + if (qos1->bcast.packing != qos2->bcast.packing) { + tester_warn("Unexpected QoS packing: 0x%02x != 0x%02x", + qos1->bcast.packing, qos2->bcast.packing); + return false; + } + + if (qos1->bcast.framing != qos2->bcast.framing) { + tester_warn("Unexpected QoS framing: 0x%02x != 0x%02x", + qos1->bcast.framing, qos2->bcast.framing); + return false; + } + + if (!check_io_qos(&qos1->ucast.in, &qos2->ucast.in)) { + tester_warn("Unexpected Input QoS"); + return false; + } + + if (!check_io_qos(&qos1->ucast.out, &qos2->ucast.out)) { + tester_warn("Unexpected Output QoS"); + return false; + } + + if (qos1->bcast.encryption != qos2->bcast.encryption) { + tester_warn("Unexpected QoS encryption: 0x%02x != 0x%02x", + qos1->bcast.encryption, qos2->bcast.encryption); + return false; + } + + if (memcmp(qos1->bcast.bcode, qos2->bcast.bcode, + sizeof(qos1->bcast.bcode))) { + tester_warn("Unexpected QoS Broadcast Code"); + return false; + } + + if (qos1->bcast.options != qos2->bcast.options) { + tester_warn("Unexpected QoS options: 0x%02x != 0x%02x", + qos1->bcast.options, qos2->bcast.options); + return false; + } + + if (qos1->bcast.skip != qos2->bcast.skip) { + tester_warn("Unexpected QoS skip: 0x%04x != 0x%04x", + qos1->bcast.skip, qos2->bcast.skip); + return false; + } + + if (qos1->bcast.sync_timeout != qos2->bcast.sync_timeout) { + tester_warn("Unexpected QoS sync timeout: 0x%04x != 0x%04x", + qos1->bcast.sync_timeout, qos2->bcast.sync_timeout); + return false; + } + + if (qos1->bcast.sync_cte_type != qos2->bcast.sync_cte_type) { + tester_warn("Unexpected QoS sync cte type: 0x%02x != 0x%02x", + qos1->bcast.sync_cte_type, qos2->bcast.sync_cte_type); + return false; + } + + if (qos1->bcast.mse != qos2->bcast.mse) { + tester_warn("Unexpected QoS MSE: 0x%02x != 0x%02x", + qos1->bcast.mse, qos2->bcast.mse); + return false; + } + + if (qos1->bcast.timeout != qos2->bcast.timeout) { + tester_warn("Unexpected QoS MSE: 0x%04x != 0x%04x", + qos1->bcast.timeout, qos2->bcast.timeout); + return false; + } + + return true; +} + static gboolean iso_recv_data(GIOChannel *io, GIOCondition cond, gpointer user_data) { @@ -1250,6 +1389,7 @@ static gboolean iso_connect(GIOChannel *io, GIOCondition cond, int err, sk_err, sk; socklen_t len; struct bt_iso_qos qos; + bool ret = true; sk = g_io_channel_unix_get_fd(io); @@ -1264,7 +1404,12 @@ static gboolean iso_connect(GIOChannel *io, GIOCondition cond, return FALSE; } - if (!check_qos(&qos, &isodata->qos)) { + if (!isodata->bcast) + ret = check_ucast_qos(&qos, &isodata->qos); + else if (!isodata->server) + ret = check_bcast_qos(&qos, &isodata->qos); + + if (!ret) { tester_warn("Unexpected QoS parameter"); tester_test_failed(); return FALSE; diff --git a/tools/isotest.c b/tools/isotest.c index 2b5f164de..cd7094b1c 100644 --- a/tools/isotest.c +++ b/tools/isotest.c @@ -4,6 +4,7 @@ * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2022 Intel Corporation. + * Copyright 2023 NXP * */ @@ -239,7 +240,7 @@ fail: return err < 0 ? err : 0; } -static void print_qos(int sk, struct sockaddr_iso *addr) +static void print_ucast_qos(int sk) { struct bt_iso_qos qos; socklen_t len; @@ -254,21 +255,63 @@ static void print_qos(int sk, struct sockaddr_iso *addr) return; } - if (!bacmp(&addr->iso_bdaddr, BDADDR_ANY)) { - syslog(LOG_INFO, "QoS BIG 0x%02x BIS 0x%02x Packing 0x%02x " - "Framing 0x%02x]", qos.big, qos.bis, qos.packing, - qos.framing); - } else { - syslog(LOG_INFO, "QoS CIG 0x%02x CIS 0x%02x Packing 0x%02x " - "Framing 0x%02x]", qos.cig, qos.cis, qos.packing, - qos.framing); - syslog(LOG_INFO, "Input QoS [Interval %u us Latency %u " - "ms SDU %u PHY 0x%02x RTN %u]", qos.in.interval, - qos.in.latency, qos.in.sdu, qos.in.phy, qos.in.rtn); + syslog(LOG_INFO, "QoS CIG 0x%02x CIS 0x%02x Packing 0x%02x " + "Framing 0x%02x]", qos.ucast.cig, qos.ucast.cis, + qos.ucast.packing, qos.ucast.framing); + + syslog(LOG_INFO, "Input QoS [Interval %u us Latency %u " + "ms SDU %u PHY 0x%02x RTN %u]", qos.ucast.in.interval, + qos.ucast.in.latency, qos.ucast.in.sdu, qos.ucast.in.phy, + qos.ucast.in.rtn); + + syslog(LOG_INFO, "Output QoS [Interval %u us Latency %u " + "ms SDU %u PHY 0x%02x RTN %u]", qos.ucast.out.interval, + qos.ucast.out.latency, qos.ucast.out.sdu, qos.ucast.out.phy, + qos.ucast.out.rtn); +} + +static void print_bcast_qos(int sk) +{ + struct bt_iso_qos qos; + socklen_t len; + + /* Read Out QOS */ + memset(&qos, 0, sizeof(qos)); + len = sizeof(qos); + + if (getsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &qos, &len) < 0) { + syslog(LOG_ERR, "Can't get QoS socket option: %s (%d)", + strerror(errno), errno); + return; } + + syslog(LOG_INFO, "QoS BIG 0x%02x BIS 0x%02x Packing 0x%02x " + "Framing 0x%02x]", qos.bcast.big, qos.bcast.bis, + qos.bcast.packing, qos.bcast.framing); + + syslog(LOG_INFO, "Input QoS [Interval %u us Latency %u " + "ms SDU %u PHY 0x%02x RTN %u]", qos.bcast.in.interval, + qos.bcast.in.latency, qos.bcast.in.sdu, + qos.bcast.in.phy, qos.bcast.in.rtn); + syslog(LOG_INFO, "Output QoS [Interval %u us Latency %u " - "ms SDU %u PHY 0x%02x RTN %u]", qos.out.interval, - qos.out.latency, qos.out.sdu, qos.out.phy, qos.out.rtn); + "ms SDU %u PHY 0x%02x RTN %u]", qos.bcast.out.interval, + qos.bcast.out.latency, qos.bcast.out.sdu, + qos.bcast.out.phy, qos.bcast.out.rtn); +} + +static void convert_ucast_qos_to_bcast(struct bt_iso_qos *qos) +{ + iso_qos->bcast.in.phy = 0x00; + iso_qos->bcast.in.sdu = 0; + qos->bcast.encryption = 0x00; + memset(qos->bcast.bcode, 0, sizeof(qos->bcast.bcode)); + qos->bcast.options = 0x00; + qos->bcast.skip = 0x0000; + qos->bcast.sync_timeout = 0x4000; + qos->bcast.sync_cte_type = 0x00; + qos->bcast.mse = 0x00; + qos->bcast.timeout = 0x4000; } static int do_connect(char *peer) @@ -301,9 +344,13 @@ static int do_connect(char *peer) /* Set QoS if available */ if (iso_qos) { - if (!inout || !strcmp(peer, "00:00:00:00:00:00")) { - iso_qos->in.phy = 0x00; - iso_qos->in.sdu = 0; + if (!strcmp(peer, "00:00:00:00:00:00")) { + convert_ucast_qos_to_bcast(iso_qos); + } else { + if (!inout) { + iso_qos->ucast.in.phy = 0x00; + iso_qos->ucast.in.sdu = 0; + } } if (setsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, iso_qos, @@ -338,7 +385,10 @@ static int do_connect(char *peer) syslog(LOG_INFO, "Connected [%s]", peer); - print_qos(sk, &addr); + if (!strcmp(peer, "00:00:00:00:00:00")) + print_bcast_qos(sk); + else + print_ucast_qos(sk); return sk; @@ -441,7 +491,10 @@ static void do_listen(char *filename, void (*handler)(int fd, int sk), ba2str(&addr->iso_bdaddr, ba); syslog(LOG_INFO, "Connected [%s]", ba); - print_qos(nsk, addr); + if (peer) + print_bcast_qos(nsk); + else + print_ucast_qos(nsk); /* Handle deferred setup */ if (defer_setup) { @@ -648,7 +701,7 @@ static int read_file(int fd, ssize_t count, bool rewind) return len; } -static void do_send(int sk, int fd, struct bt_iso_qos *qos, uint32_t num, +static void do_send(int sk, int fd, struct bt_iso_io_qos *out, uint32_t num, bool repeat) { uint32_t seq; @@ -662,14 +715,14 @@ static void do_send(int sk, int fd, struct bt_iso_qos *qos, uint32_t num, for (seq = 0; ; seq++) { if (fd >= 0) { - len = read_file(fd, qos->out.sdu, repeat); + len = read_file(fd, out->sdu, repeat); if (len < 0) { syslog(LOG_ERR, "read failed: %s (%d)", strerror(-len), -len); exit(1); } } else - len = qos->out.sdu; + len = out->sdu; len = send(sk, buf, len, 0); if (len <= 0) { @@ -686,7 +739,7 @@ static void do_send(int sk, int fd, struct bt_iso_qos *qos, uint32_t num, seq, len, used / len, used); if (seq && !((seq + 1) % num)) - send_wait(&t_start, num * qos->out.interval); + send_wait(&t_start, num * out->interval); } } @@ -696,6 +749,7 @@ static void send_mode(char *filename, char *peer, int i, bool repeat) socklen_t len; int sk, fd = -1; uint32_t num; + struct bt_iso_io_qos *out; if (filename) { char altername[PATH_MAX]; @@ -728,16 +782,21 @@ static void send_mode(char *filename, char *peer, int i, bool repeat) syslog(LOG_INFO, "Sending ..."); /* Read QoS */ + if (!strcmp(peer, "00:00:00:00:00:00")) + out = &qos.bcast.out; + else + out = &qos.ucast.out; + memset(&qos, 0, sizeof(qos)); len = sizeof(qos); if (getsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &qos, &len) < 0) { syslog(LOG_ERR, "Can't get Output QoS socket option: %s (%d)", strerror(errno), errno); - qos.out.sdu = ISO_DEFAULT_MTU; + out->sdu = ISO_DEFAULT_MTU; } /* num of packets = latency (ms) / interval (us) */ - num = (qos.out.latency * 1000 / qos.out.interval); + num = (out->latency * 1000 / out->interval); syslog(LOG_INFO, "Number of packets: %d", num); @@ -746,8 +805,8 @@ static void send_mode(char *filename, char *peer, int i, bool repeat) * latency: * jitter buffer = 2 * (SDU * subevents) */ - sndbuf = 2 * ((qos.out.latency * 1000 / qos.out.interval) * - qos.out.sdu); + sndbuf = 2 * ((out->latency * 1000 / out->interval) * + out->sdu); len = sizeof(sndbuf); if (setsockopt(sk, SOL_SOCKET, SO_SNDBUF, &sndbuf, len) < 0) { @@ -768,10 +827,10 @@ static void send_mode(char *filename, char *peer, int i, bool repeat) } } - for (i = 6; i < qos.out.sdu; i++) + for (i = 6; i < out->sdu; i++) buf[i] = 0x7f; - do_send(sk, fd, &qos, num, repeat); + do_send(sk, fd, out, num, repeat); } static void reconnect_mode(char *peer) @@ -826,12 +885,14 @@ static void multy_connect_mode(char *peer) #define QOS(_interval, _latency, _sdu, _phy, _rtn) \ { \ - .cig = BT_ISO_QOS_CIG_UNSET, \ - .cis = BT_ISO_QOS_CIS_UNSET, \ - .sca = 0x07, \ - .packing = 0x00, \ - .framing = 0x00, \ - .out = QOS_IO(_interval, _latency, _sdu, _phy, _rtn), \ + .ucast = { \ + .cig = BT_ISO_QOS_CIG_UNSET, \ + .cis = BT_ISO_QOS_CIS_UNSET, \ + .sca = 0x07, \ + .packing = 0x00, \ + .framing = 0x00, \ + .out = QOS_IO(_interval, _latency, _sdu, _phy, _rtn), \ + }, \ } #define QOS_PRESET(_name, _inout, _interval, _latency, _sdu, _phy, _rtn) \ @@ -1057,43 +1118,43 @@ int main(int argc, char *argv[]) case 'M': if (optarg) - iso_qos->out.sdu = atoi(optarg); + iso_qos->ucast.out.sdu = atoi(optarg); break; case 'S': if (optarg) - iso_qos->sca = atoi(optarg); + iso_qos->ucast.sca = atoi(optarg); break; case 'P': if (optarg) - iso_qos->packing = atoi(optarg); + iso_qos->ucast.packing = atoi(optarg); break; case 'F': if (optarg) - iso_qos->framing = atoi(optarg); + iso_qos->ucast.framing = atoi(optarg); break; case 'I': if (optarg) - iso_qos->out.interval = atoi(optarg); + iso_qos->ucast.out.interval = atoi(optarg); break; case 'L': if (optarg) - iso_qos->out.latency = atoi(optarg); + iso_qos->ucast.out.latency = atoi(optarg); break; case 'Y': if (optarg) - iso_qos->out.phy = atoi(optarg); + iso_qos->ucast.out.phy = atoi(optarg); break; case 'R': if (optarg) - iso_qos->out.rtn = atoi(optarg); + iso_qos->ucast.out.rtn = atoi(optarg); break; case 'B': @@ -1112,12 +1173,12 @@ int main(int argc, char *argv[]) case 'G': if (optarg) - iso_qos->cig = atoi(optarg); + iso_qos->ucast.cig = atoi(optarg); break; case 'T': if (optarg) - iso_qos->cis = atoi(optarg); + iso_qos->ucast.cis = atoi(optarg); break; /* fall through */ @@ -1128,11 +1189,11 @@ int main(int argc, char *argv[]) } if (inout) { - iso_qos->in = iso_qos->out; + iso_qos->ucast.in = iso_qos->ucast.out; } else { /* Align interval and latency even if is unidirectional */ - iso_qos->in.interval = iso_qos->out.interval; - iso_qos->in.latency = iso_qos->out.latency; + iso_qos->ucast.in.interval = iso_qos->ucast.out.interval; + iso_qos->ucast.in.latency = iso_qos->ucast.out.latency; } buf = malloc(data_size); -- cgit v1.2.1