diff mbox series

[BlueZ] l2cap-tester: Add server tests for Ext-Flowctl

Message ID 20230310000049.3395992-1-luiz.dentz@gmail.com (mailing list archive)
State Superseded
Headers show
Series [BlueZ] l2cap-tester: Add server tests for Ext-Flowctl | expand

Commit Message

Luiz Augusto von Dentz March 10, 2023, midnight UTC
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds the following tests:

L2CAP Ext-Flowctl Server - Success
L2CAP Ext-Flowctl Server - Nval SCID
L2CAP LE EATT Client - Success
L2CAP LE EATT Server - Success
L2CAP LE EATT Server - Reject
---
 tools/l2cap-tester.c | 287 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 246 insertions(+), 41 deletions(-)
diff mbox series

Patch

diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c
index 3f04640131fa..922533f34133 100644
--- a/tools/l2cap-tester.c
+++ b/tools/l2cap-tester.c
@@ -15,6 +15,7 @@ 
 #include <stdlib.h>
 #include <unistd.h>
 #include <errno.h>
+#include <poll.h>
 #include <stdbool.h>
 
 #include <glib.h>
@@ -81,6 +82,7 @@  struct l2cap_data {
 	bool server_not_advertising;
 	bool direct_advertising;
 	bool close_1;
+	bool defer;
 
 	bool shut_sock_wr;
 };
@@ -540,6 +542,64 @@  static const struct l2cap_data le_server_nval_scid_test = {
 	.expect_cmd_len = sizeof(nval_le_connect_rsp),
 };
 
+static const uint8_t ecred_connect_req[] = {	0x80, 0x00, /* PSM */
+						0x40, 0x00, /* MTU */
+						0x40, 0x00, /* MPS */
+						0x05, 0x00, /* Credits */
+						0x41, 0x00, /* SCID #1 */
+						0x42, 0x00, /* SCID #2 */
+						0x43, 0x00, /* SCID #3 */
+						0x44, 0x00, /* SCID #4 */
+						0x45, 0x00, /* SCID #5 */
+};
+
+static const uint8_t ecred_connect_rsp[] = {	0xa0, 0x02, /* MTU */
+						0xbc, 0x00, /* MPS */
+						0x04, 0x00, /* Credits */
+						0x00, 0x00, /* Result */
+						0x40, 0x00, /* DCID #1 */
+						0x41, 0x00, /* DCID #2 */
+						0x42, 0x00, /* DCID #3 */
+						0x43, 0x00, /* DCID #4 */
+						0x44, 0x00, /* DCID #5 */
+};
+
+static const struct l2cap_data ext_flowctl_server_success_test = {
+	.server_psm = 0x0080,
+	.send_cmd_code = BT_L2CAP_PDU_ECRED_CONN_REQ,
+	.send_cmd = ecred_connect_req,
+	.send_cmd_len = sizeof(ecred_connect_req),
+	.expect_cmd_code = BT_L2CAP_PDU_ECRED_CONN_RSP,
+	.expect_cmd = ecred_connect_rsp,
+	.expect_cmd_len = sizeof(ecred_connect_rsp),
+};
+
+static const uint8_t nval_ecred_connect_req[] = {
+						0x80, 0x00, /* PSM */
+						0x40, 0x00, /* MTU */
+						0x40, 0x00, /* MPS */
+						0x05, 0x00, /* Credits */
+						0x01, 0x00, /* SCID #1 */
+};
+
+static const uint8_t nval_ecred_connect_rsp[] = {
+						0x00, 0x00, /* MTU */
+						0x00, 0x00, /* MPS */
+						0x00, 0x00, /* Credits */
+						0x09, 0x00, /* Result */
+						0x00, 0x00, /* DCID #1 */
+};
+
+static const struct l2cap_data ext_flowctl_server_nval_scid_test = {
+	.server_psm = 0x0080,
+	.send_cmd_code = BT_L2CAP_PDU_ECRED_CONN_REQ,
+	.send_cmd = nval_ecred_connect_req,
+	.send_cmd_len = sizeof(nval_ecred_connect_req),
+	.expect_cmd_code = BT_L2CAP_PDU_ECRED_CONN_RSP,
+	.expect_cmd = nval_ecred_connect_rsp,
+	.expect_cmd_len = sizeof(nval_ecred_connect_rsp),
+};
+
 static const struct l2cap_data le_att_client_connect_success_test_1 = {
 	.cid = 0x0004,
 	.sec_level = BT_SECURITY_LOW,
@@ -549,6 +609,69 @@  static const struct l2cap_data le_att_server_success_test_1 = {
 	.cid = 0x0004,
 };
 
+static const struct l2cap_data le_eatt_client_connect_success_test_1 = {
+	.client_psm = 0x0027,
+	.server_psm = 0x0027,
+	.mode = BT_MODE_EXT_FLOWCTL,
+	.sec_level = BT_SECURITY_LOW,
+};
+
+static const uint8_t eatt_connect_req[] = {	0x27, 0x00, /* PSM */
+						0x40, 0x00, /* MTU */
+						0x40, 0x00, /* MPS */
+						0x05, 0x00, /* Credits */
+						0x41, 0x00, /* SCID #1 */
+};
+
+static const uint8_t eatt_connect_rsp[] = {	0xa0, 0x02, /* MTU */
+						0xbc, 0x00, /* MPS */
+						0x04, 0x00, /* Credits */
+						0x00, 0x00, /* Result */
+						0x40, 0x00, /* DCID #1 */
+};
+
+static const struct l2cap_data le_eatt_server_success_test_1 = {
+	.server_psm = 0x0027,
+	.mode = BT_MODE_EXT_FLOWCTL,
+	.send_cmd_code = BT_L2CAP_PDU_ECRED_CONN_REQ,
+	.send_cmd = eatt_connect_req,
+	.send_cmd_len = sizeof(eatt_connect_req),
+	.expect_cmd_code = BT_L2CAP_PDU_ECRED_CONN_RSP,
+	.expect_cmd = eatt_connect_rsp,
+	.expect_cmd_len = sizeof(eatt_connect_rsp),
+	.defer = true,
+};
+
+static const uint8_t eatt_reject_req[] = {	0x27, 0x00, /* PSM */
+						0x40, 0x00, /* MTU */
+						0x40, 0x00, /* MPS */
+						0x05, 0x00, /* Credits */
+						0x41, 0x00, /* SCID #1 */
+						0x42, 0x00, /* SCID #2 */
+						0x43, 0x00, /* SCID #3 */
+						0x44, 0x00, /* SCID #4 */
+						0x45, 0x00, /* SCID #5 */
+};
+
+static const uint8_t eatt_reject_rsp[] = {	0xa0, 0x02, /* MTU */
+						0xbc, 0x00, /* MPS */
+						0x04, 0x00, /* Credits */
+						0x06, 0x00, /* Result */
+};
+
+static const struct l2cap_data le_eatt_server_reject_test_1 = {
+	.server_psm = 0x0027,
+	.mode = BT_MODE_EXT_FLOWCTL,
+	.send_cmd_code = BT_L2CAP_PDU_ECRED_CONN_REQ,
+	.send_cmd = eatt_reject_req,
+	.send_cmd_len = sizeof(eatt_reject_req),
+	.expect_cmd_code = BT_L2CAP_PDU_ECRED_CONN_RSP,
+	.expect_cmd = eatt_reject_rsp,
+	.expect_cmd_len = sizeof(eatt_reject_rsp),
+	.defer = true,
+	.expect_err = -1,
+};
+
 static const struct l2cap_data ext_flowctl_client_connect_success_test_1 = {
 	.client_psm = 0x0080,
 	.server_psm = 0x0080,
@@ -1689,6 +1812,89 @@  static void test_connect_2(const void *test_data)
 								defer);
 }
 
+static gboolean l2cap_accept_cb(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	struct test_data *data = tester_get_data();
+	const struct l2cap_data *l2data = data->test_data;
+	int sk;
+
+	sk = g_io_channel_unix_get_fd(io);
+
+	if (!check_mtu(data, sk)) {
+		tester_test_failed();
+		return FALSE;
+	}
+
+	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);
+
+		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();
+		}
+
+		return FALSE;
+	}
+
+	tester_print("Successfully connected");
+
+	tester_test_passed();
+
+	return FALSE;
+}
+
+static bool defer_accept(struct test_data *data, GIOChannel *io)
+{
+	int sk;
+	char c;
+	struct pollfd pfd;
+
+	sk = g_io_channel_unix_get_fd(io);
+
+	memset(&pfd, 0, sizeof(pfd));
+	pfd.fd = sk;
+	pfd.events = POLLOUT;
+
+	if (poll(&pfd, 1, 0) < 0) {
+		tester_warn("poll: %s (%d)", strerror(errno), errno);
+		return false;
+	}
+
+	if (!(pfd.revents & POLLOUT)) {
+		if (read(sk, &c, 1) < 0) {
+			tester_warn("read: %s (%d)", strerror(errno), errno);
+			return false;
+		}
+	}
+
+	data->io_id = g_io_add_watch(io, G_IO_OUT, l2cap_accept_cb, NULL);
+
+	g_io_channel_unref(io);
+
+	tester_print("Accept deferred setup");
+
+	return true;
+}
+
 static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond,
 							gpointer user_data)
 {
@@ -1707,53 +1913,24 @@  static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond,
 		return FALSE;
 	}
 
-	if (!check_mtu(data, new_sk)) {
-		tester_test_failed();
-		close(new_sk);
-		return FALSE;
-	}
+	io = g_io_channel_unix_new(new_sk);
+	g_io_channel_set_close_on_unref(io, TRUE);
 
-	if (l2data->read_data) {
-		struct bthost *bthost;
-		GIOChannel *new_io;
-
-		new_io = g_io_channel_unix_new(new_sk);
-		g_io_channel_set_close_on_unref(new_io, TRUE);
-
-		bthost = hciemu_client_get_host(data->hciemu);
-		g_io_add_watch(new_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(new_io);
-
-		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(new_sk, l2data->write_data, l2data->data_len);
-		close(new_sk);
-
-		if (ret != l2data->data_len) {
-			tester_warn("Unable to write all data");
-			tester_test_failed();
+	if (l2data->defer) {
+		if (l2data->expect_err < 0) {
+			g_io_channel_unref(io);
+			tester_test_passed();
+			return FALSE;
 		}
 
+		if (!defer_accept(data, io)) {
+			tester_warn("Unable to accept deferred setup");
+			tester_test_failed();
+		}
 		return FALSE;
 	}
 
-	tester_print("Successfully connected");
-
-	close(new_sk);
-
-	tester_test_passed();
-
-	return FALSE;
+	return l2cap_accept_cb(io, cond, user_data);
 }
 
 static void client_l2cap_rsp(uint8_t code, const void *data, uint16_t len,
@@ -1844,6 +2021,8 @@  static void test_server(const void *test_data)
 	int sk;
 
 	if (l2data->server_psm || l2data->cid) {
+		int opt = 1;
+
 		sk = create_l2cap_sock(data, l2data->server_psm,
 					l2data->cid, l2data->sec_level,
 					l2data->mode);
@@ -1852,6 +2031,15 @@  static void test_server(const void *test_data)
 			return;
 		}
 
+		if (l2data->defer && setsockopt(sk, SOL_BLUETOOTH,
+				BT_DEFER_SETUP, &opt, sizeof(opt)) < 0) {
+			tester_warn("Can't enable deferred setup: %s (%d)",
+						strerror(errno), errno);
+			tester_test_failed();
+			close(sk);
+			return;
+		}
+
 		if (listen(sk, 5) < 0) {
 			tester_warn("listening on socket failed: %s (%u)",
 					strerror(errno), errno);
@@ -2066,6 +2254,13 @@  int main(int argc, char *argv[])
 				setup_powered_client,
 				test_connect_2);
 
+	test_l2cap_le("L2CAP Ext-Flowctl Server - Success",
+				&ext_flowctl_server_success_test,
+				setup_powered_server, test_server);
+	test_l2cap_le("L2CAP Ext-Flowctl Server - Nval SCID",
+				&ext_flowctl_server_nval_scid_test,
+				setup_powered_server, test_server);
+
 	test_l2cap_le("L2CAP LE ATT Client - Success",
 				&le_att_client_connect_success_test_1,
 				setup_powered_client, test_connect);
@@ -2073,5 +2268,15 @@  int main(int argc, char *argv[])
 				&le_att_server_success_test_1,
 				setup_powered_server, test_server);
 
+	test_l2cap_le("L2CAP LE EATT Client - Success",
+				&le_eatt_client_connect_success_test_1,
+				setup_powered_client, test_connect);
+	test_l2cap_le("L2CAP LE EATT Server - Success",
+				&le_eatt_server_success_test_1,
+				setup_powered_server, test_server);
+	test_l2cap_le("L2CAP LE EATT Server - Reject",
+				&le_eatt_server_reject_test_1,
+				setup_powered_server, test_server);
+
 	return tester_run();
 }