diff mbox series

[BlueZ,1/1] isotest: Add support for creating/synchronizing to multiple BISes

Message ID 20230529062734.3685-2-iulia.tanasescu@nxp.com (mailing list archive)
State Accepted
Commit 8ff103f9939798521f06d36dd7bf4e0f7fc2dd08
Headers show
Series isotest: Add support for creating/synchronizing to multiple BISes | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
tedd_an/CheckPatch warning WARNING:COMMIT_LOG_LONG_LINE: Possible unwrapped commit description (prefer a maximum 75 chars per line) #117: isotest[7178]: QoS [BIG 0x01 BIS 0x01 Packing 0x00 Framing 0x00 Encryption 0x00] /github/workspace/src/src/13258247.patch total: 0 errors, 1 warnings, 433 lines checked NOTE: For some of the reported defects, checkpatch may be able to mechanically convert to the typical style using --fix or --fix-inplace. /github/workspace/src/src/13258247.patch has style problems, please review. NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO NOTE: If any of the errors are false positives, please report them to the maintainer, see CHECKPATCH in MAINTAINERS.
tedd_an/GitLint fail WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search 24: B1 Line exceeds max length (81>80): "isotest[7178]: Output QoS [Interval 10000 us Latency 10 ms SDU 40 PHY 0x02 RTN 2]" 29: B1 Line exceeds max length (81>80): "isotest[7178]: Output QoS [Interval 10000 us Latency 10 ms SDU 40 PHY 0x02 RTN 2]" 83: B2 Line has trailing whitespace: " Codec Configuration: " 99: B2 Line has trailing whitespace: " Codec Configuration: " 261: B2 Line has trailing whitespace: " Codec Configuration: " 277: B2 Line has trailing whitespace: " Codec Configuration: "
tedd_an/BuildEll success Build ELL PASS
tedd_an/BluezMake success Bluez Make PASS
tedd_an/MakeCheck success Bluez Make Check PASS
tedd_an/MakeDistcheck success Make Distcheck PASS
tedd_an/CheckValgrind success Check Valgrind PASS
tedd_an/CheckSmatch success CheckSparse PASS
tedd_an/bluezmakeextell success Make External ELL PASS
tedd_an/IncrementalBuild success Incremental Build PASS
tedd_an/ScanBuild success Scan Build PASS

Commit Message

Iulia Tanasescu May 29, 2023, 6:27 a.m. UTC
This adds an additional command line option for the Broadcast exercise,
so that the user can indicate the number of BISes to create as part of a
BIG (Broadcast Source), or the number of BISes to synchronize
to (Broadcast Sink).

For the Broadcast Source exercise, issue the following command,
in order to create a BIG with handle 0x01, associated with the
advertising handle 0x01, with 2 BISes:

    tools/isotest -i hci0 -s 00:00:00:00:00:00 -N 2 -G 1 -T 1

The isotest and btmon logs will look something like this:

isotest[7178]: mgmt socket: fd 3
isotest[7178]: mgmt_set_le: err 0
isotest[7178]: mgmt_set_experimental: err 0
isotest[7179]: Exit
isotest[7178]: Connecting 00:00:00:00:00:00 ...
isotest[7178]: Connected [00:00:00:00:00:00]
isotest[7178]: QoS [BIG 0x01 BIS 0x01 Packing 0x00 Framing 0x00 Encryption 0x00]
isotest[7178]: Input QoS [Interval 10000 us Latency 10 ms SDU 0 PHY 0x00 RTN 2]
isotest[7178]: Output QoS [Interval 10000 us Latency 10 ms SDU 40 PHY 0x02 RTN 2]
isotest[7178]: Connecting 00:00:00:00:00:00 ...
isotest[7178]: Connected [00:00:00:00:00:00]
isotest[7178]: QoS [BIG 0x01 BIS 0x01 Packing 0x00 Framing 0x00 Encryption 0x00]
isotest[7178]: Input QoS [Interval 10000 us Latency 10 ms SDU 0 PHY 0x00 RTN 2]
isotest[7178]: Output QoS [Interval 10000 us Latency 10 ms SDU 40 PHY 0x02 RTN 2]
isotest[7183]: Sending ...
isotest[7183]: Number of packets: 1
isotest[7183]: Socket jitter buffer: 80 buffer
isotest[7183]: [seq 0] 40 bytes buffered 92 (3712 bytes)
isotest[7184]: Sending ...
isotest[7184]: Number of packets: 1
isotest[7184]: Socket jitter buffer: 80 buffer
isotest[7184]: [seq 0] 40 bytes buffered 92 (3712 bytes)
isotest[7178]: Exit

< HCI Command: LE Create Broadcast Isochronous Group (0x08|0x0068) plen 31
        Handle: 0x01
        Advertising Handle: 0x01
        Number of BIS: 2
        SDU Interval: 10000 us (0x002710)
        Maximum SDU size: 40
        Maximum Latency: 10 ms (0x000a)
        RTN: 0x02
        PHY: LE 2M (0x02)
        Packing: Sequential (0x00)
        Framing: Unframed (0x00)
        Encryption: 0x00
        Broadcast Code: 00000000000000000000000000000000

> HCI Event: Command Status (0x0f) plen 4
      LE Create Broadcast Isochronous Group (0x08|0x0068) ncmd 1
        Status: Success (0x00)

> HCI Event: LE Meta Event (0x3e) plen 23
      LE Broadcast Isochronous Group Complete (0x1b)
        Status: Success (0x00)
        Handle: 0x01
        BIG Synchronization Delay: 1974 us (0x0007b6)
        Transport Latency: 1974 us (0x0007b6)
        PHY: LE 2M (0x02)
        NSE: 3
        BN: 1
        PTO: 1
        IRC: 3
        Maximum PDU: 40
        ISO Interval: 10.00 msec (0x0008)
        Connection Handle #0: 10
        Connection Handle #1: 11

< HCI Command: LE Setup Isochronous Data Path (0x08|0x006e) plen 13
        Handle: 10
        Data Path Direction: Input (Host to Controller) (0x00)
        Data Path: HCI (0x00)
        Coding Format: Transparent (0x03)
        Company Codec ID: Ericsson Technology Licensing (0)
        Vendor Codec ID: 0
        Controller Delay: 0 us (0x000000)
        Codec Configuration Length: 0
        Codec Configuration: 

> HCI Event: Command Complete (0x0e) plen 6
      LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1
        Status: Success (0x00)
        Handle: 10

< HCI Command: LE Setup Isochronous Data Path (0x08|0x006e) plen 13
        Handle: 11
        Data Path Direction: Input (Host to Controller) (0x00)
        Data Path: HCI (0x00)
        Coding Format: Transparent (0x03)
        Company Codec ID: Ericsson Technology Licensing (0)
        Vendor Codec ID: 0
        Controller Delay: 0 us (0x000000)
        Codec Configuration Length: 0
        Codec Configuration: 

> HCI Event: Command Complete (0x0e) plen 6
      LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1
        Status: Success (0x00)
        Handle: 11

< ISO Data TX: Handle 10 flags 0x02 dlen 44

< ISO Data TX: Handle 11 flags 0x02 dlen 44

> HCI Event: Number of Completed Packets (0x13) plen 5
        Num handles: 1
        Handle: 10
        Count: 1

> HCI Event: Number of Completed Packets (0x13) plen 5
        Num handles: 1
        Handle: 11
        Count: 1

For the Broadcast Sink exercise, issue the following command,
in order to synchronize to the BISes created by the source:

    tools/isotest -i hci1 -r 36:13:00:E1:1B:F0 -V le_random -N 2 -G 1

The flow is shown by the isotest log and the filtered btmon snippet below:

isotest[4033]: mgmt socket: fd 3
isotest[4034]: Exit
isotest[4033]: mgmt_set_le: err 0
isotest[4033]: mgmt_set_experimental: err 0
isotest[4033]: Waiting for connection 36:13:00:E1:1B:F0...
isotest[4036]: Connected [36:13:00:E1:1B:F0]
isotest[4036]: QoS [BIG 0x01 BIS 0x00 Packing 0x00 Framing 0x00 Encryption 0x00]
isotest[4036]: Input QoS [Interval 1974 us Latency 10 ms SDU 40 PHY 0x00 RTN 0]
isotest[4036]: Output QoS [Interval 0 us Latency 0 ms SDU 0 PHY 0x00 RTN 0]
isotest[4036]: Receiving ...
isotest[4037]: Connected [36:13:00:E1:1B:F0]
isotest[4037]: QoS [BIG 0x01 BIS 0x00 Packing 0x00 Framing 0x00 Encryption 0x00]
isotest[4037]: Input QoS [Interval 1974 us Latency 10 ms SDU 40 PHY 0x00 RTN 0]
isotest[4037]: Output QoS [Interval 0 us Latency 0 ms SDU 0 PHY 0x00 RTN 0]
isotest[4037]: Receiving ...
isotest[4037]: [seq 0] 280 bytes in 6.48 sec speed 0.34 kb/s
isotest[4036]: [seq 0] 280 bytes in 6.54 sec speed 0.33 kb/s
isotest[4037]: [seq 1] 280 bytes in 7.01 sec speed 0.31 kb/s
isotest[4036]: [seq 1] 280 bytes in 7.02 sec speed 0.31 kb/s
isotest[4037]: [seq 2] 280 bytes in 7.06 sec speed 0.31 kb/s
isotest[4036]: [seq 2] 280 bytes in 7.04 sec speed 0.31 kb/s

< HCI Command: LE Periodic Advertising Create Sync (0x08|0x0044) plen 14
        Options: 0x0000
        Use advertising SID, Advertiser Address Type and address
        Reporting initially enabled
        SID: 0x00
        Adv address type: Random (0x01)
        Adv address: 36:13:00:E1:1B:F0 (Non-Resolvable)
        Skip: 0x0000
        Sync timeout: 163840 msec (0x4000)
        Sync CTE type: 0x0000

> HCI Event: Command Status (0x0f) plen 4
      LE Periodic Advertising Create Sync (0x08|0x0044) ncmd 1
        Status: Success (0x00)

< HCI Command: LE Set Extended Scan Parameters (0x08|0x0041) plen 13
        Own address type: Public (0x00)
        Filter policy: Ignore not in accept list (0x01)
        PHYs: 0x05
        Entry 0: LE 1M
          Type: Passive (0x00)
          Interval: 60.000 msec (0x0060)
          Window: 30.000 msec (0x0030)
        Entry 1: LE Coded
          Type: Passive (0x00)
          Interval: 60.000 msec (0x0060)
          Window: 30.000 msec (0x0030)

> HCI Event: Command Complete (0x0e) plen 4
      LE Set Extended Scan Parameters (0x08|0x0041) ncmd 1
        Status: Success (0x00)

< HCI Command: LE Set Extended Scan Enable (0x08|0x0042) plen 6
        Extended scan: Enabled (0x01)
        Filter duplicates: Enabled (0x01)
        Duration: 0 msec (0x0000)
        Period: 0.00 sec (0x0000)

> HCI Event: Command Complete (0x0e) plen 4
      LE Set Extended Scan Enable (0x08|0x0042) ncmd 1
        Status: Success (0x00)

> HCI Event: LE Meta Event (0x3e) plen 16
      LE Periodic Advertising Sync Established (0x0e)
        Status: Success (0x00)
        Sync handle: 0
        Advertising SID: 0x00
        Advertiser address type: Random (0x01)
        Advertiser address: 36:13:00:E1:1B:F0 (Non-Resolvable)
        Advertiser PHY: LE 2M (0x02)
        Periodic advertising interval: 10.00 msec (0x0008)
        Advertiser clock accuracy: 0x00

> HCI Event: LE Meta Event (0x3e) plen 8
      LE Periodic Advertising Report (0x0f)
        Sync handle: 0
        TX power: 127 dbm (0x7f)
        RSSI: -47 dBm (0xd1)
        CTE Type: No Constant Tone Extension (0xff)
        Data status: Complete
        Data length: 0x00

> HCI Event: LE Meta Event (0x3e) plen 20
      LE Broadcast Isochronous Group Info Advertising Report (0x22)
        Sync Handle: 0x0000
        Number BIS: 2
        NSE: 3
        ISO Interval: 10.00 msec (0x0008)
        BN: 1
        PTO: 1
        IRC: 3
        Maximum PDU: 40
        SDU Interval: 10000 us (0x002710)
        Maximum SDU: 40
        PHY: LE 2M (0x02)
        Framing: Unframed (0x00)
        Encryption: 0x00

< HCI Command: LE Broadcast Isochronous Group Create Sync (0x08|0x006b) plen 26
        BIG Handle: 0x01
        BIG Sync Handle: 0x0000
        Encryption: Unencrypted (0x00)
        Broadcast Code: 00000000000000000000000000000000
        Maximum Number Subevents: 0x00
        Timeout: 163840 ms (0x4000)
        Number of BIS: 2
        BIS ID: 0x01
        BIS ID: 0x02

> HCI Event: LE Meta Event (0x3e) plen 19
      LE Broadcast Isochronous Group Sync Estabilished (0x1d)
        Status: Success (0x00)
        BIG Handle: 0x01
        Transport Latency: 1974 us (0x0007b6)
        NSE: 3
        BN: 1
        PTO: 1
        IRC: 3
        Maximum PDU: 40
        ISO Interval: 10.00 msec (0x0008)
        Connection Handle #0: 10
        Connection Handle #1: 11

< HCI Command: LE Setup Isochronous Data Path (0x08|0x006e) plen 13
        Handle: 10
        Data Path Direction: Output (Controller to Host) (0x01)
        Data Path: HCI (0x00)
        Coding Format: Transparent (0x03)
        Company Codec ID: Ericsson Technology Licensing (0)
        Vendor Codec ID: 0
        Controller Delay: 0 us (0x000000)
        Codec Configuration Length: 0
        Codec Configuration: 

> HCI Event: Command Complete (0x0e) plen 6
      LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1
        Status: Success (0x00)
        Handle: 10

< HCI Command: LE Setup Isochronous Data Path (0x08|0x006e) plen 13
        Handle: 11
        Data Path Direction: Output (Controller to Host) (0x01)
        Data Path: HCI (0x00)
        Coding Format: Transparent (0x03)
        Company Codec ID: Ericsson Technology Licensing (0)
        Vendor Codec ID: 0
        Controller Delay: 0 us (0x000000)
        Codec Configuration Length: 0
        Codec Configuration: 

> HCI Event: Command Complete (0x0e) plen 6
      LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1
        Status: Success (0x00)
        Handle: 11

> ISO Data RX: Handle 10 flags 0x06 dlen 48

> ISO Data RX: Handle 11 flags 0x06 dlen 48

---
 tools/isotest.c   | 290 ++++++++++++++++++++++++++++++++++------------
 tools/isotest.rst |   4 +
 2 files changed, 218 insertions(+), 76 deletions(-)

Comments

bluez.test.bot@gmail.com May 29, 2023, 7:44 a.m. UTC | #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=751752

---Test result---

Test Summary:
CheckPatch                    FAIL      0.97 seconds
GitLint                       FAIL      0.55 seconds
BuildEll                      PASS      30.88 seconds
BluezMake                     PASS      952.83 seconds
MakeCheck                     PASS      12.78 seconds
MakeDistcheck                 PASS      176.93 seconds
CheckValgrind                 PASS      293.06 seconds
CheckSmatch                   PASS      389.15 seconds
bluezmakeextell               PASS      117.00 seconds
IncrementalBuild              PASS      783.28 seconds
ScanBuild                     PASS      1202.15 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[BlueZ,1/1] isotest: Add support for creating/synchronizing to multiple BISes
WARNING:COMMIT_LOG_LONG_LINE: Possible unwrapped commit description (prefer a maximum 75 chars per line)
#117: 
isotest[7178]: QoS [BIG 0x01 BIS 0x01 Packing 0x00 Framing 0x00 Encryption 0x00]

/github/workspace/src/src/13258247.patch total: 0 errors, 1 warnings, 433 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/src/13258247.patch has style problems, please review.

NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[BlueZ,1/1] isotest: Add support for creating/synchronizing to multiple BISes

WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
24: B1 Line exceeds max length (81>80): "isotest[7178]: Output QoS [Interval 10000 us Latency 10 ms SDU 40 PHY 0x02 RTN 2]"
29: B1 Line exceeds max length (81>80): "isotest[7178]: Output QoS [Interval 10000 us Latency 10 ms SDU 40 PHY 0x02 RTN 2]"
83: B2 Line has trailing whitespace: "        Codec Configuration: "
99: B2 Line has trailing whitespace: "        Codec Configuration: "
261: B2 Line has trailing whitespace: "        Codec Configuration: "
277: B2 Line has trailing whitespace: "        Codec Configuration: "


---
Regards,
Linux Bluetooth
diff mbox series

Patch

diff --git a/tools/isotest.c b/tools/isotest.c
index caa711b2e..0eae3cdc1 100644
--- a/tools/isotest.c
+++ b/tools/isotest.c
@@ -32,6 +32,7 @@ 
 #include <linux/sockios.h>
 #include <time.h>
 #include <inttypes.h>
+#include <sys/wait.h>
 
 #include "lib/bluetooth.h"
 #include "lib/hci.h"
@@ -45,6 +46,9 @@ 
 #define SEC_USEC(_t)  (_t  * 1000000L)
 #define TS_USEC(_ts)  (SEC_USEC((_ts)->tv_sec) + NSEC_USEC((_ts)->tv_nsec))
 
+#define DEFAULT_BIG_ID 0x01
+#define DEFAULT_BIS_ID 0x01
+
 /* Test modes */
 enum {
 	SEND,
@@ -72,6 +76,8 @@  static bool quiet;
 struct bt_iso_qos *iso_qos;
 static bool inout;
 
+static uint8_t num_bis = 1;
+
 struct lookup_table {
 	const char *name;
 	int flag;
@@ -316,8 +322,6 @@  static int do_connect(char *peer)
 	struct sockaddr_iso addr;
 	int sk;
 
-	mgmt_set_experimental();
-
 	/* Create socket */
 	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO);
 	if (sk < 0) {
@@ -390,6 +394,45 @@  error:
 	return -1;
 }
 
+static int *bcast_do_connect_mbis(uint8_t count, char *peer)
+{
+	int *sk;
+	uint8_t sk_cnt = 0;
+
+	sk = malloc(count * sizeof(*sk));
+	if (!sk) {
+		syslog(LOG_ERR, "Can't allocate socket array");
+		return NULL;
+	}
+
+	defer_setup = 1;
+
+	for (int i = 0; i < count; i++) {
+		if (i == count - 1)
+			defer_setup = 0;
+
+		sk[i] = do_connect(peer);
+		if (sk[i] < 0) {
+			syslog(LOG_ERR, "Can't create socket: %s (%d)",
+					strerror(errno), errno);
+
+			goto error;
+		}
+
+		sk_cnt++;
+	}
+
+	return sk;
+
+error:
+	for (int i = 0; i < sk_cnt; i++)
+		close(sk[i]);
+
+	free(sk);
+	return NULL;
+
+}
+
 static void do_listen(char *filename, void (*handler)(int fd, int sk),
 							char *peer)
 {
@@ -431,8 +474,11 @@  static void do_listen(char *filename, void (*handler)(int fd, int sk),
 	if (peer) {
 		str2ba(peer, &addr->iso_bc->bc_bdaddr);
 		addr->iso_bc->bc_bdaddr_type = bdaddr_type;
-		addr->iso_bc->bc_num_bis = 1;
-		addr->iso_bc->bc_bis[0] = 1;
+		addr->iso_bc->bc_num_bis = num_bis;
+
+		for (int i = 0; i < num_bis; i++)
+			addr->iso_bc->bc_bis[i] = i + 1;
+
 		optlen += sizeof(*addr->iso_bc);
 	}
 
@@ -584,6 +630,7 @@  static void recv_mode(int fd, int sk)
 							strerror(errno), errno);
 				if (errno != ENOTCONN)
 					return;
+
 				r = 0;
 			}
 
@@ -704,12 +751,66 @@  static int read_file(int fd, ssize_t count, bool rewind)
 	return len;
 }
 
-static void do_send(int sk, int fd, struct bt_iso_io_qos *out, uint32_t num,
-		    bool repeat)
+static void do_send(int sk, int fd, char *peer, bool repeat)
 {
 	uint32_t seq;
 	struct timespec t_start;
-	int len, used;
+	int send_len, used;
+	socklen_t len;
+	struct bt_iso_qos qos;
+	uint32_t num;
+	struct bt_iso_io_qos *out;
+
+	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);
+		out->sdu = ISO_DEFAULT_MTU;
+	}
+
+	/* num of packets = latency (ms) / interval (us) */
+	num = (out->latency * 1000 / out->interval);
+
+	syslog(LOG_INFO, "Number of packets: %d", num);
+
+	if (!sndbuf)
+		/* Use socket buffer as a jitter buffer for the entire buffer
+		 * latency:
+		 * jitter buffer = 2 * (SDU * subevents)
+		 */
+		sndbuf = 2 * ((out->latency * 1000 / out->interval) *
+							out->sdu);
+
+	len = sizeof(sndbuf);
+	if (setsockopt(sk, SOL_SOCKET, SO_SNDBUF, &sndbuf, len) < 0) {
+		syslog(LOG_ERR, "Can't set socket SO_SNDBUF option: %s (%d)",
+				strerror(errno), errno);
+	}
+
+	syslog(LOG_INFO, "Socket jitter buffer: %d buffer", sndbuf);
+
+	if (sndto.tv_usec) {
+		len = sizeof(sndto);
+		if (setsockopt(sk, SOL_SOCKET, SO_SNDTIMEO, &sndto, len) < 0) {
+			syslog(LOG_ERR, "Can't set socket SO_SNDTIMEO option: "
+				"%s (%d)", strerror(errno), errno);
+		} else {
+			syslog(LOG_INFO, "Socket send timeout: %ld usec",
+							sndto.tv_usec);
+		}
+	}
+
+	for (int i = 6; i < out->sdu; i++)
+		buf[i] = 0x7f;
 
 	if (clock_gettime(CLOCK_MONOTONIC, &t_start) < 0) {
 		perror("clock_gettime");
@@ -718,17 +819,17 @@  static void do_send(int sk, int fd, struct bt_iso_io_qos *out, uint32_t num,
 
 	for (seq = 0; ; seq++) {
 		if (fd >= 0) {
-			len = read_file(fd, out->sdu, repeat);
-			if (len < 0) {
+			send_len = read_file(fd, out->sdu, repeat);
+			if (send_len < 0) {
 				syslog(LOG_ERR, "read failed: %s (%d)",
-						strerror(-len), -len);
+						strerror(-send_len), -send_len);
 				exit(1);
 			}
 		} else
-			len = out->sdu;
+			send_len = out->sdu;
 
-		len = send(sk, buf, len, 0);
-		if (len <= 0) {
+		send_len = send(sk, buf, send_len, 0);
+		if (send_len <= 0) {
 			syslog(LOG_ERR, "send failed: %s (%d)",
 						strerror(errno), errno);
 			exit(1);
@@ -739,7 +840,7 @@  static void do_send(int sk, int fd, struct bt_iso_io_qos *out, uint32_t num,
 		if (!quiet)
 			syslog(LOG_INFO,
 				"[seq %d] %d bytes buffered %d (%d bytes)",
-				seq, len, used / len, used);
+				seq, send_len, used / send_len, used);
 
 		if (seq && !((seq + 1) % num))
 			send_wait(&t_start, num * out->interval);
@@ -748,11 +849,11 @@  static void do_send(int sk, int fd, struct bt_iso_io_qos *out, uint32_t num,
 
 static void send_mode(char *filename, char *peer, int i, bool repeat)
 {
-	struct bt_iso_qos qos;
-	socklen_t len;
 	int sk, fd = -1;
-	uint32_t num;
-	struct bt_iso_io_qos *out;
+	int *sk_arr;
+	uint8_t nconn = strcmp(peer, "00:00:00:00:00:00") ? 1 : num_bis;
+
+	mgmt_set_experimental();
 
 	if (filename) {
 		char altername[PATH_MAX];
@@ -769,6 +870,33 @@  static void send_mode(char *filename, char *peer, int i, bool repeat)
 			fd = open_file(filename);
 	}
 
+	if (nconn > 1) {
+		sk_arr = bcast_do_connect_mbis(nconn, peer);
+		if (!sk_arr)
+			exit(1);
+
+		for (int i = 0; i < nconn; i++) {
+			if (fork()) {
+				/* Parent */
+				continue;
+			}
+
+			/* Child */
+			do_send(sk_arr[i], fd, peer, repeat);
+			exit(0);
+		}
+
+		/* Wait for children to exit */
+		while (wait(NULL) > 0)
+			;
+
+		for (int i = 0; i < nconn; i++)
+			close(sk_arr[i]);
+
+		free(sk_arr);
+		return;
+	}
+
 	sk = do_connect(peer);
 	if (sk < 0) {
 		syslog(LOG_ERR, "Can't connect to the server: %s (%d)",
@@ -782,62 +910,13 @@  static void send_mode(char *filename, char *peer, int i, bool repeat)
 		sleep(abs(defer_setup) - 1);
 	}
 
-	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);
-		out->sdu = ISO_DEFAULT_MTU;
-	}
-
-	/* num of packets = latency (ms) / interval (us) */
-	num = (out->latency * 1000 / out->interval);
-
-	syslog(LOG_INFO, "Number of packets: %d", num);
-
-	if (!sndbuf)
-		/* Use socket buffer as a jitter buffer for the entire buffer
-		 * latency:
-		 * jitter buffer = 2 * (SDU * subevents)
-		 */
-		sndbuf = 2 * ((out->latency * 1000 / out->interval) *
-							out->sdu);
-
-	len = sizeof(sndbuf);
-	if (setsockopt(sk, SOL_SOCKET, SO_SNDBUF, &sndbuf, len) < 0) {
-		syslog(LOG_ERR, "Can't set socket SO_SNDBUF option: %s (%d)",
-				strerror(errno), errno);
-	}
-
-	syslog(LOG_INFO, "Socket jitter buffer: %d buffer", sndbuf);
-
-	if (sndto.tv_usec) {
-		len = sizeof(sndto);
-		if (setsockopt(sk, SOL_SOCKET, SO_SNDTIMEO, &sndto, len) < 0) {
-			syslog(LOG_ERR, "Can't set socket SO_SNDTIMEO option: "
-				"%s (%d)", strerror(errno), errno);
-		} else {
-			syslog(LOG_INFO, "Socket send timeout: %ld usec",
-							sndto.tv_usec);
-		}
-	}
-
-	for (i = 6; i < out->sdu; i++)
-		buf[i] = 0x7f;
-
-	do_send(sk, fd, out, num, repeat);
+	do_send(sk, fd, peer, repeat);
 }
 
 static void reconnect_mode(char *peer)
 {
+	mgmt_set_experimental();
+
 	while (1) {
 		int sk;
 
@@ -856,6 +935,8 @@  static void reconnect_mode(char *peer)
 
 static void multy_connect_mode(char *peer)
 {
+	mgmt_set_experimental();
+
 	while (1) {
 		int i, sk;
 
@@ -989,7 +1070,8 @@  static void usage(void)
 		"\t[-B, --preset <value>]\n"
 		"\t[-G, --CIG/BIG <value>]\n"
 		"\t[-T, --CIS/BIS <value>]\n"
-		"\t[-V, --type <value>] address type (help for list)\n");
+		"\t[-V, --type <value>] address type (help for list)\n"
+		"\t[-N, --nbis <value>] Number of BISes to create/synchronize to\n");
 }
 
 static const struct option main_options[] = {
@@ -1019,6 +1101,7 @@  static const struct option main_options[] = {
 	{ "CIG/BIG",   required_argument, NULL, 'G'},
 	{ "CIS/BIS",   required_argument, NULL, 'T'},
 	{ "type",      required_argument, NULL, 'V'},
+	{ "nbis",      required_argument, NULL, 'N'},
 	{}
 };
 
@@ -1048,6 +1131,8 @@  int main(int argc, char *argv[])
 	char *filename = NULL;
 	bool repeat = false;
 	unsigned int i;
+	uint8_t nconn = 1;
+	char *peer;
 
 	iso_qos = malloc(sizeof(*iso_qos));
 	/* Default to 16_2_1 */
@@ -1058,7 +1143,7 @@  int main(int argc, char *argv[])
 		int opt;
 
 		opt = getopt_long(argc, argv,
-			"d::cmr::s::nb:i:j:hqt:CV:W:M:S:P:F:I:L:Y:R:B:G:T:e:k:",
+			"d::cmr::s::nb:i:j:hqt:CV:W:M:S:P:F:I:L:Y:R:B:G:T:e:k:N:",
 			main_options, NULL);
 		if (opt < 0)
 			break;
@@ -1224,6 +1309,23 @@  int main(int argc, char *argv[])
 					exit(1);
 			break;
 
+		case 'N':
+			if (optarg)
+				num_bis = atoi(optarg);
+
+			if (num_bis > 1) {
+				/* If the user requested multiple BISes,
+				 * make sure that all BISes are bound
+				 * for the same BIG and advertising set
+				 */
+				if (iso_qos->bcast.big == BT_ISO_QOS_BIG_UNSET)
+					iso_qos->bcast.big = DEFAULT_BIG_ID;
+
+				if (iso_qos->bcast.bis == BT_ISO_QOS_BIS_UNSET)
+					iso_qos->bcast.bis = DEFAULT_BIS_ID;
+			}
+			break;
+
 		/* fall through */
 		default:
 			usage();
@@ -1297,10 +1399,46 @@  int main(int argc, char *argv[])
 			break;
 
 		case CONNECT:
-			sk = do_connect(argv[optind + i]);
-			if (sk < 0)
-				exit(1);
-			dump_mode(-1, sk);
+			peer = argv[optind + i];
+
+			mgmt_set_experimental();
+
+			if (!strcmp(peer, "00:00:00:00:00:00"))
+				nconn = num_bis;
+
+			if (nconn > 1) {
+				int *sk_arr =  bcast_do_connect_mbis(nconn,
+								peer);
+
+				if (!sk_arr)
+					exit(1);
+
+				for (int i = 0; i < nconn; i++) {
+					if (fork()) {
+						/* Parent */
+						continue;
+					}
+
+					/* Child */
+					dump_mode(-1, sk_arr[i]);
+					exit(0);
+				}
+
+				/* Wait for children to exit */
+				while (wait(NULL) > 0)
+					;
+
+				for (int i = 0; i < nconn; i++)
+					close(sk_arr[i]);
+
+				free(sk_arr);
+			} else {
+				sk = do_connect(argv[optind + i]);
+				if (sk < 0)
+					exit(1);
+				dump_mode(-1, sk);
+			}
+
 			break;
 
 		case RECV:
diff --git a/tools/isotest.rst b/tools/isotest.rst
index 124dc71ab..fc5b3c56f 100644
--- a/tools/isotest.rst
+++ b/tools/isotest.rst
@@ -172,6 +172,10 @@  OPTIONS
 
 -k, --bcode=<BCODE>  Socket QoS Broadcast Code
 
+-N, --nbis=<NBIS>  Number of BISes to create as part of a
+                   BIG (BIS broadcaster) or to synchronize
+                   to (BIS broadcast receiver)
+
 EXAMPLES
 ========