diff mbox series

[BlueZ,v1,1/3] l2cap-tester: Add tests for multiple data packets

Message ID 20240626150229.103047-1-luiz.dentz@gmail.com
State New
Headers show
Series [BlueZ,v1,1/3] l2cap-tester: Add tests for multiple data packets | expand

Commit Message

Luiz Augusto von Dentz June 26, 2024, 3:02 p.m. UTC
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds the following tests which cover the TX/RX of multiple
packets (up to 32K):

L2CAP BR/EDR Client - Read 32k Success
L2CAP BR/EDR Client - Write 32k Success
L2CAP BR/EDR Server - Read 32k Success
L2CAP BR/EDR Server - Write 32k Success
---
 tools/l2cap-tester.c | 294 ++++++++++++++++++++++++++-----------------
 1 file changed, 180 insertions(+), 114 deletions(-)

Comments

patchwork-bot+bluetooth@kernel.org June 27, 2024, 6:40 p.m. UTC | #1
Hello:

This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Wed, 26 Jun 2024 11:02:27 -0400 you wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> This adds the following tests which cover the TX/RX of multiple
> packets (up to 32K):
> 
> L2CAP BR/EDR Client - Read 32k Success
> L2CAP BR/EDR Client - Write 32k Success
> L2CAP BR/EDR Server - Read 32k Success
> L2CAP BR/EDR Server - Write 32k Success
> 
> [...]

Here is the summary with links:
  - [BlueZ,v1,1/3] l2cap-tester: Add tests for multiple data packets
    (no matching commit)
  - [BlueZ,v1,2/3] bthost: Introduce bthost_add_l2cap_server_custom
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=b6f8c0024a87
  - [BlueZ,v1,3/3] l2cap-tester: Add tests for multiple data packets over LE
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=72c3f5bf1ce6

You are awesome, thank you!
diff mbox series

Patch

diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c
index c34080654ed6..b6b879407115 100644
--- a/tools/l2cap-tester.c
+++ b/tools/l2cap-tester.c
@@ -45,6 +45,7 @@  struct test_data {
 	uint16_t handle;
 	uint16_t scid;
 	uint16_t dcid;
+	struct l2cap_options l2o;
 	int sk;
 	int sk2;
 	bool host_disconnected;
@@ -332,6 +333,16 @@  static const struct l2cap_data client_connect_pin_success_test = {
 
 static uint8_t l2_data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
 
+const uint8_t l2_data_32k[32768] = { [0 ... 4095] =  0x00,
+				[4096 ... 8191] =  0x01,
+				[8192 ... 12287] =  0x02,
+				[12288 ... 16383] =  0x03,
+				[16384 ... 20479] =  0x04,
+				[20480 ... 24575] =  0x05,
+				[24576 ... 28671] =  0x06,
+				[28672 ... 32767] =  0x07,
+};
+
 static const struct l2cap_data client_connect_read_success_test = {
 	.client_psm = 0x1001,
 	.server_psm = 0x1001,
@@ -339,6 +350,13 @@  static const struct l2cap_data client_connect_read_success_test = {
 	.data_len = sizeof(l2_data),
 };
 
+static const struct l2cap_data client_connect_read_32k_success_test = {
+	.client_psm = 0x1001,
+	.server_psm = 0x1001,
+	.read_data = l2_data_32k,
+	.data_len = sizeof(l2_data_32k),
+};
+
 static const struct l2cap_data client_connect_write_success_test = {
 	.client_psm = 0x1001,
 	.server_psm = 0x1001,
@@ -346,6 +364,13 @@  static const struct l2cap_data client_connect_write_success_test = {
 	.data_len = sizeof(l2_data),
 };
 
+static const struct l2cap_data client_connect_write_32k_success_test = {
+	.client_psm = 0x1001,
+	.server_psm = 0x1001,
+	.write_data = l2_data_32k,
+	.data_len = sizeof(l2_data_32k),
+};
+
 static const struct l2cap_data client_connect_tx_timestamping_test = {
 	.client_psm = 0x1001,
 	.server_psm = 0x1001,
@@ -399,6 +424,16 @@  static const struct l2cap_data l2cap_server_read_success_test = {
 	.data_len = sizeof(l2_data),
 };
 
+static const struct l2cap_data l2cap_server_read_32k_success_test = {
+	.server_psm = 0x1001,
+	.send_cmd_code = BT_L2CAP_PDU_CONN_REQ,
+	.send_cmd = l2cap_connect_req,
+	.send_cmd_len = sizeof(l2cap_connect_req),
+	.expect_cmd_code = BT_L2CAP_PDU_CONN_RSP,
+	.read_data = l2_data_32k,
+	.data_len = sizeof(l2_data_32k),
+};
+
 static const struct l2cap_data l2cap_server_write_success_test = {
 	.server_psm = 0x1001,
 	.send_cmd_code = BT_L2CAP_PDU_CONN_REQ,
@@ -409,6 +444,16 @@  static const struct l2cap_data l2cap_server_write_success_test = {
 	.data_len = sizeof(l2_data),
 };
 
+static const struct l2cap_data l2cap_server_write_32k_success_test = {
+	.server_psm = 0x1001,
+	.send_cmd_code = BT_L2CAP_PDU_CONN_REQ,
+	.send_cmd = l2cap_connect_req,
+	.send_cmd_len = sizeof(l2cap_connect_req),
+	.expect_cmd_code = BT_L2CAP_PDU_CONN_RSP,
+	.write_data = l2_data_32k,
+	.data_len = sizeof(l2_data_32k),
+};
+
 static const uint8_t l2cap_sec_block_rsp[] = {	0x00, 0x00,	/* dcid */
 						0x41, 0x00,	/* scid */
 						0x03, 0x00,	/* Sec Block */
@@ -1104,50 +1149,54 @@  static void test_basic(const void *test_data)
 	tester_test_passed();
 }
 
-static gboolean client_received_data(GIOChannel *io, GIOCondition cond,
-							gpointer user_data)
+static void received_data(struct test_data *tdata, const void *buf,
+					uint16_t len, const void *data,
+					uint16_t data_len)
 {
-	struct test_data *data = tester_get_data();
-	const struct l2cap_data *l2data = data->test_data;
-	char buf[1024];
-	int sk;
+	static struct iovec iov;
 
-	tester_debug("Client received data");
+	util_iov_append(&iov, buf, len);
 
-	sk = g_io_channel_unix_get_fd(io);
-	if (read(sk, buf, l2data->data_len) != l2data->data_len) {
-		tester_warn("Unable to read %u bytes", l2data->data_len);
+	tester_debug("read: %d/%zu", len, iov.iov_len);
+
+	/* Check if all the data has been received */
+	if (iov.iov_len < data_len)
+		return;
+
+	--tdata->step;
+
+	if (iov.iov_len != data_len || memcmp(iov.iov_base, data, data_len))
 		tester_test_failed();
-		return FALSE;
-	}
-
-	if (memcmp(buf, l2data->read_data, l2data->data_len))
-		tester_test_failed();
-	else
+	else if (!tdata->step)
 		tester_test_passed();
 
-	return FALSE;
+	free(iov.iov_base);
+	iov.iov_base = NULL;
+	iov.iov_len = 0;
 }
 
-static gboolean server_received_data(GIOChannel *io, GIOCondition cond,
+static gboolean sock_received_data(GIOChannel *io, GIOCondition cond,
 							gpointer user_data)
 {
 	struct test_data *data = tester_get_data();
 	const struct l2cap_data *l2data = data->test_data;
 	char buf[1024];
 	int sk;
+	ssize_t len;
 
 	sk = g_io_channel_unix_get_fd(io);
-	if (read(sk, buf, l2data->data_len) != l2data->data_len) {
-		tester_warn("Unable to read %u bytes", l2data->data_len);
+
+	len = read(sk, buf, sizeof(buf));
+	if (len < 0) {
+		tester_warn("Unable to read: %s (%d)", strerror(errno), errno);
 		tester_test_failed();
 		return FALSE;
 	}
 
-	if (memcmp(buf, l2data->read_data, l2data->data_len))
-		tester_test_failed();
-	else
-		tester_test_passed();
+	received_data(data, buf, len, l2data->read_data, l2data->data_len);
+
+	if (data->step)
+		return TRUE;
 
 	return FALSE;
 }
@@ -1158,36 +1207,7 @@  static void bthost_received_data(const void *buf, uint16_t len,
 	struct test_data *data = tester_get_data();
 	const struct l2cap_data *l2data = data->test_data;
 
-	tester_debug("BTHost received data: %u bytes", len);
-
-	--data->step;
-
-	if (len != l2data->data_len) {
-		tester_test_failed();
-		return;
-	}
-
-	if (memcmp(buf, l2data->write_data, l2data->data_len))
-		tester_test_failed();
-	else if (!data->step)
-		tester_test_passed();
-}
-
-static void server_bthost_received_data(const void *buf, uint16_t len,
-							void *user_data)
-{
-	struct test_data *data = tester_get_data();
-	const struct l2cap_data *l2data = data->test_data;
-
-	if (len != l2data->data_len) {
-		tester_test_failed();
-		return;
-	}
-
-	if (memcmp(buf, l2data->write_data, l2data->data_len))
-		tester_test_failed();
-	else
-		tester_test_passed();
+	received_data(data, buf, len, l2data->write_data, l2data->data_len);
 }
 
 static gboolean socket_closed_cb(GIOChannel *io, GIOCondition cond,
@@ -1234,27 +1254,26 @@  static gboolean socket_closed_cb(GIOChannel *io, GIOCondition cond,
 static bool check_mtu(struct test_data *data, int sk)
 {
 	const struct l2cap_data *l2data = data->test_data;
-	struct l2cap_options l2o;
 	socklen_t len;
 
-	memset(&l2o, 0, sizeof(l2o));
+	memset(&data->l2o, 0, sizeof(data->l2o));
 
 	if (data->hciemu_type == HCIEMU_TYPE_LE &&
 				(l2data->client_psm || l2data->server_psm)) {
 		/* LE CoC enabled kernels should support BT_RCVMTU and
 		 * BT_SNDMTU.
 		 */
-		len = sizeof(l2o.imtu);
+		len = sizeof(data->l2o.imtu);
 		if (getsockopt(sk, SOL_BLUETOOTH, BT_RCVMTU,
-							&l2o.imtu, &len) < 0) {
+						&data->l2o.imtu, &len) < 0) {
 			tester_warn("getsockopt(BT_RCVMTU): %s (%d)",
 					strerror(errno), errno);
 			return false;
 		}
 
-		len = sizeof(l2o.omtu);
+		len = sizeof(data->l2o.omtu);
 		if (getsockopt(sk, SOL_BLUETOOTH, BT_SNDMTU,
-							&l2o.omtu, &len) < 0) {
+						&data->l2o.omtu, &len) < 0) {
 			tester_warn("getsockopt(BT_SNDMTU): %s (%d)",
 					strerror(errno), errno);
 			return false;
@@ -1262,8 +1281,9 @@  static bool check_mtu(struct test_data *data, int sk)
 	} else {
 		/* For non-LE CoC enabled kernels we need to fall back to
 		 * L2CAP_OPTIONS, so test support for it as well */
-		len = sizeof(l2o);
-		if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0) {
+		len = sizeof(data->l2o);
+		if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &data->l2o,
+						&len) < 0) {
 			 tester_warn("getsockopt(L2CAP_OPTIONS): %s (%d)",
 						strerror(errno), errno);
 			 return false;
@@ -1326,6 +1346,84 @@  static void l2cap_tx_timestamping(struct test_data *data, GIOChannel *io)
 	data->err_io_id = g_io_add_watch(io, G_IO_ERR, recv_errqueue, data);
 }
 
+static int l2cap_send(int sk, const void *data, size_t len, uint16_t mtu)
+{
+	struct iovec iov = { (void *)data, len };
+	int err;
+	size_t total = 0;
+
+	len = MIN(mtu, len);
+
+	while (iov.iov_len) {
+		size_t l = MIN(iov.iov_len, len);
+
+		err = write(sk, util_iov_pull_mem(&iov, l), l);
+		if (err < 0)
+			return -errno;
+
+		total += err;
+		tester_debug("write: %d/%zu", err, total);
+	}
+
+	return total;
+}
+
+static void l2cap_read_data(struct test_data *data, GIOChannel *io,
+							uint16_t cid)
+{
+	const struct l2cap_data *l2data = data->test_data;
+	struct bthost *bthost;
+	struct iovec iov = { (void *)l2data->read_data, l2data->data_len };
+	size_t len;
+
+	data->step = 0;
+
+	bthost = hciemu_client_get_host(data->hciemu);
+	g_io_add_watch(io, G_IO_IN, sock_received_data, NULL);
+
+	len = MIN(iov.iov_len, data->l2o.imtu);
+
+	while (iov.iov_len) {
+		size_t l = MIN(iov.iov_len, len);
+
+		bthost_send_cid(bthost, data->handle, cid,
+					util_iov_pull_mem(&iov, l), l);
+	}
+
+	++data->step;
+}
+
+static void l2cap_write_data(struct test_data *data, GIOChannel *io,
+							uint16_t cid)
+{
+	const struct l2cap_data *l2data = data->test_data;
+	struct bthost *bthost;
+	ssize_t ret;
+	int sk;
+	unsigned int count;
+
+	sk = g_io_channel_unix_get_fd(io);
+
+	data->step = 0;
+
+	bthost = hciemu_client_get_host(data->hciemu);
+	bthost_add_cid_hook(bthost, data->handle, cid, bthost_received_data,
+							NULL);
+
+	l2cap_tx_timestamping(data, io);
+
+	for (count = 0; count < l2data->repeat_send + 1; ++count) {
+		ret = l2cap_send(sk, l2data->write_data, l2data->data_len,
+							data->l2o.omtu);
+		if (ret != l2data->data_len) {
+			tester_warn("Unable to write all data: "
+					"%zd != %u", ret, l2data->data_len);
+			tester_test_failed();
+		}
+		++data->step;
+	}
+}
+
 static gboolean l2cap_connect_cb(GIOChannel *io, GIOCondition cond,
 							gpointer user_data)
 {
@@ -1356,37 +1454,10 @@  static gboolean l2cap_connect_cb(GIOChannel *io, GIOCondition cond,
 	}
 
 	if (l2data->read_data) {
-		struct bthost *bthost;
-
-		bthost = hciemu_client_get_host(data->hciemu);
-		g_io_add_watch(io, G_IO_IN, client_received_data, NULL);
-
-		bthost_send_cid(bthost, data->handle, data->dcid,
-					l2data->read_data, l2data->data_len);
-
+		l2cap_read_data(data, io, data->dcid);
 		return FALSE;
 	} else if (l2data->write_data) {
-		struct bthost *bthost;
-		ssize_t ret;
-		unsigned int count;
-
-		data->step = 0;
-
-		bthost = hciemu_client_get_host(data->hciemu);
-		bthost_add_cid_hook(bthost, data->handle, data->dcid,
-					bthost_received_data, NULL);
-
-		l2cap_tx_timestamping(data, io);
-
-		for (count = 0; count < l2data->repeat_send + 1; ++count) {
-			ret = write(sk, l2data->write_data, l2data->data_len);
-			if (ret != l2data->data_len) {
-				tester_warn("Unable to write all data");
-				tester_test_failed();
-			}
-			++data->step;
-		}
-
+		l2cap_write_data(data, io, data->dcid);
 		return FALSE;
 	} else if (l2data->shut_sock_wr) {
 		g_io_add_watch(io, G_IO_HUP, socket_closed_cb, NULL);
@@ -2087,31 +2158,10 @@  static gboolean l2cap_accept_cb(GIOChannel *io, GIOCondition cond,
 	}
 
 	if (l2data->read_data) {
-		struct bthost *bthost;
-
-		bthost = hciemu_client_get_host(data->hciemu);
-		g_io_add_watch(io, G_IO_IN, server_received_data, NULL);
-		bthost_send_cid(bthost, data->handle, data->dcid,
-					l2data->read_data, l2data->data_len);
-
-		g_io_channel_unref(io);
-
+		l2cap_read_data(data, io, data->dcid);
 		return FALSE;
 	} else if (l2data->write_data) {
-		struct bthost *bthost;
-		ssize_t ret;
-
-		bthost = hciemu_client_get_host(data->hciemu);
-		bthost_add_cid_hook(bthost, data->handle, data->scid,
-					server_bthost_received_data, NULL);
-
-		ret = write(sk, l2data->write_data, l2data->data_len);
-
-		if (ret != l2data->data_len) {
-			tester_warn("Unable to write all data");
-			tester_test_failed();
-		}
-
+		l2cap_write_data(data, io, data->scid);
 		return FALSE;
 	}
 
@@ -2405,10 +2455,18 @@  int main(int argc, char *argv[])
 					&client_connect_read_success_test,
 					setup_powered_client, test_connect);
 
+	test_l2cap_bredr("L2CAP BR/EDR Client - Read 32k Success",
+					&client_connect_read_32k_success_test,
+					setup_powered_client, test_connect);
+
 	test_l2cap_bredr("L2CAP BR/EDR Client - Write Success",
 					&client_connect_write_success_test,
 					setup_powered_client, test_connect);
 
+	test_l2cap_bredr("L2CAP BR/EDR Client - Write 32k Success",
+					&client_connect_write_32k_success_test,
+					setup_powered_client, test_connect);
+
 	test_l2cap_bredr("L2CAP BR/EDR Client - TX Timestamping",
 					&client_connect_tx_timestamping_test,
 					setup_powered_client, test_connect);
@@ -2437,10 +2495,18 @@  int main(int argc, char *argv[])
 					&l2cap_server_read_success_test,
 					setup_powered_server, test_server);
 
+	test_l2cap_bredr("L2CAP BR/EDR Server - Read 32k Success",
+					&l2cap_server_read_32k_success_test,
+					setup_powered_server, test_server);
+
 	test_l2cap_bredr("L2CAP BR/EDR Server - Write Success",
 					&l2cap_server_write_success_test,
 					setup_powered_server, test_server);
 
+	test_l2cap_bredr("L2CAP BR/EDR Server - Write 32k Success",
+					&l2cap_server_write_32k_success_test,
+					setup_powered_server, test_server);
+
 	test_l2cap_bredr("L2CAP BR/EDR Server - Security Block",
 					&l2cap_server_sec_block_test,
 					setup_powered_server, test_server);