Linux bluetooth development
 help / color / mirror / Atom feed
From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ v2 8/8] unit/test-gatt: Add Read Multiple Variable Length tests
Date: Fri,  6 Nov 2026 13:33:50 -0500	[thread overview]
Message-ID: <20261106183350.3155282-9-luiz.dentz@gmail.com> (raw)
In-Reply-To: <20261106183350.3155282-1-luiz.dentz@gmail.com>

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

Add client tests, using EATT client features, for regular and truncated
responses and for cancelling the request from the callback, and a
server test for the response.

Assisted-by: OpenCode:claude-opus-5.5
---
 unit/test-gatt.c | 169 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 165 insertions(+), 4 deletions(-)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index d032e7598f9b..267bcc61802e 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -119,6 +119,29 @@ struct context {
 		MTU_EXCHANGE_CLIENT_PDUS,				\
 		READ_SERVER_FEAT_PDUS
 
+#define EATT_CLIENT_INIT_PDUS						\
+		MTU_EXCHANGE_CLIENT_PDUS,				\
+		raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x3a, 0x2b),	\
+		raw_pdu(0x09, 0x03, 0x03, 0x00, 0x01),			\
+		raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),	\
+		raw_pdu(0x11, 0x06, 0x01, 0x00, 0x05, 0x00, 0x01, 0x18),\
+		raw_pdu(0x08, 0x04, 0x00, 0xff, 0xff, 0x3a, 0x2b),	\
+		raw_pdu(0x01, 0x08, 0x04, 0x00, 0x0a),			\
+		raw_pdu(0x10, 0x06, 0x00, 0xff, 0xff, 0x00, 0x28),	\
+		raw_pdu(0x01, 0x10, 0x06, 0x00, 0x0a),			\
+		raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28),	\
+		raw_pdu(0x01, 0x10, 0x01, 0x00, 0x0a),			\
+		raw_pdu(0x08, 0x01, 0x00, 0x05, 0x00, 0x02, 0x28),	\
+		raw_pdu(0x01, 0x08, 0x01, 0x00, 0x0a),			\
+		raw_pdu(0x08, 0x01, 0x00, 0x05, 0x00, 0x03, 0x28),	\
+		raw_pdu(0x09, 0x07, 0x02, 0x00, 0x02, 0x03, 0x00, 0x3a,	\
+				0x2b, 0x04, 0x00, 0x0a, 0x05, 0x00, 0x29,\
+				0x2b),					\
+		raw_pdu(0x08, 0x05, 0x00, 0x05, 0x00, 0x03, 0x28),	\
+		raw_pdu(0x01, 0x08, 0x05, 0x00, 0x0a),			\
+		raw_pdu(0x12, 0x05, 0x00, 0x07),			\
+		raw_pdu(0x13)
+
 #define SERVICE_DATA_1_PDUS						\
 		CLIENT_INIT_PDUS,					\
 		raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),	\
@@ -328,6 +351,7 @@ struct test_step {
 	uint8_t expected_att_ecode;
 	const uint8_t *value;
 	uint16_t length;
+	uint8_t features;
 };
 
 static void destroy_context(struct context *context)
@@ -624,7 +648,7 @@ static void client_ready_cb(bool success, uint8_t att_ecode, void *user_data)
 
 	g_assert(success);
 
-	if (!context->data->source_db) {
+	if (!context->data->source_db && !context->data->step) {
 		context_quit(context);
 		return;
 	}
@@ -632,8 +656,10 @@ static void client_ready_cb(bool success, uint8_t att_ecode, void *user_data)
 	g_assert(context->client);
 	g_assert(context->client_db);
 
-	gatt_db_foreach_service(context->client_db, NULL, match_services,
-						context->data->source_db);
+	if (context->data->source_db)
+		gatt_db_foreach_service(context->client_db, NULL,
+					match_services,
+					context->data->source_db);
 
 	if (context->data->step) {
 		const struct test_step *step = context->data->step;
@@ -653,6 +679,7 @@ static struct context *create_context(uint16_t mtu, gconstpointer data)
 {
 	struct context *context = g_new0(struct context, 1);
 	const struct test_data *test_data = data;
+	const struct test_step *step;
 	GIOChannel *channel;
 	int err, sv[2];
 
@@ -680,11 +707,14 @@ static struct context *create_context(uint16_t mtu, gconstpointer data)
 						"bt_gatt_server:", NULL);
 		break;
 	case CLIENT:
+		step = test_data->step;
+
 		context->client_db = gatt_db_new();
 		g_assert(context->client_db);
 
 		context->client = bt_gatt_client_new(context->client_db,
-							context->att, mtu, 0);
+						context->att, mtu,
+						step ? step->features : 0);
 		g_assert(context->client);
 
 		bt_gatt_client_set_debug(context->client, print_debug,
@@ -2149,6 +2179,109 @@ static const struct test_step test_multiple_read_6 = {
 	.expected_att_ecode = 0x0c
 };
 
+static void multiple_read_vl_cb(bool success, uint8_t att_ecode,
+					const uint8_t *value, uint16_t length,
+					void *user_data)
+{
+	struct context *context = user_data;
+	const struct test_step *step = context->data->step;
+	static uint16_t offset;
+
+	g_assert(success);
+	g_assert_cmpint(offset + 2 + length, <=, step->length);
+	g_assert_cmpint(get_le16(step->value + offset), ==, length);
+	g_assert(memcmp(value, step->value + offset + 2, length) == 0);
+
+	offset += 2 + length;
+	if (offset == step->length) {
+		offset = 0;
+		context_quit(context);
+	}
+}
+
+static void test_multiple_read_vl(struct context *context)
+{
+	const struct test_step *step = context->data->step;
+	uint16_t handles[2];
+
+	handles[0] = step->handle;
+	handles[1] = step->end_handle;
+
+	g_assert(bt_gatt_client_read_multiple(context->client, handles, 2,
+						multiple_read_vl_cb, context,
+						NULL));
+}
+
+static const uint8_t read_mult_vl_data_1[] = {
+	0x02, 0x00, 0x01, 0x02,
+	0x03, 0x00, 0x03, 0x04, 0x05
+};
+
+static const struct test_step test_multiple_read_vl_1 = {
+	.handle = 0x0003,
+	.end_handle = 0x0005,
+	.func = test_multiple_read_vl,
+	.value = read_mult_vl_data_1,
+	.length = sizeof(read_mult_vl_data_1),
+	.features = BT_GATT_CHRC_CLI_FEAT_EATT,
+};
+
+static const uint8_t read_mult_vl_data_2[] = {
+	0x02, 0x00, 0x01, 0x02,
+	0x01, 0x00, 0x03
+};
+
+static const struct test_step test_multiple_read_vl_2 = {
+	.handle = 0x0003,
+	.end_handle = 0x0005,
+	.func = test_multiple_read_vl,
+	.value = read_mult_vl_data_2,
+	.length = sizeof(read_mult_vl_data_2),
+	.features = BT_GATT_CHRC_CLI_FEAT_EATT,
+};
+
+static unsigned int multiple_read_vl_id;
+
+static void multiple_read_vl_cancel_cb(bool success, uint8_t att_ecode,
+					const uint8_t *value, uint16_t length,
+					void *user_data)
+{
+	struct context *context = user_data;
+	const struct test_step *step = context->data->step;
+
+	g_assert(success);
+	g_assert_cmpint(get_le16(step->value), ==, length);
+	g_assert(memcmp(value, step->value + 2, length) == 0);
+
+	g_assert(bt_gatt_client_cancel(context->client, multiple_read_vl_id));
+	multiple_read_vl_id = 0;
+
+	context_quit(context);
+}
+
+static void test_multiple_read_vl_cancel(struct context *context)
+{
+	const struct test_step *step = context->data->step;
+	uint16_t handles[2];
+
+	handles[0] = step->handle;
+	handles[1] = step->end_handle;
+
+	multiple_read_vl_id = bt_gatt_client_read_multiple(context->client,
+					handles, 2, multiple_read_vl_cancel_cb,
+					context, NULL);
+	g_assert(multiple_read_vl_id);
+}
+
+static const struct test_step test_multiple_read_vl_3 = {
+	.handle = 0x0003,
+	.end_handle = 0x0005,
+	.func = test_multiple_read_vl_cancel,
+	.value = read_mult_vl_data_1,
+	.length = sizeof(read_mult_vl_data_1),
+	.features = BT_GATT_CHRC_CLI_FEAT_EATT,
+};
+
 static void read_by_type_cb(bool success, uint8_t att_ecode,
 						struct bt_gatt_result *result,
 						void *user_data)
@@ -3378,6 +3511,27 @@ int main(int argc, char *argv[])
 			raw_pdu(0x0e, 0x03, 0x00, 0x07, 0x00),
 			raw_pdu(0x0f, 0x01, 0x02, 0x03));
 
+	define_test_client("/robustness/read-multiple-vl", test_client,
+			NULL, &test_multiple_read_vl_1,
+			EATT_CLIENT_INIT_PDUS,
+			raw_pdu(0x20, 0x03, 0x00, 0x05, 0x00),
+			raw_pdu(0x21, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00,
+					0x03, 0x04, 0x05));
+
+	define_test_client("/robustness/read-multiple-vl-truncated",
+			test_client, NULL, &test_multiple_read_vl_2,
+			EATT_CLIENT_INIT_PDUS,
+			raw_pdu(0x20, 0x03, 0x00, 0x05, 0x00),
+			raw_pdu(0x21, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00,
+					0x03));
+
+	define_test_client("/robustness/read-multiple-vl-cancel",
+			test_client, NULL, &test_multiple_read_vl_3,
+			EATT_CLIENT_INIT_PDUS,
+			raw_pdu(0x20, 0x03, 0x00, 0x05, 0x00),
+			raw_pdu(0x21, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00,
+					0x03, 0x04, 0x05));
+
 	define_test_client("/TP/GAR/CL/BI-22-C", test_client, service_db_1,
 			&test_multiple_read_6,
 			SERVICE_DATA_1_PDUS,
@@ -3390,6 +3544,13 @@ int main(int argc, char *argv[])
 			raw_pdu(0x0e, 0x15, 0xF0, 0x03, 0x00),
 			raw_pdu(0x0f, 0x09, 'B', 'l', 'u', 'e', 'Z'));
 
+	define_test_server("/robustness/read-multiple-vl/server",
+			test_server, ts_small_db, NULL,
+			raw_pdu(0x03, 0x00, 0x02),
+			raw_pdu(0x20, 0x15, 0xF0, 0x03, 0x00),
+			raw_pdu(0x21, 0x01, 0x00, 0x09, 0x05, 0x00, 'B', 'l',
+					'u', 'e', 'Z'));
+
 	define_test_server("/TP/GAR/SR/BV-05-C/large-1", test_server,
 			ts_large_db_1, NULL,
 			raw_pdu(0x03, 0x00, 0x02),
-- 
2.56.0


  parent reply	other threads:[~2026-11-06 18:33 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-06 18:33 [PATCH BlueZ v2 0/8] Fix handling of malformed GATT PDUs Luiz Augusto von Dentz
2026-11-06 18:33 ` [PATCH BlueZ v2 1/8] shared/gatt: Validate Read By Type responses Luiz Augusto von Dentz
2026-11-06 23:18   ` Fix handling of malformed GATT PDUs bluez.test.bot
2026-11-06 18:33 ` [PATCH BlueZ v2 2/8] unit/test-gatt: Add malformed Read By Type response tests Luiz Augusto von Dentz
2026-11-06 18:33 ` [PATCH BlueZ v2 3/8] shared/gatt-client: Fix handling of short notifications Luiz Augusto von Dentz
2026-11-06 18:33 ` [PATCH BlueZ v2 4/8] unit/test-gatt: Add short notification test Luiz Augusto von Dentz
2026-11-06 18:33 ` [PATCH BlueZ v2 5/8] shared/att: Add Read Multiple Variable Length opcodes Luiz Augusto von Dentz
2026-11-06 18:33 ` [PATCH BlueZ v2 6/8] shared/gatt-client: Fix parsing Read Multiple Variable Length response Luiz Augusto von Dentz
2026-11-06 18:33 ` [PATCH BlueZ v2 7/8] shared/gatt-client: Check value lengths before reading them Luiz Augusto von Dentz
2026-11-06 18:33 ` Luiz Augusto von Dentz [this message]
2026-11-07 21:00 ` [PATCH BlueZ v2 0/8] Fix handling of malformed GATT PDUs patchwork-bot+bluetooth

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261106183350.3155282-9-luiz.dentz@gmail.com \
    --to=luiz.dentz@gmail.com \
    --cc=linux-bluetooth@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox