All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH BlueZ 1/4] lib: Add definitions for ISO socket
@ 2020-12-21 23:01 Luiz Augusto von Dentz
  2020-12-21 23:01 ` [PATCH BlueZ 2/4] tools: Add isotest tool Luiz Augusto von Dentz
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Luiz Augusto von Dentz @ 2020-12-21 23:01 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 lib/bluetooth.h | 24 ++++++++++++++++++++++++
 lib/iso.h       | 45 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 69 insertions(+)
 create mode 100644 lib/iso.h

diff --git a/lib/bluetooth.h b/lib/bluetooth.h
index 9ab033ec4..0d4557377 100644
--- a/lib/bluetooth.h
+++ b/lib/bluetooth.h
@@ -37,6 +37,7 @@ extern "C" {
 #define BTPROTO_CMTP	5
 #define BTPROTO_HIDP	6
 #define BTPROTO_AVDTP	7
+#define BTPROTO_ISO	8
 
 #define SOL_HCI		0
 #define SOL_L2CAP	6
@@ -140,6 +141,29 @@ struct bt_voice {
 
 #define BT_SCM_PKT_STATUS	0x03
 
+#define BT_ISO_QOS		17
+
+#define BT_ISO_QOS_CIG_UNSET	0xff
+#define BT_ISO_QOS_CIS_UNSET	0xff
+
+struct bt_iso_io_qos {
+	uint32_t interval;
+	uint16_t latency;
+	uint16_t sdu;
+	uint8_t  phy;
+	uint8_t  rtn;
+};
+
+struct bt_iso_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;
+};
+
 /* Connection and socket states */
 enum {
 	BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
diff --git a/lib/iso.h b/lib/iso.h
new file mode 100644
index 000000000..2d427b417
--- /dev/null
+++ b/lib/iso.h
@@ -0,0 +1,45 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2019  Intel Corporation.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __ISO_H
+#define __ISO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ISO defaults */
+#define ISO_DEFAULT_MTU		251
+
+/* ISO socket address */
+struct sockaddr_iso {
+	sa_family_t	iso_family;
+	bdaddr_t	iso_bdaddr;
+	uint8_t		iso_bdaddr_type;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ISO_H */
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH BlueZ 2/4] tools: Add isotest tool
  2020-12-21 23:01 [PATCH BlueZ 1/4] lib: Add definitions for ISO socket Luiz Augusto von Dentz
@ 2020-12-21 23:01 ` Luiz Augusto von Dentz
  2020-12-21 23:01 ` [PATCH BlueZ 3/4] btio: Add support for ISO sockets Luiz Augusto von Dentz
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Luiz Augusto von Dentz @ 2020-12-21 23:01 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds isotest tool which can be used to test ISO sockets.
---
 Makefile.tools  |   5 +-
 tools/isotest.c | 845 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 849 insertions(+), 1 deletion(-)
 create mode 100644 tools/isotest.c

diff --git a/Makefile.tools b/Makefile.tools
index d5fdf2d89..c1eb2778a 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -191,7 +191,8 @@ noinst_PROGRAMS += tools/bdaddr tools/avinfo tools/avtest \
 			tools/eddystone tools/ibeacon \
 			tools/btgatt-client tools/btgatt-server \
 			tools/test-runner tools/check-selftest \
-			tools/gatt-service profiles/iap/iapd
+			tools/gatt-service profiles/iap/iapd \
+			tools/isotest
 
 tools_bdaddr_SOURCES = tools/bdaddr.c src/oui.h src/oui.c
 tools_bdaddr_LDADD = lib/libbluetooth-internal.la $(UDEV_LIBS)
@@ -291,6 +292,8 @@ tools_gatt_service_LDADD = $(GLIB_LIBS) $(DBUS_LIBS) gdbus/libgdbus-internal.la
 profiles_iap_iapd_SOURCES = profiles/iap/main.c
 profiles_iap_iapd_LDADD = gdbus/libgdbus-internal.la $(GLIB_LIBS) $(DBUS_LIBS)
 
+tools_isotest_LDADD = lib/libbluetooth-internal.la
+
 dist_man_MANS += tools/rctest.1 tools/l2ping.1 tools/btattach.1
 
 EXTRA_DIST += tools/bdaddr.1
diff --git a/tools/isotest.c b/tools/isotest.c
new file mode 100644
index 000000000..6abe2fd8a
--- /dev/null
+++ b/tools/isotest.c
@@ -0,0 +1,845 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2020  Intel Corporation.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <syslog.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/iso.h"
+
+#include "src/shared/util.h"
+
+/* Test modes */
+enum {
+	SEND,
+	RECV,
+	RECONNECT,
+	MULTY,
+	DUMP,
+	CONNECT
+};
+
+static unsigned char *buf;
+
+/* Default data size */
+static long data_size = 251;
+
+static bdaddr_t bdaddr;
+static int bdaddr_type = BDADDR_LE_PUBLIC;
+
+static int defer_setup = 0;
+
+struct bt_iso_qos *iso_qos = NULL;
+static bool inout;
+
+struct lookup_table {
+	const char *name;
+	int flag;
+};
+
+static struct lookup_table bdaddr_types[] = {
+	{ "le_public",	BDADDR_LE_PUBLIC	},
+	{ "le_random",	BDADDR_LE_RANDOM	},
+	{ NULL,		0			},
+};
+
+static int get_lookup_flag(struct lookup_table *table, char *name)
+{
+	int i;
+
+	for (i = 0; table[i].name; i++)
+		if (!strcasecmp(table[i].name, name))
+			return table[i].flag;
+
+	return -1;
+}
+
+static void print_lookup_values(struct lookup_table *table, char *header)
+{
+	int i;
+
+	printf("%s\n", header);
+
+	for (i = 0; table[i].name; i++)
+		printf("\t%s\n", table[i].name);
+}
+
+static float tv2fl(struct timeval tv)
+{
+	return (float)tv.tv_sec + (float)(tv.tv_usec/1000000.0);
+}
+
+static int do_connect(char *peer)
+{
+	struct sockaddr_iso addr;
+	struct bt_iso_qos qos;
+	socklen_t len;
+	int sk;
+
+	/* Create socket */
+	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO);
+	if (sk < 0) {
+		syslog(LOG_ERR, "Can't create socket: %s (%d)",
+							strerror(errno), errno);
+		return -1;
+	}
+
+	/* Bind to local address */
+	memset(&addr, 0, sizeof(addr));
+	addr.iso_family = AF_BLUETOOTH;
+	bacpy(&addr.iso_bdaddr, &bdaddr);
+	addr.iso_bdaddr_type = bdaddr_type;
+
+	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		syslog(LOG_ERR, "Can't bind socket: %s (%d)",
+							strerror(errno), errno);
+		goto error;
+	}
+
+	/* Set QoS if available */
+	if (iso_qos) {
+		if (!inout) {
+			iso_qos->in.phy = 0x00;
+			iso_qos->in.sdu = 0;
+		}
+
+		if (setsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, iso_qos,
+					sizeof(*iso_qos)) < 0) {
+			syslog(LOG_ERR, "Can't set QoS socket option: "
+					"%s (%d)", strerror(errno), errno);
+		}
+	}
+
+	/* Enable deferred setup */
+	if (defer_setup && setsockopt(sk, SOL_BLUETOOTH, BT_DEFER_SETUP,
+				&defer_setup, sizeof(defer_setup)) < 0) {
+		syslog(LOG_ERR, "Can't enable deferred setup : %s (%d)",
+							strerror(errno), errno);
+		goto error;
+	}
+
+	/* Connect to remote device */
+	memset(&addr, 0, sizeof(addr));
+	addr.iso_family = AF_BLUETOOTH;
+	str2ba(peer, &addr.iso_bdaddr);
+	addr.iso_bdaddr_type = bdaddr_type;
+
+	syslog(LOG_INFO, "Connecting %s ...", peer);
+
+	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		syslog(LOG_ERR, "Can't connect: %s (%d)",
+							strerror(errno), errno);
+		goto error;
+	}
+
+	/* 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);
+		goto error;
+	}
+
+	syslog(LOG_INFO, "Connected [%s]", peer);
+	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, "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);
+
+	return sk;
+
+error:
+	close(sk);
+	return -1;
+}
+
+static void do_listen(char *filename, void (*handler)(int fd, int sk))
+{
+	struct sockaddr_iso addr;
+	socklen_t optlen;
+	int sk, nsk, fd = -1;
+	char ba[18];
+
+	if (filename) {
+		fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, 0644);
+		if (fd < 0) {
+			syslog(LOG_ERR, "Can't open file %s: %s\n",
+						filename, strerror(errno));
+			exit(1);
+		}
+	}
+
+	/* Create socket */
+	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO);
+	if (sk < 0) {
+		syslog(LOG_ERR, "Can't create socket: %s (%d)",
+							strerror(errno), errno);
+		if (fd >= 0)
+			close(fd);
+		exit(1);
+	}
+
+	/* Bind to local address */
+	memset(&addr, 0, sizeof(addr));
+	addr.iso_family = AF_BLUETOOTH;
+	bacpy(&addr.iso_bdaddr, &bdaddr);
+	addr.iso_bdaddr_type = bdaddr_type;
+
+	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		syslog(LOG_ERR, "Can't bind socket: %s (%d)",
+							strerror(errno), errno);
+		goto error;
+	}
+
+	/* Enable deferred setup */
+	if (defer_setup && setsockopt(sk, SOL_BLUETOOTH, BT_DEFER_SETUP,
+				&defer_setup, sizeof(defer_setup)) < 0) {
+		syslog(LOG_ERR, "Can't enable deferred setup : %s (%d)",
+							strerror(errno), errno);
+		goto error;
+	}
+
+	/* Listen for connections */
+	if (listen(sk, 10)) {
+		syslog(LOG_ERR,"Can not listen on the socket: %s (%d)",
+							strerror(errno), errno);
+		goto error;
+	}
+
+	syslog(LOG_INFO,"Waiting for connection ...");
+
+	while (1) {
+		memset(&addr, 0, sizeof(addr));
+		optlen = sizeof(addr);
+
+		nsk = accept(sk, (struct sockaddr *) &addr, &optlen);
+		if (nsk < 0) {
+			syslog(LOG_ERR,"Accept failed: %s (%d)",
+							strerror(errno), errno);
+			goto error;
+		}
+		if (fork()) {
+			/* Parent */
+			close(nsk);
+			continue;
+		}
+		/* Child */
+		close(sk);
+
+		ba2str(&addr.iso_bdaddr, ba);
+		syslog(LOG_INFO, "Connect from %s", ba);
+
+		/* Handle deferred setup */
+		if (defer_setup) {
+			syslog(LOG_INFO, "Waiting for %d seconds",
+							abs(defer_setup) - 1);
+			sleep(abs(defer_setup) - 1);
+
+			if (defer_setup < 0) {
+				close(nsk);
+				exit(1);
+			}
+		}
+
+		handler(fd, nsk);
+
+		syslog(LOG_INFO, "Disconnect");
+		exit(0);
+	}
+
+error:
+	if (fd >= 0)
+		close(fd);
+	close(sk);
+	exit(1);
+}
+
+static void dump_mode(int fd, int sk)
+{
+	int len;
+
+	if (defer_setup) {
+		len = read(sk, buf, data_size);
+		if (len < 0)
+			syslog(LOG_ERR, "Initial read error: %s (%d)",
+						strerror(errno), errno);
+		else
+			syslog(LOG_INFO, "Initial bytes %d", len);
+	}
+
+	syslog(LOG_INFO,"Receiving ...");
+	while ((len = read(sk, buf, data_size)) > 0) {
+		if (fd >= 0) {
+			len = write(fd, buf, len);
+			if (len < 0) {
+				syslog(LOG_ERR, "Write failed: %s (%d)",
+						strerror(errno), errno);
+				return;
+			}
+		} else
+			syslog(LOG_INFO, "Received %d bytes", len);
+	}
+}
+
+static void recv_mode(int fd, int sk)
+{
+	struct timeval tv_beg,tv_end,tv_diff;
+	long total;
+	int len;
+
+	if (defer_setup) {
+		len = read(sk, buf, data_size);
+		if (len < 0)
+			syslog(LOG_ERR, "Initial read error: %s (%d)",
+						strerror(errno), errno);
+		else
+			syslog(LOG_INFO, "Initial bytes %d", len);
+	}
+
+	syslog(LOG_INFO, "Receiving ...");
+
+	while (1) {
+		gettimeofday(&tv_beg, NULL);
+		total = 0;
+		while (total < data_size) {
+			int r;
+
+			r = recv(sk, buf, data_size, 0);
+			if (r <= 0) {
+				if (r < 0)
+					syslog(LOG_ERR, "Read failed: %s (%d)",
+							strerror(errno), errno);
+				if (errno != ENOTCONN)
+					return;
+				r = 0;
+			}
+
+			if (fd >= 0) {
+				r = write(fd, buf, r);
+				if (r < 0) {
+					syslog(LOG_ERR, "Write failed: %s (%d)",
+							strerror(errno), errno);
+					return;
+				}
+			}
+
+			total += r;
+		}
+		gettimeofday(&tv_end, NULL);
+
+		timersub(&tv_end, &tv_beg, &tv_diff);
+
+		syslog(LOG_INFO,"%ld bytes in %.2f sec speed %.2f kb/s", total,
+			tv2fl(tv_diff),
+			(float)(total * 8 / tv2fl(tv_diff)) / 1024.0);
+	}
+}
+
+static int open_file(const char *filename)
+{
+	int fd = -1;
+
+	syslog(LOG_INFO,"Opening %s ...", filename);
+
+	fd = open(filename, O_RDONLY);
+	if (fd <= 0) {
+		syslog(LOG_ERR, "Can't open file %s: %s\n",
+						filename, strerror(errno));
+	}
+
+	return fd;
+}
+
+static void send_mode(char *filename, char *peer, int i)
+{
+	struct bt_iso_qos qos;
+	socklen_t len;
+	uint32_t seq;
+	int sk, fd = -1;
+
+	if (filename) {
+		char altername[PATH_MAX];
+		struct stat st;
+		int err;
+
+		snprintf(altername, PATH_MAX, "%s.%u", filename, i);
+
+		err = stat(altername, &st);
+		if (!err)
+			fd = open_file(altername);
+
+		if (fd <= 0)
+			fd = open_file(filename);
+	}
+
+	sk = do_connect(peer);
+	if (sk < 0) {
+		syslog(LOG_ERR, "Can't connect to the server: %s (%d)",
+							strerror(errno), errno);
+		exit(1);
+	}
+
+	if (defer_setup) {
+		syslog(LOG_INFO, "Waiting for %d seconds",
+			abs(defer_setup) - 1);
+		sleep(abs(defer_setup) - 1);
+	}
+
+	syslog(LOG_INFO,"Sending ...");
+
+	/* Read 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 Output QoS socket option: %s (%d)",
+				strerror(errno), errno);
+		qos.out.sdu = ISO_DEFAULT_MTU;
+	}
+
+	for (i = 6; i < qos.out.sdu; i++)
+		buf[i] = 0x7f;
+
+	seq = 0;
+	while (1) {
+		if (fd >= 0) {
+			ssize_t ret;
+
+			ret = read(fd, buf, qos.out.sdu);
+			if (ret <= 0) {
+				if (ret < 0)
+					syslog(LOG_ERR, "read failed: %s (%d)",
+							strerror(errno), errno);
+				close(fd);
+				break;
+			}
+		}
+
+		seq++;
+
+		if (send(sk, buf, qos.out.sdu, 0) <= 0) {
+			syslog(LOG_ERR, "Send failed: %s (%d)",
+							strerror(errno), errno);
+			exit(1);
+		}
+
+		usleep(qos.out.interval);
+	}
+}
+
+static void reconnect_mode(char *peer)
+{
+	while (1) {
+		int sk;
+
+		sk = do_connect(peer);
+		if (sk < 0) {
+			syslog(LOG_ERR, "Can't connect to the server: %s (%d)",
+							strerror(errno), errno);
+			exit(1);
+		}
+
+		close(sk);
+
+		sleep(5);
+	}
+}
+
+static void multy_connect_mode(char *peer)
+{
+	while (1) {
+		int i, sk;
+
+		for (i = 0; i < 10; i++){
+			if (fork())
+				continue;
+
+			/* Child */
+			sk = do_connect(peer);
+			if (sk < 0) {
+				syslog(LOG_ERR, "Can't connect to the server: "
+					"%s (%d)", strerror(errno), errno);
+			}
+			close(sk);
+			exit(0);
+		}
+
+		sleep(19);
+	}
+}
+
+#define QOS_IO(_interval, _latency, _sdu, _phy, _rtn) \
+{ \
+	.interval = _interval, \
+	.latency = _latency, \
+	.sdu = _sdu, \
+	.phy = _phy, \
+	.rtn = _rtn, \
+}
+
+#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), \
+}
+
+#define QOS_PRESET(_name, _inout, _interval, _latency, _sdu, _phy, _rtn) \
+{ \
+	.name = _name, \
+	.inout = _inout, \
+	.qos = QOS(_interval, _latency, _sdu, _phy, _rtn), \
+}
+
+static struct qos_preset {
+	const char *name;
+	bool inout;
+	struct bt_iso_qos qos;
+} presets[] = {
+	/* QoS Configuration settings for low latency audio data */
+	QOS_PRESET("8_1_1", true, 7500, 8, 26, 0x02, 2),
+	QOS_PRESET("8_2_1", true, 10000, 10, 30, 0x02, 2),
+	QOS_PRESET("16_1_1", true, 7500, 8, 30, 0x02, 2),
+	QOS_PRESET("16_2_1", true, 10000, 10, 40, 0x02, 2),
+	QOS_PRESET("24_1_1", true, 7500, 8, 45, 0x02, 2),
+	QOS_PRESET("24_2_1", true, 10000, 10, 60, 0x02, 2),
+	QOS_PRESET("32_1_1", true, 7500, 8, 60, 0x02, 2),
+	QOS_PRESET("32_2_1", true, 10000, 10, 80, 0x02, 2),
+	QOS_PRESET("44_1_1", false, 8163, 24, 98, 0x02, 5),
+	QOS_PRESET("44_2_1", false, 10884, 31, 130, 0x02, 5),
+	QOS_PRESET("48_1_1", false, 7500, 15, 75, 0x02, 5),
+	QOS_PRESET("48_2_1", false, 10000, 20, 100, 0x02, 5),
+	QOS_PRESET("48_3_1", false, 7500, 15, 90, 0x02, 5),
+	QOS_PRESET("48_4_1", false, 10000, 20, 120, 0x02, 5),
+	QOS_PRESET("48_5_1", false, 7500, 15, 117, 0x02, 5),
+	QOS_PRESET("44_6_1", false, 10000, 20, 155, 0x02, 5),
+	/* QoS Configuration settings for high reliability audio data */
+	QOS_PRESET("8_1_2", true, 7500, 45, 26, 0x02, 41),
+	QOS_PRESET("8_2_2", true, 10000, 60, 30, 0x02, 53),
+	QOS_PRESET("16_1_2", true, 7500, 45, 30, 0x02, 41),
+	QOS_PRESET("16_2_2", true, 10000, 60, 40, 0x02, 47),
+	QOS_PRESET("24_1_2", true, 7500, 45, 45, 0x02, 35),
+	QOS_PRESET("24_2_2", true, 10000, 60, 60, 0x02, 41),
+	QOS_PRESET("32_1_2", true, 7500, 45, 60, 0x02, 29),
+	QOS_PRESET("32_2_1", true, 10000, 60, 80, 0x02, 35),
+	QOS_PRESET("44_1_2", false, 8163, 54, 98, 0x02, 23),
+	QOS_PRESET("44_2_2", false, 10884, 71, 130, 0x02, 23),
+	QOS_PRESET("48_1_2", false, 7500, 45, 75, 0x02, 23),
+	QOS_PRESET("48_2_2", false, 10000, 60, 100, 0x02, 23),
+	QOS_PRESET("48_3_2", false, 7500, 45, 90, 0x02, 23),
+	QOS_PRESET("48_4_2", false, 10000, 60, 120, 0x02, 23),
+	QOS_PRESET("48_5_2", false, 7500, 45, 117, 0x02, 23),
+	QOS_PRESET("44_6_2", false, 10000, 60, 155, 0x02, 23),
+};
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+static void usage(void)
+{
+	printf("isotest - ISO testing\n"
+		"Usage:\n");
+	printf("\tisotest <mode> [options] [bdaddr] [bdaddr1]...\n");
+	printf("Modes:\n"
+		"\t-d, --dump [filename]    dump (server)\n"
+		"\t-c, --reconnect          reconnect (client)\n"
+		"\t-m, --multiple           multiple connects (client)\n"
+		"\t-r, --receive [filename] receive (server)\n"
+		"\t-s, --send [filename,...] connect and send (client)\n"
+		"\t-n, --silent             connect and be silent (client)\n"
+		"Options:\n"
+		"\t[-b, --bytes <value>]\n"
+		"\t[-i, --device <num>]\n"
+		"\t[-h, --help]\n"
+		"\t[-W, --defer <seconds>]  enable deferred setup\n"
+		"\t[-M, --mtu <value>]\n"
+		"\t[-S, --sca <value>]\n"
+		"\t[-P, --packing <value>]\n"
+		"\t[-F, --framing <value>]\n"
+		"\t[-I, --interval <useconds>]\n"
+		"\t[-L, --latency <mseconds>]\n"
+		"\t[-Y, --phy <value>]\n"
+		"\t[-R, --rtn <value>]\n"
+		"\t[-B, --preset <value>]\n"
+		"\t[-G, --CIG <value>]\n"
+		"\t[-V, --type <value>] address type (help for list)\n");
+}
+
+static const struct option main_options[] = {
+	{ "dump",      optional_argument, NULL, 'd'},
+	{ "reconnect", no_argument,       NULL, 'c'},
+	{ "multiple",  no_argument,       NULL, 'm'},
+	{ "receive",   optional_argument, NULL, 'r'},
+	{ "send",      optional_argument, NULL, 's'},
+	{ "silent",    no_argument,       NULL, 'n'},
+	{ "bytes",     required_argument, NULL, 'b'},
+	{ "device",    required_argument, NULL, 'i'},
+	{ "help",      no_argument,       NULL, 'h'},
+	{ "defer",     required_argument, NULL, 'W'},
+	{ "mtu",       required_argument, NULL, 'M'},
+	{ "sca",       required_argument, NULL, 'S'},
+	{ "packing",   required_argument, NULL, 'P'},
+	{ "framing",   required_argument, NULL, 'F'},
+	{ "interval",  required_argument, NULL, 'I'},
+	{ "latency",   required_argument, NULL, 'L'},
+	{ "phy",       required_argument, NULL, 'Y'},
+	{ "rtn",       required_argument, NULL, 'R'},
+	{ "preset",    required_argument, NULL, 'B'},
+	{ "CIG",       required_argument, NULL, 'G'},
+	{ "type",      required_argument, NULL, 'V'},
+	{}
+};
+
+int main(int argc ,char *argv[])
+{
+	struct sigaction sa;
+	int sk, mode = RECV;
+	char *filename = NULL;
+	unsigned int i;
+
+	iso_qos = malloc(sizeof(*iso_qos));
+	/* Default to 16_2_1 */
+	*iso_qos = presets[3].qos;
+	inout = true;
+
+	while (1) {
+		int opt;
+
+		opt = getopt_long(argc, argv,
+				"d::cmr::s::nb:i:hV:W:M:S:P:F:I:L:Y:R:B:G:",
+				main_options, NULL);
+		if (opt < 0)
+			break;
+
+
+		switch(opt) {
+		case 'r':
+			mode = RECV;
+			if (optarg)
+				filename = strdup(optarg);
+			break;
+
+		case 's':
+			mode = SEND;
+			if (optarg)
+				filename = strdup(optarg);
+			break;
+
+		case 'd':
+			mode = DUMP;
+			if (optarg)
+				filename = strdup(optarg);
+			break;
+
+		case 'c':
+			mode = RECONNECT;
+			break;
+
+		case 'm':
+			mode = MULTY;
+			break;
+
+		case 'n':
+			mode = CONNECT;
+			break;
+
+		case 'b':
+			data_size = atoi(optarg);
+			break;
+
+		case 'i':
+			if (!strncasecmp(optarg, "hci", 3))
+				hci_devba(atoi(optarg + 3), &bdaddr);
+			else
+				str2ba(optarg, &bdaddr);
+			break;
+
+		case 'V':
+			bdaddr_type = get_lookup_flag(bdaddr_types, optarg);
+
+			if (bdaddr_type == -1) {
+				print_lookup_values(bdaddr_types,
+						"List Address types:");
+				exit(1);
+			}
+
+			break;
+
+		case 'W':
+			defer_setup = atoi(optarg);
+			break;
+
+		case 'M':
+			iso_qos->out.sdu = atoi(optarg);
+
+			break;
+
+		case 'S':
+			iso_qos->sca = atoi(optarg);
+
+			break;
+
+
+		case 'P':
+			iso_qos->packing = atoi(optarg);
+
+			break;
+
+		case 'F':
+			iso_qos->framing = atoi(optarg);
+
+			break;
+
+		case 'I':
+			iso_qos->out.interval = atoi(optarg);
+
+			break;
+
+		case 'L':
+			iso_qos->out.latency = atoi(optarg);
+
+			break;
+
+		case 'Y':
+			iso_qos->out.phy = atoi(optarg);
+
+			break;
+
+		case 'R':
+			iso_qos->out.rtn = atoi(optarg);
+
+			break;
+
+		case 'B':
+			for (i = 0; i < ARRAY_SIZE(presets); i++) {
+				if (!strcmp(presets[i].name, optarg)) {
+					*iso_qos = presets[i].qos;
+					inout = presets[i].inout;
+					break;
+				}
+			}
+
+			break;
+
+		case 'G':
+			iso_qos->cig = atoi(optarg);
+
+			break;
+
+		/* Fallthrough */
+		default:
+			usage();
+			exit(1);
+		}
+	}
+
+	if (inout)
+		iso_qos->in = iso_qos->out;
+
+	buf = malloc(data_size);
+	if (!buf) {
+		perror("Can't allocate data buffer");
+		exit(1);
+	}
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = SIG_IGN;
+	sa.sa_flags   = SA_NOCLDSTOP;
+	sigaction(SIGCHLD, &sa, NULL);
+
+	openlog("isotest", LOG_PERROR | LOG_PID, LOG_LOCAL0);
+
+	if (!(argc - optind)) {
+		switch (mode) {
+		case RECV:
+			do_listen(filename, recv_mode);
+			goto done;
+
+		case DUMP:
+			do_listen(filename, dump_mode);
+			goto done;
+		default:
+			usage();
+			exit(1);
+		}
+	}
+
+	argc -= optind;
+
+	for (i = 0; i < (unsigned int) argc; i++) {
+		pid_t pid;
+
+		pid = fork();
+		if (pid < 0) {
+			perror("Failed to fork new process");
+			return -1;
+		}
+
+		if (!pid)
+			continue;
+
+		switch (mode) {
+		case SEND:
+			send_mode(filename, argv[optind + i], i);
+			if (strchr(filename, ','))
+				filename = strchr(filename, ',') + 1;
+			break;
+
+		case RECONNECT:
+			reconnect_mode(argv[optind + i]);
+			break;
+
+		case MULTY:
+			multy_connect_mode(argv[optind + i]);
+			break;
+
+		case CONNECT:
+			sk = do_connect(argv[optind + i]);
+			if (sk < 0)
+				exit(1);
+			dump_mode(-1, sk);
+			break;
+		}
+
+		break;
+	}
+
+done:
+	syslog(LOG_INFO, "Exit");
+
+	closelog();
+
+	return 0;
+}
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH BlueZ 3/4] btio: Add support for ISO sockets
  2020-12-21 23:01 [PATCH BlueZ 1/4] lib: Add definitions for ISO socket Luiz Augusto von Dentz
  2020-12-21 23:01 ` [PATCH BlueZ 2/4] tools: Add isotest tool Luiz Augusto von Dentz
@ 2020-12-21 23:01 ` Luiz Augusto von Dentz
  2020-12-21 23:01 ` [PATCH BlueZ 4/4] tools: Add iso-tester Luiz Augusto von Dentz
  2020-12-21 23:42 ` [BlueZ,1/4] lib: Add definitions for ISO socket bluez.test.bot
  3 siblings, 0 replies; 5+ messages in thread
From: Luiz Augusto von Dentz @ 2020-12-21 23:01 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds support to create objects that map to ISO sockets.
---
 btio/btio.c      | 164 +++++++++++++++++++++++++++++++++++++++++++++++
 btio/btio.h      |   4 +-
 tools/btiotest.c | 110 +++++++++++++++++++++++++++++++
 3 files changed, 277 insertions(+), 1 deletion(-)

diff --git a/btio/btio.c b/btio/btio.c
index 8230212b4..38356ff00 100644
--- a/btio/btio.c
+++ b/btio/btio.c
@@ -27,6 +27,7 @@
 #include "lib/l2cap.h"
 #include "lib/rfcomm.h"
 #include "lib/sco.h"
+#include "lib/iso.h"
 
 #include "btio.h"
 
@@ -44,6 +45,7 @@ typedef enum {
 	BT_IO_L2CAP,
 	BT_IO_RFCOMM,
 	BT_IO_SCO,
+	BT_IO_ISO,
 	BT_IO_INVALID,
 } BtIOType;
 
@@ -66,6 +68,7 @@ struct set_opts {
 	int flushable;
 	uint32_t priority;
 	uint16_t voice;
+	struct bt_iso_qos qos;
 };
 
 struct connect {
@@ -763,6 +766,25 @@ static int sco_bind(int sock, const bdaddr_t *src, GError **err)
 	return 0;
 }
 
+static int iso_bind(int sock, const bdaddr_t *src, uint8_t src_type,
+							GError **err)
+{
+	struct sockaddr_iso addr;
+
+	memset(&addr, 0, sizeof(addr));
+	addr.iso_family = AF_BLUETOOTH;
+	bacpy(&addr.iso_bdaddr, src);
+	addr.iso_bdaddr_type = src_type;
+
+	if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		int error = -errno;
+		ERROR_FAILED(err, "sco_bind", errno);
+		return error;
+	}
+
+	return 0;
+}
+
 static int sco_connect(int sock, const bdaddr_t *dst)
 {
 	struct sockaddr_sco addr;
@@ -779,6 +801,23 @@ static int sco_connect(int sock, const bdaddr_t *dst)
 	return 0;
 }
 
+static int iso_connect(int sock, const bdaddr_t *dst, uint8_t dst_type)
+{
+	struct sockaddr_iso addr;
+	int err;
+
+	memset(&addr, 0, sizeof(addr));
+	addr.iso_family = AF_BLUETOOTH;
+	bacpy(&addr.iso_bdaddr, dst);
+	addr.iso_bdaddr_type = dst_type;
+
+	err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
+	if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
+		return -errno;
+
+	return 0;
+}
+
 static gboolean sco_set(int sock, uint16_t mtu, uint16_t voice, GError **err)
 {
 	struct sco_options sco_opt;
@@ -817,6 +856,17 @@ voice:
 	return TRUE;
 }
 
+static gboolean iso_set(int sock, struct bt_iso_qos *qos, GError **err)
+{
+	if (setsockopt(sock, SOL_BLUETOOTH, BT_ISO_QOS, qos,
+				sizeof(*qos)) < 0) {
+		ERROR_FAILED(err, "setsockopt(BT_ISO_QOS)", errno);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
 static gboolean parse_set_opts(struct set_opts *opts, GError **err,
 						BtIOOption opt1, va_list args)
 {
@@ -894,6 +944,8 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
 			break;
 		case BT_IO_OPT_MODE:
 			opts->mode = va_arg(args, int);
+			if (opts->mode == BT_IO_MODE_ISO)
+				opts->type = BT_IO_ISO;
 			break;
 		case BT_IO_OPT_FLUSHABLE:
 			opts->flushable = va_arg(args, gboolean);
@@ -904,6 +956,9 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
 		case BT_IO_OPT_VOICE:
 			opts->voice = va_arg(args, int);
 			break;
+		case BT_IO_OPT_QOS:
+			opts->qos = *va_arg(args, struct bt_iso_qos *);
+			break;
 		case BT_IO_OPT_INVALID:
 		case BT_IO_OPT_KEY_SIZE:
 		case BT_IO_OPT_SOURCE_CHANNEL:
@@ -1227,6 +1282,7 @@ parse_opts:
 		case BT_IO_OPT_DEST_CHANNEL:
 		case BT_IO_OPT_MTU:
 		case BT_IO_OPT_VOICE:
+		case BT_IO_OPT_QOS:
 		default:
 			g_set_error(err, BT_IO_ERROR, EINVAL,
 					"Unknown option %d", opt);
@@ -1380,6 +1436,7 @@ static gboolean rfcomm_get(int sock, GError **err, BtIOOption opt1,
 		case BT_IO_OPT_FLUSHABLE:
 		case BT_IO_OPT_PRIORITY:
 		case BT_IO_OPT_VOICE:
+		case BT_IO_OPT_QOS:
 		case BT_IO_OPT_INVALID:
 		default:
 			g_set_error(err, BT_IO_ERROR, EINVAL,
@@ -1489,6 +1546,95 @@ static gboolean sco_get(int sock, GError **err, BtIOOption opt1, va_list args)
 		case BT_IO_OPT_FLUSHABLE:
 		case BT_IO_OPT_PRIORITY:
 		case BT_IO_OPT_VOICE:
+		case BT_IO_OPT_QOS:
+		case BT_IO_OPT_INVALID:
+		default:
+			g_set_error(err, BT_IO_ERROR, EINVAL,
+					"Unknown option %d", opt);
+			return FALSE;
+		}
+
+		opt = va_arg(args, int);
+	}
+
+	return TRUE;
+}
+
+static gboolean iso_get(int sock, GError **err, BtIOOption opt1, va_list args)
+{
+	BtIOOption opt = opt1;
+	struct sockaddr_iso src, dst;
+	struct bt_iso_qos qos;
+	socklen_t len;
+	uint32_t phy;
+
+	len = sizeof(qos);
+	memset(&qos, 0, len);
+	if (getsockopt(sock, SOL_BLUETOOTH, BT_ISO_QOS, &qos, &len) < 0) {
+		ERROR_FAILED(err, "getsockopt(BT_ISO_QOS)", errno);
+		return FALSE;
+	}
+
+	if (!get_src(sock, &src, sizeof(src), err))
+		return FALSE;
+
+	if (!get_dst(sock, &dst, sizeof(dst), err))
+		return FALSE;
+
+	while (opt != BT_IO_OPT_INVALID) {
+		switch (opt) {
+		case BT_IO_OPT_SOURCE:
+			ba2str(&src.iso_bdaddr, va_arg(args, char *));
+			break;
+		case BT_IO_OPT_SOURCE_BDADDR:
+			bacpy(va_arg(args, bdaddr_t *), &src.iso_bdaddr);
+			break;
+		case BT_IO_OPT_SOURCE_TYPE:
+			*(va_arg(args, uint8_t *)) = src.iso_bdaddr_type;
+			break;
+		case BT_IO_OPT_DEST:
+			ba2str(&dst.iso_bdaddr, va_arg(args, char *));
+			break;
+		case BT_IO_OPT_DEST_BDADDR:
+			bacpy(va_arg(args, bdaddr_t *), &dst.iso_bdaddr);
+			break;
+		case BT_IO_OPT_DEST_TYPE:
+			*(va_arg(args, uint8_t *)) = dst.iso_bdaddr_type;
+			break;
+		case BT_IO_OPT_MTU:
+			*(va_arg(args, uint16_t *)) = qos.out.sdu;
+			break;
+		case BT_IO_OPT_IMTU:
+			*(va_arg(args, uint16_t *)) = qos.in.sdu;
+			break;
+		case BT_IO_OPT_OMTU:
+			*(va_arg(args, uint16_t *)) = qos.out.sdu;
+			break;
+		case BT_IO_OPT_PHY:
+			if (get_phy(sock, &phy) < 0) {
+				ERROR_FAILED(err, "get_phy", errno);
+				return FALSE;
+			}
+			*(va_arg(args, uint32_t *)) = phy;
+			break;
+		case BT_IO_OPT_QOS:
+			*(va_arg(args, struct bt_iso_qos *)) = qos;
+			break;
+		case BT_IO_OPT_HANDLE:
+		case BT_IO_OPT_CLASS:
+		case BT_IO_OPT_DEFER_TIMEOUT:
+		case BT_IO_OPT_SEC_LEVEL:
+		case BT_IO_OPT_KEY_SIZE:
+		case BT_IO_OPT_CHANNEL:
+		case BT_IO_OPT_SOURCE_CHANNEL:
+		case BT_IO_OPT_DEST_CHANNEL:
+		case BT_IO_OPT_PSM:
+		case BT_IO_OPT_CID:
+		case BT_IO_OPT_MASTER:
+		case BT_IO_OPT_MODE:
+		case BT_IO_OPT_FLUSHABLE:
+		case BT_IO_OPT_PRIORITY:
+		case BT_IO_OPT_VOICE:
 		case BT_IO_OPT_INVALID:
 		default:
 			g_set_error(err, BT_IO_ERROR, EINVAL,
@@ -1516,6 +1662,8 @@ static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err,
 		return rfcomm_get(sock, err, opt1, args);
 	case BT_IO_SCO:
 		return sco_get(sock, err, opt1, args);
+	case BT_IO_ISO:
+		return iso_get(sock, err, opt1, args);
 	case BT_IO_INVALID:
 	default:
 		g_set_error(err, BT_IO_ERROR, EINVAL,
@@ -1584,6 +1732,8 @@ gboolean bt_io_set(GIOChannel *io, GError **err, BtIOOption opt1, ...)
 		return rfcomm_set(sock, opts.sec_level, opts.master, err);
 	case BT_IO_SCO:
 		return sco_set(sock, opts.mtu, opts.voice, err);
+	case BT_IO_ISO:
+		return iso_set(sock, &opts.qos, err);
 	case BT_IO_INVALID:
 	default:
 		g_set_error(err, BT_IO_ERROR, EINVAL,
@@ -1655,6 +1805,17 @@ static GIOChannel *create_io(gboolean server, struct set_opts *opts,
 		if (!sco_set(sock, opts->mtu, opts->voice, err))
 			goto failed;
 		break;
+	case BT_IO_ISO:
+		sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO);
+		if (sock < 0) {
+			ERROR_FAILED(err, "socket(SEQPACKET, ISO)", errno);
+			return NULL;
+		}
+		if (iso_bind(sock, &opts->src, opts->src_type, err) < 0)
+			goto failed;
+		if (!iso_set(sock, &opts->qos, err))
+			goto failed;
+		break;
 	case BT_IO_INVALID:
 	default:
 		g_set_error(err, BT_IO_ERROR, EINVAL,
@@ -1719,6 +1880,9 @@ GIOChannel *bt_io_connect(BtIOConnect connect, gpointer user_data,
 	case BT_IO_SCO:
 		err = sco_connect(sock, &opts.dst);
 		break;
+	case BT_IO_ISO:
+		err = iso_connect(sock, &opts.dst, opts.dst_type);
+		break;
 	case BT_IO_INVALID:
 	default:
 		g_set_error(gerr, BT_IO_ERROR, EINVAL,
diff --git a/btio/btio.h b/btio/btio.h
index f0259cf1d..7d0acbb17 100644
--- a/btio/btio.h
+++ b/btio/btio.h
@@ -44,6 +44,7 @@ typedef enum {
 	BT_IO_OPT_PRIORITY,
 	BT_IO_OPT_VOICE,
 	BT_IO_OPT_PHY,
+	BT_IO_OPT_QOS,
 } BtIOOption;
 
 typedef enum {
@@ -58,7 +59,8 @@ typedef enum {
 	BT_IO_MODE_ERTM,
 	BT_IO_MODE_STREAMING,
 	BT_IO_MODE_LE_FLOWCTL,
-	BT_IO_MODE_EXT_FLOWCTL
+	BT_IO_MODE_EXT_FLOWCTL,
+	BT_IO_MODE_ISO
 } BtIOMode;
 
 typedef void (*BtIOConfirm)(GIOChannel *io, gpointer user_data);
diff --git a/tools/btiotest.c b/tools/btiotest.c
index cb8cc3534..c5def5044 100644
--- a/tools/btiotest.c
+++ b/tools/btiotest.c
@@ -29,6 +29,25 @@
 #define DEFAULT_ACCEPT_TIMEOUT 2
 static int opt_update_sec = 0;
 
+#define DEFAULT_IO_QOS \
+{ \
+	.interval = 10000, \
+	.latency = 10, \
+	.sdu = 40, \
+	.phy = 0x02, \
+	.rtn = 2, \
+}
+
+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,
+};
+
 struct io_data {
 	guint ref;
 	GIOChannel *io;
@@ -36,6 +55,8 @@ struct io_data {
 	int disconn;
 	int accept;
 	int voice;
+	struct bt_iso_qos *in_qos;
+	struct bt_iso_qos *out_qos;
 };
 
 static void io_data_unref(struct io_data *data)
@@ -67,6 +88,8 @@ static struct io_data *io_data_new(GIOChannel *io, int reject, int disconn,
 	data->reject = reject;
 	data->disconn = disconn;
 	data->accept = accept;
+	data->in_qos = &qos;
+	data->out_qos = &qos;
 
 	return io_data_ref(data);
 }
@@ -530,9 +553,86 @@ static void sco_listen(const char *src, gboolean defer, int reject,
 	g_io_channel_unref(sco_srv);
 }
 
+static void iso_connect(const char *src, const char *dst, int disconn)
+{
+	struct io_data *data;
+	GError *err = NULL;
+
+	printf("Connecting ISO to %s\n", dst);
+
+	data = io_data_new(NULL, -1, disconn, -1);
+
+	if (src)
+		data->io = bt_io_connect(connect_cb, data,
+						(GDestroyNotify) io_data_unref,
+						&err,
+						BT_IO_OPT_SOURCE, src,
+						BT_IO_OPT_DEST, dst,
+						BT_IO_OPT_MODE, BT_IO_MODE_ISO,
+						BT_IO_OPT_INVALID);
+	else
+		data->io = bt_io_connect(connect_cb, data,
+						(GDestroyNotify) io_data_unref,
+						&err,
+						BT_IO_OPT_DEST, dst,
+						BT_IO_OPT_MODE, BT_IO_MODE_ISO,
+						BT_IO_OPT_INVALID);
+
+	if (!data->io) {
+		printf("Connecting to %s failed: %s\n", dst, err->message);
+		g_error_free(err);
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void iso_listen(const char *src, gboolean defer, int reject,
+				int disconn, int accept)
+{
+	struct io_data *data;
+	BtIOConnect conn;
+	BtIOConfirm cfm;
+	GIOChannel *iso_srv;
+	GError *err = NULL;
+
+	printf("Listening for ISO connections\n");
+
+	if (defer) {
+		conn = NULL;
+		cfm = confirm_cb;
+	} else {
+		conn = connect_cb;
+		cfm = NULL;
+	}
+
+	data = io_data_new(NULL, reject, disconn, accept);
+
+	if (src)
+		iso_srv = bt_io_listen(conn, cfm, data,
+					(GDestroyNotify) io_data_unref,
+					&err,
+					BT_IO_OPT_SOURCE, src,
+					BT_IO_OPT_MODE, BT_IO_MODE_ISO,
+					BT_IO_OPT_INVALID);
+	else
+		iso_srv = bt_io_listen(conn, cfm, data,
+					(GDestroyNotify) io_data_unref,
+					&err,
+					BT_IO_OPT_MODE, BT_IO_MODE_ISO,
+					BT_IO_OPT_INVALID);
+
+	if (!iso_srv) {
+		printf("Listening failed: %s\n", err->message);
+		g_error_free(err);
+		exit(EXIT_FAILURE);
+	}
+
+	g_io_channel_unref(iso_srv);
+}
+
 static int opt_channel = -1;
 static int opt_psm = 0;
 static gboolean opt_sco = FALSE;
+static gboolean opt_iso = FALSE;
 static gboolean opt_defer = FALSE;
 static gint opt_voice = 0;
 static char *opt_dev = NULL;
@@ -559,6 +659,8 @@ static GOptionEntry options[] = {
 				"(0 BR/EDR 1 LE Public 2 LE Random" },
 	{ "sco", 's', 0, G_OPTION_ARG_NONE, &opt_sco,
 				"Use SCO" },
+	{ "iso", 'o', 0, G_OPTION_ARG_NONE, &opt_iso,
+				"Use ISO" },
 	{ "defer", 'd', 0, G_OPTION_ARG_NONE, &opt_defer,
 				"Use DEFER_SETUP for incoming connections" },
 	{ "voice", 'V', 0, G_OPTION_ARG_INT, &opt_voice,
@@ -635,6 +737,14 @@ int main(int argc, char *argv[])
 					opt_disconn, opt_accept, opt_voice);
 	}
 
+	if (opt_iso) {
+		if (argc > 1)
+			iso_connect(opt_dev, argv[1], opt_disconn);
+		else
+			iso_listen(opt_dev, opt_defer, opt_reject,
+					opt_disconn, opt_accept);
+	}
+
 	signal(SIGTERM, sig_term);
 	signal(SIGINT, sig_term);
 
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH BlueZ 4/4] tools: Add iso-tester
  2020-12-21 23:01 [PATCH BlueZ 1/4] lib: Add definitions for ISO socket Luiz Augusto von Dentz
  2020-12-21 23:01 ` [PATCH BlueZ 2/4] tools: Add isotest tool Luiz Augusto von Dentz
  2020-12-21 23:01 ` [PATCH BlueZ 3/4] btio: Add support for ISO sockets Luiz Augusto von Dentz
@ 2020-12-21 23:01 ` Luiz Augusto von Dentz
  2020-12-21 23:42 ` [BlueZ,1/4] lib: Add definitions for ISO socket bluez.test.bot
  3 siblings, 0 replies; 5+ messages in thread
From: Luiz Augusto von Dentz @ 2020-12-21 23:01 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds iso-tester which tests BTPROTO_ISO socket:

Basic Framework - Success
Basic ISO Socket - Success
Basic ISO Get Socket Option - Success
Basic ISO Set Socket Option - Success
ISO QoS 8_1_1 - Success
ISO QoS 8_2_1 - Success
ISO QoS 16_1_1 - Success
ISO QoS 16_2_1 - Success
ISO QoS 24_1_1 - Success
ISO QoS 24_2_1 - Success
ISO QoS 32_1_1 - Success
ISO QoS 32_2_1 - Success
ISO QoS 44_1_1 - Success
ISO QoS 44_2_1 - Success
ISO QoS 48_1_1 - Success
ISO QoS 48_2_1 - Success
ISO QoS 48_3_1 - Success
ISO QoS 48_4_1 - Success
ISO QoS 48_5_1 - Success
ISO QoS 48_6_1 - Success
ISO QoS 8_1_2 - Success
ISO QoS 8_2_2 - Success
ISO QoS 16_1_2 - Success
ISO QoS 16_2_2 - Success
ISO QoS 24_1_2 - Success
ISO QoS 24_2_2 - Success
ISO QoS 32_1_2 - Success
ISO QoS 32_2_2 - Success
ISO QoS 44_1_2 - Success
ISO QoS 44_2_2 - Success
ISO QoS 48_1_2 - Success
ISO QoS 48_2_2 - Success
ISO QoS 48_3_2 - Success
ISO QoS 48_4_2 - Success
ISO QoS 48_5_2 - Success
ISO QoS 48_6_2 - Success
ISO Connect2 - Success
---
 Makefile.tools      |  10 +-
 tools/iso-tester.c  | 998 ++++++++++++++++++++++++++++++++++++++++++++
 tools/test-runner.c |   5 +-
 3 files changed, 1010 insertions(+), 3 deletions(-)
 create mode 100644 tools/iso-tester.c

diff --git a/Makefile.tools b/Makefile.tools
index c1eb2778a..6dfbc9808 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -73,7 +73,7 @@ noinst_PROGRAMS += emulator/btvirt emulator/b1ee emulator/hfp \
 					tools/l2cap-tester tools/sco-tester \
 					tools/smp-tester tools/hci-tester \
 					tools/rfcomm-tester tools/bnep-tester \
-					tools/userchan-tester
+					tools/userchan-tester tools/iso-tester
 
 emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
 				emulator/serial.h emulator/serial.c \
@@ -173,6 +173,14 @@ tools_userchan_tester_SOURCES = tools/userchan-tester.c monitor/bt.h \
 				emulator/smp.c
 tools_userchan_tester_LDADD = lib/libbluetooth-internal.la \
 				src/libshared-glib.la $(GLIB_LIBS)
+
+tools_iso_tester_SOURCES = tools/iso-tester.c monitor/bt.h \
+				emulator/hciemu.h emulator/hciemu.c \
+				emulator/btdev.h emulator/btdev.c \
+				emulator/bthost.h emulator/bthost.c \
+				emulator/smp.c
+tools_iso_tester_LDADD = lib/libbluetooth-internal.la \
+				src/libshared-glib.la $(GLIB_LIBS)
 endif
 
 if TOOLS
diff --git a/tools/iso-tester.c b/tools/iso-tester.c
new file mode 100644
index 000000000..d722ea516
--- /dev/null
+++ b/tools/iso-tester.c
@@ -0,0 +1,998 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2020  Intel Corporation. All rights reserved.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/iso.h"
+#include "lib/mgmt.h"
+
+#include "monitor/bt.h"
+#include "emulator/bthost.h"
+#include "emulator/hciemu.h"
+
+#include "src/shared/tester.h"
+#include "src/shared/mgmt.h"
+#include "src/shared/util.h"
+
+#define QOS_IO(_interval, _latency, _sdu, _phy, _rtn) \
+{ \
+	.interval = _interval, \
+	.latency = _latency, \
+	.sdu = _sdu, \
+	.phy = _phy, \
+	.rtn = _rtn, \
+}
+
+#define QOS_FULL(_in, _out) \
+{ \
+	.cig = BT_ISO_QOS_CIG_UNSET, \
+	.cis = BT_ISO_QOS_CIS_UNSET, \
+	.sca = 0x07, \
+	.packing = 0x00, \
+	.framing = 0x00, \
+	.in = _in, \
+	.out = _out, \
+}
+
+#define QOS(_interval, _latency, _sdu, _phy, _rtn) \
+	QOS_FULL(QOS_IO(_interval, _latency, _sdu, _phy, _rtn), \
+		QOS_IO(_interval, _latency, _sdu, _phy, _rtn))
+
+#define QOS_OUT(_interval, _latency, _sdu, _phy, _rtn) \
+	QOS_FULL({}, QOS_IO(_interval, _latency, _sdu, _phy, _rtn))
+
+/* QoS Configuration settings for low latency audio data */
+#define QOS_8_1_1 QOS(7500, 8, 26, 0x02, 2)
+#define QOS_8_2_1 QOS(10000, 10, 30, 0x02, 2)
+#define QOS_16_1_1 QOS(7500, 8, 30, 0x02, 2)
+#define QOS_16_2_1 QOS(10000, 10, 40, 0x02, 2)
+#define QOS_24_1_1 QOS(7500, 8, 45, 0x02, 2)
+#define QOS_24_2_1 QOS(10000, 10, 60, 0x02, 2)
+#define QOS_32_1_1 QOS(7500, 8, 60, 0x02, 2)
+#define QOS_32_2_1 QOS(10000, 10, 80, 0x02, 2)
+#define QOS_44_1_1 QOS_OUT(8163, 24, 98, 0x02, 5)
+#define QOS_44_2_1 QOS_OUT(10884, 31, 130, 0x02, 5)
+#define QOS_48_1_1 QOS_OUT(7500, 15, 75, 0x02, 5)
+#define QOS_48_2_1 QOS_OUT(10000, 20, 100, 0x02, 5)
+#define QOS_48_3_1 QOS_OUT(7500, 15, 90, 0x02, 5)
+#define QOS_48_4_1 QOS_OUT(10000, 20, 120, 0x02, 5)
+#define QOS_48_5_1 QOS_OUT(7500, 15, 117, 0x02, 5)
+#define QOS_48_6_1 QOS_OUT(10000, 20, 155, 0x02, 5)
+/* QoS Configuration settings for high reliability audio data */
+#define QOS_8_1_2 QOS(7500, 45, 26, 0x02, 41)
+#define QOS_8_2_2 QOS(10000, 60, 30, 0x02, 53)
+#define QOS_16_1_2 QOS(7500, 45, 30, 0x02, 41)
+#define QOS_16_2_2 QOS(10000, 60, 40, 0x02, 47)
+#define QOS_24_1_2 QOS(7500, 45, 45, 0x02, 35)
+#define QOS_24_2_2 QOS(10000, 60, 60, 0x02, 41)
+#define QOS_32_1_2 QOS(7500, 45, 60, 0x02, 29)
+#define QOS_32_2_2 QOS(10000, 60, 80, 0x02, 35)
+#define QOS_44_1_2 QOS_OUT(8163, 54, 98, 0x02, 23)
+#define QOS_44_2_2 QOS_OUT(10884, 71, 130, 0x02, 23)
+#define QOS_48_1_2 QOS_OUT(7500, 45, 75, 0x02, 23)
+#define QOS_48_2_2 QOS_OUT(10000, 60, 100, 0x02, 23)
+#define QOS_48_3_2 QOS_OUT(7500, 45, 90, 0x02, 23)
+#define QOS_48_4_2 QOS_OUT(10000, 60, 120, 0x02, 23)
+#define QOS_48_5_2 QOS_OUT(7500, 45, 117, 0x02, 23)
+#define QOS_48_6_2 QOS_OUT(10000, 60, 155, 0x02, 23)
+
+struct test_data {
+	const void *test_data;
+	struct mgmt *mgmt;
+	uint16_t mgmt_index;
+	struct hciemu *hciemu;
+	enum hciemu_type hciemu_type;
+	unsigned int io_id[2];
+	uint8_t client_num;
+	int step;
+};
+
+struct iso_client_data {
+	struct bt_iso_qos qos;
+	int expect_err;
+};
+
+static void mgmt_debug(const char *str, void *user_data)
+{
+	const char *prefix = user_data;
+
+	tester_print("%s%s", prefix, str);
+}
+
+static void read_info_callback(uint8_t status, uint16_t length,
+					const void *param, void *user_data)
+{
+	struct test_data *data = tester_get_data();
+	const struct mgmt_rp_read_info *rp = param;
+	char addr[18];
+	uint16_t manufacturer;
+	uint32_t supported_settings, current_settings;
+
+	tester_print("Read Info callback");
+	tester_print("  Status: 0x%02x", status);
+
+	if (status || !param) {
+		tester_pre_setup_failed();
+		return;
+	}
+
+	ba2str(&rp->bdaddr, addr);
+	manufacturer = btohs(rp->manufacturer);
+	supported_settings = btohl(rp->supported_settings);
+	current_settings = btohl(rp->current_settings);
+
+	tester_print("  Address: %s", addr);
+	tester_print("  Version: 0x%02x", rp->version);
+	tester_print("  Manufacturer: 0x%04x", manufacturer);
+	tester_print("  Supported settings: 0x%08x", supported_settings);
+	tester_print("  Current settings: 0x%08x", current_settings);
+	tester_print("  Class: 0x%02x%02x%02x",
+			rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
+	tester_print("  Name: %s", rp->name);
+	tester_print("  Short name: %s", rp->short_name);
+
+	if (strcmp(hciemu_get_address(data->hciemu), addr)) {
+		tester_pre_setup_failed();
+		return;
+	}
+
+	tester_pre_setup_complete();
+}
+
+static void index_added_callback(uint16_t index, uint16_t length,
+					const void *param, void *user_data)
+{
+	struct test_data *data = tester_get_data();
+
+	tester_print("Index Added callback");
+	tester_print("  Index: 0x%04x", index);
+
+	data->mgmt_index = index;
+
+	mgmt_send(data->mgmt, MGMT_OP_READ_INFO, data->mgmt_index, 0, NULL,
+					read_info_callback, NULL, NULL);
+}
+
+static void index_removed_callback(uint16_t index, uint16_t length,
+					const void *param, void *user_data)
+{
+	struct test_data *data = tester_get_data();
+
+	tester_print("Index Removed callback");
+	tester_print("  Index: 0x%04x", index);
+
+	if (index != data->mgmt_index)
+		return;
+
+	mgmt_unregister_index(data->mgmt, data->mgmt_index);
+
+	mgmt_unref(data->mgmt);
+	data->mgmt = NULL;
+
+	tester_post_teardown_complete();
+}
+
+static void hciemu_debug(const char *str, void *user_data)
+{
+	const char *prefix = user_data;
+
+	tester_print("%s%s", prefix, str);
+}
+
+static void read_index_list_callback(uint8_t status, uint16_t length,
+					const void *param, void *user_data)
+{
+	struct test_data *data = tester_get_data();
+
+	tester_print("Read Index List callback");
+	tester_print("  Status: 0x%02x", status);
+
+	if (status || !param) {
+		tester_pre_setup_failed();
+		return;
+	}
+
+	mgmt_register(data->mgmt, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
+					index_added_callback, NULL, NULL);
+
+	mgmt_register(data->mgmt, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
+					index_removed_callback, NULL, NULL);
+
+	data->hciemu = hciemu_new_num(HCIEMU_TYPE_BREDRLE52, data->client_num);
+	if (!data->hciemu) {
+		tester_warn("Failed to setup HCI emulation");
+		tester_pre_setup_failed();
+		return;
+	}
+
+	if (tester_use_debug())
+		hciemu_set_debug(data->hciemu, hciemu_debug, "hciemu: ", NULL);
+
+	tester_print("New hciemu instance created");
+}
+
+static void test_pre_setup(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+
+	data->mgmt = mgmt_new_default();
+	if (!data->mgmt) {
+		tester_warn("Failed to setup management interface");
+		tester_pre_setup_failed();
+		return;
+	}
+
+	if (tester_use_debug())
+		mgmt_set_debug(data->mgmt, mgmt_debug, "mgmt: ", NULL);
+
+	mgmt_send(data->mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL,
+					read_index_list_callback, NULL, NULL);
+}
+
+static void test_post_teardown(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+
+	hciemu_unref(data->hciemu);
+	data->hciemu = NULL;
+}
+
+static void test_data_free(void *test_data)
+{
+	struct test_data *data = test_data;
+
+	if (data->io_id[0] > 0)
+		g_source_remove(data->io_id[0]);
+
+	if (data->io_id[1] > 0)
+		g_source_remove(data->io_id[1]);
+
+	free(data);
+}
+
+#define test_iso_full(name, data, setup, func, num) \
+	do { \
+		struct test_data *user; \
+		user = new0(struct test_data, 1); \
+		if (!user) \
+			break; \
+		user->hciemu_type = HCIEMU_TYPE_BREDRLE; \
+		user->test_data = data; \
+		user->client_num = num; \
+		tester_add_full(name, data, \
+				test_pre_setup, setup, func, NULL, \
+				test_post_teardown, 2, user, test_data_free); \
+	} while (0)
+
+#define test_iso(name, data, setup, func) \
+	test_iso_full(name, data, setup, func, 1)
+
+#define test_iso2(name, data, setup, func) \
+	test_iso_full(name, data, setup, func, 2)
+
+static const struct iso_client_data connect_8_1_1 = {
+	.qos = QOS_8_1_1,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_8_2_1 = {
+	.qos = QOS_8_2_1,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_16_1_1 = {
+	.qos = QOS_16_1_1,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_16_2_1 = {
+	.qos = QOS_16_2_1,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_24_1_1 = {
+	.qos = QOS_24_1_1,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_24_2_1 = {
+	.qos = QOS_24_2_1,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_32_1_1 = {
+	.qos = QOS_32_1_1,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_32_2_1 = {
+	.qos = QOS_32_2_1,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_44_1_1 = {
+	.qos = QOS_44_1_1,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_44_2_1 = {
+	.qos = QOS_44_2_1,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_48_1_1 = {
+	.qos = QOS_48_1_1,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_48_2_1 = {
+	.qos = QOS_48_2_1,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_48_3_1 = {
+	.qos = QOS_48_3_1,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_48_4_1 = {
+	.qos = QOS_48_4_1,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_48_5_1 = {
+	.qos = QOS_48_5_1,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_48_6_1 = {
+	.qos = QOS_48_6_1,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_8_1_2 = {
+	.qos = QOS_8_1_2,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_8_2_2 = {
+	.qos = QOS_8_2_2,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_16_1_2 = {
+	.qos = QOS_16_1_2,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_16_2_2 = {
+	.qos = QOS_16_2_2,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_24_1_2 = {
+	.qos = QOS_24_1_2,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_24_2_2 = {
+	.qos = QOS_24_2_2,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_32_1_2 = {
+	.qos = QOS_32_1_2,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_32_2_2 = {
+	.qos = QOS_32_2_2,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_44_1_2 = {
+	.qos = QOS_44_1_2,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_44_2_2 = {
+	.qos = QOS_44_2_2,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_48_1_2 = {
+	.qos = QOS_48_1_2,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_48_2_2 = {
+	.qos = QOS_48_2_2,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_48_3_2 = {
+	.qos = QOS_48_3_2,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_48_4_2 = {
+	.qos = QOS_48_4_2,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_48_5_2 = {
+	.qos = QOS_48_5_2,
+	.expect_err = 0
+};
+
+static const struct iso_client_data connect_48_6_2 = {
+	.qos = QOS_48_6_2,
+	.expect_err = 0
+};
+
+static void client_connectable_complete(uint16_t opcode, uint8_t status,
+					const void *param, uint8_t len,
+					void *user_data)
+{
+	struct test_data *data = user_data;
+	static uint8_t client_num;
+
+	if (opcode != BT_HCI_CMD_LE_SET_EXT_ADV_ENABLE)
+		return;
+
+	tester_print("Client %u set connectable status 0x%02x", client_num,
+								status);
+
+	client_num++;
+
+	if (status)
+		tester_setup_failed();
+	else if (data->client_num == client_num) {
+		tester_setup_complete();
+		client_num = 0;
+	}
+}
+
+static void setup_powered_callback(uint8_t status, uint16_t length,
+					const void *param, void *user_data)
+{
+	struct test_data *data = tester_get_data();
+	uint8_t i;
+
+	if (status != MGMT_STATUS_SUCCESS) {
+		tester_setup_failed();
+		return;
+	}
+
+	tester_print("Controller powered on");
+
+	for (i = 0; i < data->client_num; i++) {
+		struct hciemu_client *client;
+		struct bthost *host;
+
+		client = hciemu_get_client(data->hciemu, i);
+		host = hciemu_client_host(client);
+		bthost_set_cmd_complete_cb(host, client_connectable_complete,
+									data);
+		bthost_set_ext_adv_enable(host, 0x01);
+	}
+}
+
+static void setup_powered(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+	unsigned char param[] = { 0x01 };
+
+	tester_print("Powering on controller");
+
+	mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
+					sizeof(param), param,
+					NULL, NULL, NULL);
+
+	mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
+				sizeof(param), param, NULL, NULL, NULL);
+
+	mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+				sizeof(param), param, NULL, NULL, NULL);
+
+	mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+					sizeof(param), param,
+					setup_powered_callback, NULL, NULL);
+}
+
+static void test_framework(const void *test_data)
+{
+	tester_test_passed();
+}
+
+static void test_socket(const void *test_data)
+{
+	int sk;
+
+	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO);
+	if (sk < 0) {
+		tester_warn("Can't create socket: %s (%d)", strerror(errno),
+									errno);
+		tester_test_abort();
+		return;
+	}
+
+	close(sk);
+
+	tester_test_passed();
+}
+
+static void test_getsockopt(const void *test_data)
+{
+	int sk, err;
+	socklen_t len;
+	struct bt_iso_qos qos;
+
+	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO);
+	if (sk < 0) {
+		tester_warn("Can't create socket: %s (%d)", strerror(errno),
+									errno);
+		tester_test_abort();
+		return;
+	}
+
+	len = sizeof(qos);
+	memset(&qos, 0, len);
+
+	err = getsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &qos, &len);
+	if (err < 0) {
+		tester_warn("Can't get socket option : %s (%d)",
+							strerror(errno), errno);
+		tester_test_failed();
+		goto end;
+	}
+
+	tester_test_passed();
+
+end:
+	close(sk);
+}
+
+static void test_setsockopt(const void *test_data)
+{
+	int sk, err;
+	socklen_t len;
+	struct bt_iso_qos qos = QOS_16_1_2;
+
+	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO);
+	if (sk < 0) {
+		tester_warn("Can't create socket: %s (%d)", strerror(errno),
+									errno);
+		tester_test_abort();
+		goto end;
+	}
+
+	err = setsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &qos, sizeof(qos));
+	if (err < 0) {
+		tester_warn("Can't set socket option : %s (%d)",
+							strerror(errno), errno);
+		tester_test_failed();
+		goto end;
+	}
+
+	len = sizeof(qos);
+	memset(&qos, 0, len);
+
+	err = getsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &qos, &len);
+	if (err < 0) {
+		tester_warn("Can't get socket option : %s (%d)",
+							strerror(errno), errno);
+		tester_test_failed();
+		goto end;
+	}
+
+	tester_test_passed();
+
+end:
+	close(sk);
+}
+
+static int create_iso_sock(struct test_data *data)
+{
+	const uint8_t *master_bdaddr;
+	struct sockaddr_iso addr;
+	int sk, err;
+
+	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK, BTPROTO_ISO);
+	if (sk < 0) {
+		err = -errno;
+		tester_warn("Can't create socket: %s (%d)", strerror(errno),
+									errno);
+		return -EPROTONOSUPPORT;
+	}
+
+	master_bdaddr = hciemu_get_master_bdaddr(data->hciemu);
+	if (!master_bdaddr) {
+		tester_warn("No master bdaddr");
+		return -ENODEV;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.iso_family = AF_BLUETOOTH;
+	bacpy(&addr.iso_bdaddr, (void *) master_bdaddr);
+	addr.iso_bdaddr_type = BDADDR_LE_PUBLIC;
+
+	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		err = -errno;
+		tester_warn("Can't bind socket: %s (%d)", strerror(errno),
+									errno);
+		close(sk);
+		return err;
+	}
+
+	return sk;
+}
+
+static int connect_iso_sock(struct test_data *data, uint8_t num, int sk)
+{
+	const struct iso_client_data *isodata = data->test_data;
+	struct hciemu_client *client;
+	const uint8_t *client_bdaddr;
+	struct sockaddr_iso addr;
+	char str[18];
+	int err;
+
+	client = hciemu_get_client(data->hciemu, num);
+	if (!client) {
+		tester_warn("No client");
+		return -ENODEV;
+	}
+
+	client_bdaddr = hciemu_client_bdaddr(client);
+	if (!client_bdaddr) {
+		tester_warn("No client bdaddr");
+		return -ENODEV;
+	}
+
+	err = setsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &isodata->qos,
+						sizeof(isodata->qos));
+	if (err < 0) {
+		tester_warn("Can't set socket option : %s (%d)",
+							strerror(errno), errno);
+		tester_test_failed();
+		return -EINVAL;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.iso_family = AF_BLUETOOTH;
+	bacpy(&addr.iso_bdaddr, (void *) client_bdaddr);
+	addr.iso_bdaddr_type = BDADDR_LE_PUBLIC;
+
+	ba2str(&addr.iso_bdaddr, str);
+
+	tester_print("Connecting to %s...", str);
+
+	err = connect(sk, (struct sockaddr *) &addr, sizeof(addr));
+	if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) {
+		err = -errno;
+		tester_warn("Can't connect socket: %s (%d)", strerror(errno),
+									errno);
+		return err;
+	}
+
+	return 0;
+}
+
+static bool check_io_qos(const struct bt_iso_io_qos *io1,
+				const struct bt_iso_io_qos *io2)
+{
+	if (io1->interval != io2->interval) {
+		tester_warn("Unexpected IO interval: %u != %u",
+				io1->interval, io2->interval);
+		return false;
+	}
+
+	if (io1->latency != io2->latency) {
+		tester_warn("Unexpected IO latency: %u != %u",
+				io1->latency, io2->latency);
+		return false;
+	}
+
+	if (io1->sdu != io2->sdu) {
+		tester_warn("Unexpected IO SDU: %u != %u", io1->sdu, io2->sdu);
+		return false;
+	}
+
+	if (io2->phy && io1->phy != io2->phy) {
+		tester_warn("Unexpected IO PHY: 0x%02x != 0x%02x",
+				io1->phy, io2->phy);
+		return false;
+	}
+
+	if (io1->rtn != io2->rtn) {
+		tester_warn("Unexpected IO RTN: %u != %u", io1->rtn, io2->rtn);
+		return false;
+	}
+
+	return true;
+}
+
+static bool check_qos(const struct bt_iso_qos *qos1,
+				const struct bt_iso_qos *qos2)
+{
+	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 (!check_io_qos(&qos1->in, &qos2->in)) {
+		tester_warn("Unexpected Input QoS");
+		return false;
+	}
+
+	if (!check_io_qos(&qos1->out, &qos2->out)) {
+		tester_warn("Unexpected Output QoS");
+		return false;
+	}
+
+	return true;
+}
+
+static gboolean iso_connect(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	struct test_data *data = tester_get_data();
+	const struct iso_client_data *isodata = data->test_data;
+	int err, sk_err, sk;
+	socklen_t len;
+	struct bt_iso_qos qos;
+
+	data->io_id[0] = 0;
+
+	sk = g_io_channel_unix_get_fd(io);
+
+	len = sizeof(qos);
+	memset(&qos, 0, len);
+
+	err = getsockopt(sk, SOL_BLUETOOTH, BT_ISO_QOS, &qos, &len);
+	if (err < 0) {
+		tester_warn("Can't get socket option : %s (%d)",
+							strerror(errno), errno);
+		tester_test_failed();
+		return FALSE;
+	}
+
+	if (!check_qos(&qos, &isodata->qos)) {
+		tester_warn("Unexpected QoS parameter");
+		tester_test_failed();
+		return FALSE;
+	}
+
+	len = sizeof(sk_err);
+
+	if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+		err = -errno;
+	else
+		err = -sk_err;
+
+	if (err < 0)
+		tester_warn("Connect failed: %s (%d)", strerror(-err), -err);
+	else
+		tester_print("Successfully connected");
+
+	if (-err != isodata->expect_err)
+		tester_test_failed();
+	else {
+		data->step--;
+		if (data->step)
+			tester_print("Step %u", data->step);
+		else
+			tester_test_passed();
+	}
+
+	return FALSE;
+}
+
+static gboolean iso_connect_cb(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	struct test_data *data = tester_get_data();
+
+	data->io_id[0] = 0;
+
+	return iso_connect(io, cond, user_data);
+}
+
+static gboolean iso_connect2_cb(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	struct test_data *data = tester_get_data();
+
+	data->io_id[1] = 0;
+
+	return iso_connect(io, cond, user_data);
+}
+
+static void setup_connect(struct test_data *data, uint8_t num, GIOFunc func)
+{
+	GIOChannel *io;
+	int sk;
+
+	sk = create_iso_sock(data);
+	if (sk < 0) {
+		if (sk == -EPROTONOSUPPORT)
+			tester_test_abort();
+		else
+			tester_test_failed();
+		return;
+	}
+
+	if (connect_iso_sock(data, num, sk) < 0) {
+		close(sk);
+		tester_test_failed();
+		return;
+	}
+
+	io = g_io_channel_unix_new(sk);
+	g_io_channel_set_close_on_unref(io, TRUE);
+
+	data->io_id[num] = g_io_add_watch(io, G_IO_OUT, func, NULL);
+
+	g_io_channel_unref(io);
+
+	tester_print("Connect in progress");
+
+	data->step++;
+}
+
+static void test_connect(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+
+	setup_connect(data, 0, iso_connect_cb);
+}
+
+static void test_connect2(const void *test_data)
+{
+	struct test_data *data = tester_get_data();
+
+	setup_connect(data, 0, iso_connect_cb);
+	setup_connect(data, 1, iso_connect2_cb);
+}
+
+int main(int argc, char *argv[])
+{
+	tester_init(&argc, &argv);
+
+	test_iso("Basic Framework - Success", NULL, setup_powered,
+							test_framework);
+
+	test_iso("Basic ISO Socket - Success", NULL, setup_powered,
+							test_socket);
+
+	test_iso("Basic ISO Get Socket Option - Success", NULL, setup_powered,
+							test_getsockopt);
+
+	test_iso("Basic ISO Set Socket Option - Success", NULL, setup_powered,
+							test_setsockopt);
+
+	test_iso("ISO QoS 8_1_1 - Success", &connect_8_1_1, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 8_2_1 - Success", &connect_8_2_1, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 16_1_1 - Success", &connect_16_1_1, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 16_2_1 - Success", &connect_16_2_1, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 24_1_1 - Success", &connect_24_1_1, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 24_2_1 - Success", &connect_24_2_1, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 32_1_1 - Success", &connect_32_1_1, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 32_2_1 - Success", &connect_32_2_1, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 44_1_1 - Success", &connect_44_1_1, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 44_2_1 - Success", &connect_44_2_1, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 48_1_1 - Success", &connect_48_1_1, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 48_2_1 - Success", &connect_48_2_1, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 48_3_1 - Success", &connect_48_3_1, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 48_4_1 - Success", &connect_48_4_1, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 48_5_1 - Success", &connect_48_5_1, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 48_6_1 - Success", &connect_48_6_1, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 8_1_2 - Success", &connect_8_1_2, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 8_2_2 - Success", &connect_8_2_2, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 16_1_2 - Success", &connect_16_1_2, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 16_2_2 - Success", &connect_16_2_2, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 24_1_2 - Success", &connect_24_1_2, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 24_2_2 - Success", &connect_24_2_2, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 32_1_2 - Success", &connect_32_1_2, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 32_2_2 - Success", &connect_32_2_2, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 44_1_2 - Success", &connect_44_1_2, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 44_2_2 - Success", &connect_44_2_2, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 48_1_2 - Success", &connect_48_1_2, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 48_2_2 - Success", &connect_48_2_2, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 48_3_2 - Success", &connect_48_3_2, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 48_4_2 - Success", &connect_48_4_2, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 48_5_2 - Success", &connect_48_5_2, setup_powered,
+							test_connect);
+
+	test_iso("ISO QoS 48_6_2 - Success", &connect_48_6_2, setup_powered,
+							test_connect);
+
+	test_iso2("ISO Connect2 - Success", &connect_16_2_1, setup_powered,
+							test_connect2);
+
+	return tester_run();
+}
diff --git a/tools/test-runner.c b/tools/test-runner.c
index a17ec594a..c27f7549e 100644
--- a/tools/test-runner.c
+++ b/tools/test-runner.c
@@ -188,7 +188,6 @@ static char *const qemu_argv[] = {
 	"-machine", "type=q35,accel=kvm:tcg",
 	"-m", "192M",
 	"-nographic",
-	"-vga", "none",
 	"-net", "none",
 	"-no-acpi",
 	"-no-hpet",
@@ -245,7 +244,7 @@ static void start_qemu(void)
 	snprintf(cmdline, sizeof(cmdline),
 				"console=ttyS0,115200n8 earlyprintk=serial "
 				"rootfstype=9p "
-				"rootflags=trans=virtio,version=9p2000.L "
+				"rootflags=trans=virtio,version=9p2000.u "
 				"acpi=off pci=noacpi noapic quiet ro init=%s "
 				"TESTHOME=%s TESTDBUS=%u TESTMONITOR=%u "
 				"TESTDEVS=%d TESTAUTO=%u TESTARGS=\'%s\'",
@@ -523,6 +522,7 @@ static const char *test_table[] = {
 	"l2cap-tester",
 	"rfcomm-tester",
 	"sco-tester",
+	"iso-tester",
 	"bnep-tester",
 	"check-selftest",
 	"tools/mgmt-tester",
@@ -530,6 +530,7 @@ static const char *test_table[] = {
 	"tools/l2cap-tester",
 	"tools/rfcomm-tester",
 	"tools/sco-tester",
+	"tools/iso-tester",
 	"tools/bnep-tester",
 	"tools/check-selftest",
 	NULL
-- 
2.26.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* RE: [BlueZ,1/4] lib: Add definitions for ISO socket
  2020-12-21 23:01 [PATCH BlueZ 1/4] lib: Add definitions for ISO socket Luiz Augusto von Dentz
                   ` (2 preceding siblings ...)
  2020-12-21 23:01 ` [PATCH BlueZ 4/4] tools: Add iso-tester Luiz Augusto von Dentz
@ 2020-12-21 23:42 ` bluez.test.bot
  3 siblings, 0 replies; 5+ messages in thread
From: bluez.test.bot @ 2020-12-21 23:42 UTC (permalink / raw)
  To: linux-bluetooth, luiz.dentz

[-- Attachment #1: Type: text/plain, Size: 5662 bytes --]

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=405035

---Test result---

##############################
Test: CheckPatch - FAIL
Output:
lib: Add definitions for ISO socket
WARNING:SPDX_LICENSE_TAG: Missing or malformed SPDX-License-Identifier tag in line 1
#55: FILE: lib/iso.h:1:
+/*

ERROR:FSF_MAILING_ADDRESS: Do not include the paragraph about writing to the Free Software Foundation's mailing address from the sample GPL notice. The FSF has changed addresses in the past, and may do so again. Linux already includes a copy of the GPL.
#73: FILE: lib/iso.h:19:
+ *  along with this program; if not, write to the Free Software$

ERROR:FSF_MAILING_ADDRESS: Do not include the paragraph about writing to the Free Software Foundation's mailing address from the sample GPL notice. The FSF has changed addresses in the past, and may do so again. Linux already includes a copy of the GPL.
#74: FILE: lib/iso.h:20:
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA$

- total: 2 errors, 1 warnings, 81 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.

"[PATCH] lib: Add definitions for ISO socket" has style problems, please review.

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

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

tools: Add isotest tool
ERROR:INITIALISED_STATIC: do not initialise statics to 0
#91: FILE: tools/isotest.c:55:
+static int defer_setup = 0;

ERROR:GLOBAL_INITIALISERS: do not initialise globals to NULL
#93: FILE: tools/isotest.c:57:
+struct bt_iso_qos *iso_qos = NULL;

ERROR:SPACING: space required after that ',' (ctx:VxV)
#271: FILE: tools/isotest.c:235:
+		syslog(LOG_ERR,"Can not listen on the socket: %s (%d)",
 		              ^

ERROR:SPACING: space required after that ',' (ctx:VxV)
#276: FILE: tools/isotest.c:240:
+	syslog(LOG_INFO,"Waiting for connection ...");
 	               ^

ERROR:SPACING: space required after that ',' (ctx:VxV)
#284: FILE: tools/isotest.c:248:
+			syslog(LOG_ERR,"Accept failed: %s (%d)",
 			              ^

ERROR:SPACING: space required after that ',' (ctx:VxV)
#337: FILE: tools/isotest.c:301:
+	syslog(LOG_INFO,"Receiving ...");
 	               ^

ERROR:SPACING: space required after that ',' (ctx:VxV)
#353: FILE: tools/isotest.c:317:
+	struct timeval tv_beg,tv_end,tv_diff;
 	                     ^

ERROR:SPACING: space required after that ',' (ctx:VxV)
#353: FILE: tools/isotest.c:317:
+	struct timeval tv_beg,tv_end,tv_diff;
 	                            ^

ERROR:SPACING: space required after that ',' (ctx:VxV)
#399: FILE: tools/isotest.c:363:
+		syslog(LOG_INFO,"%ld bytes in %.2f sec speed %.2f kb/s", total,
 		               ^

ERROR:SPACING: space required after that ',' (ctx:VxV)
#409: FILE: tools/isotest.c:373:
+	syslog(LOG_INFO,"Opening %s ...", filename);
 	               ^

ERROR:SPACING: space required after that ',' (ctx:VxV)
#455: FILE: tools/isotest.c:419:
+	syslog(LOG_INFO,"Sending ...");
 	               ^

ERROR:SPACING: space required before the open brace '{'
#519: FILE: tools/isotest.c:483:
+		for (i = 0; i < 10; i++){

ERROR:SPACING: space prohibited before that ',' (ctx:WxV)
#661: FILE: tools/isotest.c:625:
+int main(int argc ,char *argv[])
                   ^

ERROR:SPACING: space required after that ',' (ctx:WxV)
#661: FILE: tools/isotest.c:625:
+int main(int argc ,char *argv[])
                   ^

ERROR:SPACING: space required before the open parenthesis '('
#683: FILE: tools/isotest.c:647:
+		switch(opt) {

WARNING:PREFER_FALLTHROUGH: Prefer 'fallthrough;' over fallthrough comment
#797: FILE: tools/isotest.c:761:
+		/* Fallthrough */

- total: 15 errors, 1 warnings, 862 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.

"[PATCH] tools: Add isotest tool" has style problems, please review.

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

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

btio: Add support for ISO sockets
WARNING:LINE_SPACING: Missing a blank line after declarations
#52: FILE: btio/btio.c:781:
+		int error = -errno;
+		ERROR_FAILED(err, "sco_bind", errno);

- total: 0 errors, 1 warnings, 419 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.

"[PATCH] btio: Add support for ISO sockets" has style problems, please review.

NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED 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: CheckGitLint - FAIL
Output:
lib: Add definitions for ISO socket
3: B6 Body message is missing


##############################
Test: CheckBuild - PASS

##############################
Test: MakeCheck - PASS



---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-12-21 23:43 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-21 23:01 [PATCH BlueZ 1/4] lib: Add definitions for ISO socket Luiz Augusto von Dentz
2020-12-21 23:01 ` [PATCH BlueZ 2/4] tools: Add isotest tool Luiz Augusto von Dentz
2020-12-21 23:01 ` [PATCH BlueZ 3/4] btio: Add support for ISO sockets Luiz Augusto von Dentz
2020-12-21 23:01 ` [PATCH BlueZ 4/4] tools: Add iso-tester Luiz Augusto von Dentz
2020-12-21 23:42 ` [BlueZ,1/4] lib: Add definitions for ISO socket bluez.test.bot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.