Split bt_iso_qos into dedicated structures
authorIulia Tanasescu <iulia.tanasescu@nxp.com>
Fri, 31 Mar 2023 15:39:27 +0000 (18:39 +0300)
committerAyush Garg <ayush.garg@samsung.com>
Fri, 5 Jan 2024 10:41:34 +0000 (16:11 +0530)
Split bt_iso_qos into dedicated unicast and broadcast
structures and add additional broadcast parameters.

btio/btio.c
client/player.c
emulator/bthost.c
lib/bluetooth.h
profiles/audio/bap.c
tools/btiotest.c
tools/iso-tester.c
tools/isotest.c

index bc32033..94e8023 100755 (executable)
@@ -5,6 +5,7 @@
  *
  *  Copyright (C) 2009-2010  Marcel Holtmann <marcel@holtmann.org>
  *  Copyright (C) 2009-2010  Nokia Corporation
+ *  Copyright 2023 NXP
  *
  *
  */
@@ -1608,13 +1609,13 @@ static gboolean iso_get(int sock, GError **err, BtIOOption opt1, va_list args)
                        *(va_arg(args, uint8_t *)) = dst.iso_bdaddr_type;
                        break;
                case BT_IO_OPT_MTU:
-                       *(va_arg(args, uint16_t *)) = qos.out.sdu;
+                       *(va_arg(args, uint16_t *)) = qos.ucast.out.sdu;
                        break;
                case BT_IO_OPT_IMTU:
-                       *(va_arg(args, uint16_t *)) = qos.in.sdu;
+                       *(va_arg(args, uint16_t *)) = qos.ucast.in.sdu;
                        break;
                case BT_IO_OPT_OMTU:
-                       *(va_arg(args, uint16_t *)) = qos.out.sdu;
+                       *(va_arg(args, uint16_t *)) = qos.ucast.out.sdu;
                        break;
                case BT_IO_OPT_PHY:
                        if (get_phy(sock, &phy) < 0) {
index efb87d1..3894ebf 100644 (file)
@@ -4,6 +4,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2020  Intel Corporation. All rights reserved.
+ *  Copyright 2023 NXP
  *
  *
  */
@@ -3533,7 +3534,7 @@ static bool transport_timer_read(struct io *io, void *user_data)
        }
 
        /* num of packets = latency (ms) / interval (us) */
-       num = (qos.out.latency * 1000 / qos.out.interval);
+       num = (qos.ucast.out.latency * 1000 / qos.ucast.out.interval);
 
        ret = transport_send_seq(transport, transport->fd, num);
        if (ret < 0) {
@@ -3569,8 +3570,8 @@ static int transport_send(struct transport *transport, int fd,
                return -errno;
 
        memset(&ts, 0, sizeof(ts));
-       ts.it_value.tv_nsec = qos->out.latency * 1000000;
-       ts.it_interval.tv_nsec = qos->out.latency * 1000000;
+       ts.it_value.tv_nsec = qos->ucast.out.latency * 1000000;
+       ts.it_interval.tv_nsec = qos->ucast.out.latency * 1000000;
 
        if (timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &ts, NULL) < 0)
                return -errno;
index cd0b33e..1fadfde 100755 (executable)
@@ -5,6 +5,7 @@
  *
  *  Copyright (C) 2011-2012  Intel Corporation
  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright 2023 NXP
  *
  *
  */
@@ -3177,22 +3178,24 @@ void bthost_set_cig_params(struct bthost *bthost, uint8_t cig_id,
        cp = malloc(sizeof(*cp) + sizeof(*cp->cis));
        memset(cp, 0, sizeof(*cp) + sizeof(*cp->cis));
        cp->cig_id = cig_id;
-       put_le24(qos->in.interval ? qos->in.interval : qos->out.interval,
-                                                       cp->c_interval);
-       put_le24(qos->out.interval ? qos->out.interval : qos->in.interval,
-                                                       cp->p_interval);
-       cp->c_latency = cpu_to_le16(qos->in.latency ? qos->in.latency :
-                                                       qos->out.latency);
-       cp->p_latency = cpu_to_le16(qos->out.latency ? qos->out.latency :
-                                                       qos->in.latency);
+       put_le24(qos->ucast.in.interval ? qos->ucast.in.interval :
+                               qos->ucast.out.interval, cp->c_interval);
+       put_le24(qos->ucast.out.interval ? qos->ucast.out.interval :
+                               qos->ucast.in.interval, cp->p_interval);
+       cp->c_latency = cpu_to_le16(qos->ucast.in.latency ?
+                               qos->ucast.in.latency : qos->ucast.out.latency);
+       cp->p_latency = cpu_to_le16(qos->ucast.out.latency ?
+                               qos->ucast.out.latency : qos->ucast.in.latency);
        cp->num_cis = 0x01;
        cp->cis[0].cis_id = cis_id;
-       cp->cis[0].c_sdu = qos->in.sdu;
-       cp->cis[0].p_sdu = qos->out.sdu;
-       cp->cis[0].c_phy = qos->in.phy ? qos->in.phy : qos->out.phy;
-       cp->cis[0].p_phy = qos->out.phy ? qos->out.phy : qos->in.phy;
-       cp->cis[0].c_rtn = qos->in.rtn;
-       cp->cis[0].p_rtn = qos->out.rtn;
+       cp->cis[0].c_sdu = qos->ucast.in.sdu;
+       cp->cis[0].p_sdu = qos->ucast.out.sdu;
+       cp->cis[0].c_phy = qos->ucast.in.phy ? qos->ucast.in.phy :
+                                                       qos->ucast.out.phy;
+       cp->cis[0].p_phy = qos->ucast.out.phy ? qos->ucast.out.phy :
+                                                       qos->ucast.in.phy;
+       cp->cis[0].c_rtn = qos->ucast.in.rtn;
+       cp->cis[0].p_rtn = qos->ucast.out.rtn;
 
        send_command(bthost, BT_HCI_CMD_LE_SET_CIG_PARAMS, cp,
                                sizeof(*cp) + sizeof(*cp->cis));
index aaaa835..16a32b1 100755 (executable)
@@ -6,6 +6,7 @@
  *  Copyright (C) 2000-2001  Qualcomm Incorporated
  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright 2023 NXP
  *
  *
  */
@@ -156,6 +157,9 @@ struct le_conn_param {
 #define BT_ISO_QOS_CIG_UNSET   0xff
 #define BT_ISO_QOS_CIS_UNSET   0xff
 
+#define BT_ISO_QOS_BIG_UNSET   0xff
+#define BT_ISO_QOS_BIS_UNSET   0xff
+
 struct bt_iso_io_qos {
        uint32_t interval;
        uint16_t latency;
@@ -164,25 +168,41 @@ struct bt_iso_io_qos {
        uint8_t  rtn;
 };
 
-struct bt_iso_qos {
-       union {
-               uint8_t  cig;
-               uint8_t  big;
-       };
-       union {
-               uint8_t  cis;
-               uint8_t  bis;
-       };
-       union {
-               uint8_t  sca;
-               uint8_t  sync_interval;
-       };
+struct bt_iso_ucast_qos {
+       uint8_t  cig;
+       uint8_t  cis;
+       uint8_t  sca;
        uint8_t  packing;
        uint8_t  framing;
        struct bt_iso_io_qos in;
        struct bt_iso_io_qos out;
 };
 
+struct bt_iso_bcast_qos {
+       uint8_t  big;
+       uint8_t  bis;
+       uint8_t  sync_interval;
+       uint8_t  packing;
+       uint8_t  framing;
+       struct bt_iso_io_qos in;
+       struct bt_iso_io_qos out;
+       uint8_t  encryption;
+       uint8_t  bcode[16];
+       uint8_t  options;
+       uint16_t skip;
+       uint16_t sync_timeout;
+       uint8_t  sync_cte_type;
+       uint8_t  mse;
+       uint16_t timeout;
+};
+
+struct bt_iso_qos {
+       union {
+               struct bt_iso_ucast_qos ucast;
+               struct bt_iso_bcast_qos bcast;
+       };
+};
+
 #define BT_CODEC               19
 struct bt_codec {
        uint8_t id;
index afafebd..1ad3f9d 100644 (file)
@@ -4,6 +4,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2022  Intel Corporation. All rights reserved.
+ *  Copyright 2023 NXP
  *
  *
  */
@@ -750,10 +751,10 @@ static bool match_stream_qos(const void *data, const void *user_data)
 
        qos = bt_bap_stream_get_qos((void *)stream);
 
-       if (iso_qos->cig != qos->cig_id)
+       if (iso_qos->ucast.cig != qos->cig_id)
                return false;
 
-       return iso_qos->cis == qos->cis_id;
+       return iso_qos->ucast.cis == qos->cis_id;
 }
 
 static void iso_confirm_cb(GIOChannel *io, void *user_data)
@@ -775,7 +776,7 @@ static void iso_confirm_cb(GIOChannel *io, void *user_data)
        }
 
        DBG("ISO: incoming connect from %s (CIG 0x%02x CIS 0x%02x)",
-                                       address, qos.cig, qos.cis);
+                                       address, qos.ucast.cig, qos.ucast.cis);
 
        stream = queue_remove_if(data->streams, match_stream_qos, &qos);
        if (!stream) {
@@ -994,11 +995,11 @@ static void bap_create_io(struct bap_data *data, struct bap_ep *ep,
        }
 
        memset(&iso_qos, 0, sizeof(iso_qos));
-       iso_qos.cig = qos[0] ? qos[0]->cig_id : qos[1]->cig_id;
-       iso_qos.cis = qos[0] ? qos[0]->cis_id : qos[1]->cis_id;
+       iso_qos.ucast.cig = qos[0] ? qos[0]->cig_id : qos[1]->cig_id;
+       iso_qos.ucast.cis = qos[0] ? qos[0]->cis_id : qos[1]->cis_id;
 
-       bap_iso_qos(qos[0], &iso_qos.in);
-       bap_iso_qos(qos[1], &iso_qos.out);
+       bap_iso_qos(qos[0], &iso_qos.ucast.in);
+       bap_iso_qos(qos[1], &iso_qos.ucast.out);
 
        if (ep)
                bap_connect_io(data, ep, stream, &iso_qos, defer);
@@ -1193,8 +1194,8 @@ static void bap_connecting(struct bt_bap_stream *stream, bool state, int fd,
                        return;
                }
 
-               ep->qos.cig_id = qos.cig;
-               ep->qos.cis_id = qos.cis;
+               ep->qos.cig_id = qos.ucast.cig;
+               ep->qos.cis_id = qos.ucast.cis;
        }
 
        DBG("stream %p fd %d: CIG 0x%02x CIS 0x%02x", stream, fd,
index 2ef9656..07a2d06 100755 (executable)
@@ -5,6 +5,7 @@
  *
  *  Copyright (C) 2009-2010  Marcel Holtmann <marcel@holtmann.org>
  *  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 {
index e458257..0f10f89 100644 (file)
@@ -4,6 +4,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2022  Intel Corporation.
+ *  Copyright 2023 NXP
  *
  */
 
 
 #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) \
 #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;
index 0cd000d..8e07b28 100644 (file)
@@ -4,6 +4,7 @@
  *  BlueZ - Bluetooth protocol stack for Linux
  *
  *  Copyright (C) 2022  Intel Corporation.
+ *  Copyright 2023 NXP
  *
  */
 
@@ -242,7 +243,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;
@@ -257,21 +258,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)
@@ -304,9 +347,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,
@@ -341,7 +388,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;
 
@@ -444,7 +494,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) {
@@ -659,7 +712,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;
@@ -673,14 +726,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) {
@@ -697,7 +750,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);
        }
 }
 
@@ -707,6 +760,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];
@@ -739,16 +793,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);
 
@@ -757,8 +816,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) {
@@ -779,10 +838,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)
@@ -837,12 +896,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) \
@@ -1068,43 +1129,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':
@@ -1123,12 +1184,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 */
@@ -1139,11 +1200,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);