* [PATCH] shared/gatt-client: Cancel discovery read-by-type requests
@ 2026-11-07 6:59 Kyle Pepper
2026-11-07 8:45 ` bluez.test.bot
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Kyle Pepper @ 2026-11-07 6:59 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, luiz.dentz, Kyle Pepper
Server Features and Database Hash reads outlive the client when it is
released during discovery. Their destroy callback then dereferences the
freed client while unregistering the discovery database callback.
Retain cancellable request references for both reads and release them
on completion or client cancellation. Preserve the boolean helper for
callers that do not retain requests. Add native ATT teardown regressions
for queued and pending reads, including repeated cancellation.
Fixes: 76d63c91b27a ("shared/gatt-client: Add support for EATT features")
Fixes: 0f67d5e2f19f ("shared/gatt-client: Read database hash if available")
Assisted-by: Codex:gpt-6
---
src/shared/gatt-client.c | 32 +++++++++++++++++++++---
src/shared/gatt-helpers.c | 26 +++++++++++++++++---
src/shared/gatt-helpers.h | 7 ++++++
unit/test-gatt.c | 52 ++++++++++++++++++++++++++++++++++++++-
4 files changed, 108 insertions(+), 9 deletions(-)
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 836a59a..d283376 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -105,6 +105,8 @@ struct bt_gatt_client {
unsigned int next_request_id;
struct bt_gatt_request *discovery_req;
+ struct bt_gatt_request *server_feat_req;
+ struct bt_gatt_request *db_hash_req;
unsigned int mtu_req_id;
/* Pending retry operation for DB out of sync handling */
@@ -1472,6 +1474,9 @@ static void db_hash_read_cb(bool success, uint8_t att_ecode,
uint16_t len, handle;
struct bt_gatt_iter iter;
+ bt_gatt_request_unref(client->db_hash_req);
+ client->db_hash_req = NULL;
+
if (!success)
goto discover;
@@ -1542,10 +1547,12 @@ static bool read_db_hash(struct discovery_op *op)
if (!op->hash)
return false;
- if (!bt_gatt_read_by_type(client->att, 0x0001, 0xffff, &uuid,
+ client->db_hash_req = bt_gatt_read_by_type_request(client->att,
+ 0x0001, 0xffff, &uuid,
db_hash_read_cb,
discovery_op_ref(op),
- discovery_op_unref)) {
+ discovery_op_unref);
+ if (!client->db_hash_req) {
discovery_op_unref(op);
return false;
}
@@ -1562,6 +1569,9 @@ static void db_server_feat_read(bool success, uint8_t att_ecode,
uint16_t len, handle;
struct bt_gatt_iter iter;
+ bt_gatt_request_unref(client->server_feat_req);
+ client->server_feat_req = NULL;
+
if (!result)
return;
@@ -1606,10 +1616,12 @@ static void read_server_feat(struct discovery_op *op)
return;
}
- if (!bt_gatt_read_by_type(client->att, 0x0001, 0xffff, &uuid,
+ client->server_feat_req = bt_gatt_read_by_type_request(client->att,
+ 0x0001, 0xffff, &uuid,
db_server_feat_read,
discovery_op_ref(op),
- discovery_op_unref))
+ discovery_op_unref);
+ if (!client->server_feat_req)
discovery_op_unref(op);
}
@@ -2841,6 +2853,15 @@ static void cancel_pending(void *data)
cancel_request(data);
}
+static void cancel_gatt_request(struct bt_gatt_request **req)
+{
+ struct bt_gatt_request *pending = *req;
+
+ *req = NULL;
+ bt_gatt_request_cancel(pending);
+ bt_gatt_request_unref(pending);
+}
+
bool bt_gatt_client_cancel_all(struct bt_gatt_client *client)
{
if (!client || !client->att)
@@ -2848,6 +2869,9 @@ bool bt_gatt_client_cancel_all(struct bt_gatt_client *client)
queue_remove_all(client->pending_requests, NULL, NULL, cancel_pending);
+ cancel_gatt_request(&client->server_feat_req);
+ cancel_gatt_request(&client->db_hash_req);
+
if (client->discovery_req) {
bt_gatt_request_cancel(client->discovery_req);
bt_gatt_request_unref(client->discovery_req);
diff --git a/src/shared/gatt-helpers.c b/src/shared/gatt-helpers.c
index b3d5d8f..f33d387 100644
--- a/src/shared/gatt-helpers.c
+++ b/src/shared/gatt-helpers.c
@@ -1356,7 +1356,8 @@ done:
discovery_op_complete(op, success, att_ecode);
}
-bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end,
+struct bt_gatt_request *bt_gatt_read_by_type_request(struct bt_att *att,
+ uint16_t start, uint16_t end,
const bt_uuid_t *uuid,
bt_gatt_request_callback_t callback,
void *user_data,
@@ -1366,7 +1367,7 @@ bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end,
uint8_t pdu[4 + get_uuid_len(uuid)];
if (!att || !uuid || uuid->type == BT_UUID_UNSPEC)
- return false;
+ return NULL;
op = new0(struct bt_gatt_request, 1);
op->att = att;
@@ -1386,10 +1387,27 @@ bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end,
bt_gatt_request_ref(op),
async_req_unref);
if (op->id)
- return true;
+ return bt_gatt_request_ref(op);
free(op);
- return false;
+ return NULL;
+}
+
+bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end,
+ const bt_uuid_t *uuid,
+ bt_gatt_request_callback_t callback,
+ void *user_data,
+ bt_gatt_destroy_func_t destroy)
+{
+ struct bt_gatt_request *req;
+
+ req = bt_gatt_read_by_type_request(att, start, end, uuid, callback,
+ user_data, destroy);
+ if (!req)
+ return false;
+
+ bt_gatt_request_unref(req);
+ return true;
}
static void discover_descs_cb(uint8_t opcode, const void *pdu,
diff --git a/src/shared/gatt-helpers.h b/src/shared/gatt-helpers.h
index 2bf5aad..528ef21 100644
--- a/src/shared/gatt-helpers.h
+++ b/src/shared/gatt-helpers.h
@@ -102,5 +102,12 @@ bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end,
void *user_data,
bt_gatt_destroy_func_t destroy);
+struct bt_gatt_request *bt_gatt_read_by_type_request(struct bt_att *att,
+ uint16_t start, uint16_t end,
+ const bt_uuid_t *uuid,
+ bt_gatt_request_callback_t callback,
+ void *user_data,
+ bt_gatt_destroy_func_t destroy);
+
uint16_t bt_gatt_req_get_end_handle(struct bt_gatt_request *req);
uint16_t bt_gatt_req_get_start_handle(struct bt_gatt_request *req);
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 6d6d0c7..d206a44 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -42,6 +42,7 @@ struct test_pdu {
enum context_type {
ATT,
CLIENT,
+ CLIENT_CACHED,
SERVER
};
@@ -680,7 +681,13 @@ static struct context *create_context(uint16_t mtu, gconstpointer data)
"bt_gatt_server:", NULL);
break;
case CLIENT:
- context->client_db = gatt_db_new();
+ case CLIENT_CACHED:
+ if (test_data->context_type == CLIENT_CACHED)
+ context->client_db =
+ gatt_db_clone(test_data->source_db);
+ else
+ context->client_db = gatt_db_new();
+
g_assert(context->client_db);
context->client = bt_gatt_client_new(context->client_db,
@@ -1968,6 +1975,22 @@ static void test_client(gconstpointer data)
create_context(512, data);
}
+static void test_client_cancel(gconstpointer data)
+{
+ struct context *context = create_context(23, data);
+
+ context_quit(context);
+}
+
+static void test_client_cancel_all(gconstpointer data)
+{
+ struct context *context = create_context(23, data);
+
+ g_assert(bt_gatt_client_cancel_all(context->client));
+ g_assert(bt_gatt_client_cancel_all(context->client));
+ context_quit(context);
+}
+
static void test_server(gconstpointer data)
{
struct context *context = create_context(512, data);
@@ -2480,9 +2503,36 @@ int main(int argc, char *argv[])
{
struct gatt_db *service_db_1, *service_db_2, *service_db_3;
struct gatt_db *ts_small_db, *ts_large_db_1, *ts_tail_db;
+ struct gatt_db *hash_db;
+ const struct att_handle_spec hash_specs[] = {
+ PRIMARY_SERVICE(0x0001, GATT_UUID, 3),
+ CHARACTERISTIC(GATT_CHARAC_DB_HASH, BT_ATT_PERM_READ,
+ BT_GATT_CHRC_PROP_READ, 0x00),
+ { }
+ };
tester_init(&argc, &argv);
+ define_test_client("/robustness/client-cancel-queued-discovery",
+ test_client_cancel, NULL, NULL, {});
+
+ define_test_client("/robustness/client-cancel-pending-server-features",
+ test_client, NULL, NULL, MTU_EXCHANGE_CLIENT_PDUS,
+ raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x3a, 0x2b));
+
+ define_test_client("/robustness/client-cancel-all-queued-discovery",
+ test_client_cancel_all, NULL, NULL, {});
+
+ hash_db = make_db(hash_specs);
+ define_test("/robustness/client-cancel-queued-db-hash",
+ test_client_cancel, CLIENT_CACHED, NULL, hash_db,
+ NULL, {});
+
+ define_test("/robustness/client-cancel-pending-db-hash",
+ test_client, CLIENT_CACHED, NULL, hash_db, NULL,
+ CLIENT_INIT_PDUS,
+ raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x2a, 0x2b));
+
service_db_1 = make_service_data_1_db();
service_db_2 = make_service_data_2_db();
service_db_3 = make_service_data_3_db();
--
2.56.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* RE: shared/gatt-client: Cancel discovery read-by-type requests 2026-11-07 6:59 [PATCH] shared/gatt-client: Cancel discovery read-by-type requests Kyle Pepper @ 2026-11-07 8:45 ` bluez.test.bot 2026-11-07 20:53 ` [PATCH] " Luiz Augusto von Dentz 2026-11-11 21:42 ` [PATCH v2 0/3] shared/gatt-client: Track internal discovery reads Kyle Pepper 2 siblings, 0 replies; 9+ messages in thread From: bluez.test.bot @ 2026-11-07 8:45 UTC (permalink / raw) To: linux-bluetooth, cochcoder [-- Attachment #1: Type: text/plain, Size: 2012 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/series/1204776/ ---Test result--- Test Summary: CheckPatch PASS 0.36 seconds GitLint PASS 0.77 seconds BuildEll PASS 15.93 seconds BluezMake PASS 223.92 seconds MakeCheck PASS 13.54 seconds MakeDistcheck PASS 114.67 seconds CheckValgrind PASS 276.47 seconds CheckSmatch WARNING 224.41 seconds bluezmakeextell PASS 73.86 seconds TestFunctional PASS 959.71 seconds IncrementalBuild PASS 228.34 seconds ScanBuild PASS 819.69 seconds Details ############################## Test: CheckSmatch - WARNING Desc: Run smatch tool with source Output: src/shared/gatt-helpers.c:764:31: warning: Variable length array is used.src/shared/gatt-helpers.c:842:31: warning: Variable length array is used.src/shared/gatt-helpers.c:1335:31: warning: Variable length array is used.src/shared/gatt-helpers.c:1367:23: warning: Variable length array is used.src/shared/gatt-helpers.c:764:31: warning: Variable length array is used.src/shared/gatt-helpers.c:842:31: warning: Variable length array is used.src/shared/gatt-helpers.c:1335:31: warning: Variable length array is used.src/shared/gatt-helpers.c:1367:23: warning: Variable length array is used.src/shared/gatt-helpers.c:764:31: warning: Variable length array is used.src/shared/gatt-helpers.c:842:31: warning: Variable length array is used.src/shared/gatt-helpers.c:1335:31: warning: Variable length array is used.src/shared/gatt-helpers.c:1367:23: warning: Variable length array is used. https://github.com/bluez/bluez/pull/2779 --- Regards, Linux Bluetooth ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] shared/gatt-client: Cancel discovery read-by-type requests 2026-11-07 6:59 [PATCH] shared/gatt-client: Cancel discovery read-by-type requests Kyle Pepper 2026-11-07 8:45 ` bluez.test.bot @ 2026-11-07 20:53 ` Luiz Augusto von Dentz 2026-11-11 21:42 ` [PATCH v2 0/3] shared/gatt-client: Track internal discovery reads Kyle Pepper 2 siblings, 0 replies; 9+ messages in thread From: Luiz Augusto von Dentz @ 2026-11-07 20:53 UTC (permalink / raw) To: Kyle Pepper; +Cc: linux-bluetooth, marcel Hi Kyle, On Sat, Nov 7, 2026 at 1:59 AM Kyle Pepper <cochcoder@proton.me> wrote: > > Server Features and Database Hash reads outlive the client when it is > released during discovery. Their destroy callback then dereferences the > freed client while unregistering the discovery database callback. > > Retain cancellable request references for both reads and release them > on completion or client cancellation. Preserve the boolean helper for > callers that do not retain requests. Add native ATT teardown regressions > for queued and pending reads, including repeated cancellation. > > Fixes: 76d63c91b27a ("shared/gatt-client: Add support for EATT features") > Fixes: 0f67d5e2f19f ("shared/gatt-client: Read database hash if available") > Assisted-by: Codex:gpt-6 > --- > src/shared/gatt-client.c | 32 +++++++++++++++++++++--- > src/shared/gatt-helpers.c | 26 +++++++++++++++++--- > src/shared/gatt-helpers.h | 7 ++++++ > unit/test-gatt.c | 52 ++++++++++++++++++++++++++++++++++++++- > 4 files changed, 108 insertions(+), 9 deletions(-) > > diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c > index 836a59a..d283376 100644 > --- a/src/shared/gatt-client.c > +++ b/src/shared/gatt-client.c > @@ -105,6 +105,8 @@ struct bt_gatt_client { > unsigned int next_request_id; > > struct bt_gatt_request *discovery_req; > + struct bt_gatt_request *server_feat_req; > + struct bt_gatt_request *db_hash_req; We probably need a queue to store these requests and then cancel them or perhaps reuse the pending_requests logic, since they pending request just submitted internally but Id still argue they are pending. And lets have each of them fixed separatly so if we need to revert one we don't have to revert both fixes, and the same applies to tests. > unsigned int mtu_req_id; > > /* Pending retry operation for DB out of sync handling */ > @@ -1472,6 +1474,9 @@ static void db_hash_read_cb(bool success, uint8_t att_ecode, > uint16_t len, handle; > struct bt_gatt_iter iter; > > + bt_gatt_request_unref(client->db_hash_req); > + client->db_hash_req = NULL; > + > if (!success) > goto discover; > > @@ -1542,10 +1547,12 @@ static bool read_db_hash(struct discovery_op *op > if (!op->hash) > return false; > > - if (!bt_gatt_read_by_type(client->att, 0x0001, 0xffff, &uuid, > + client->db_hash_req = bt_gatt_read_by_type_request(client->att, > + 0x0001, 0xffff, &uuid, > db_hash_read_cb, > discovery_op_ref(op), > - discovery_op_unref)) { > + discovery_op_unref); > + if (!client->db_hash_req) { > discovery_op_unref(op); > return false; > } > @@ -1562,6 +1569,9 @@ static void db_server_feat_read(bool success, uint8_t att_ecode, > uint16_t len, handle; > struct bt_gatt_iter iter; > > + bt_gatt_request_unref(client->server_feat_req); > + client->server_feat_req = NULL; > + > if (!result) > return; > > @@ -1606,10 +1616,12 @@ static void read_server_feat(struct discovery_op *op) > return; > } > > - if (!bt_gatt_read_by_type(client->att, 0x0001, 0xffff, &uuid, > + client->server_feat_req = bt_gatt_read_by_type_request(client->att, > + 0x0001, 0xffff, &uuid, > db_server_feat_read, > discovery_op_ref(op), > - discovery_op_unref)) > + discovery_op_unref); > + if (!client->server_feat_req) > discovery_op_unref(op); > } > > @@ -2841,6 +2853,15 @@ static void cancel_pending(void *data) > cancel_request(data); > } > > +static void cancel_gatt_request(struct bt_gatt_request **req) > +{ > + struct bt_gatt_request *pending = *req; > + > + *req = NULL; > + bt_gatt_request_cancel(pending); > + bt_gatt_request_unref(pending); > +} > + > bool bt_gatt_client_cancel_all(struct bt_gatt_client *client) > { > if (!client || !client->att) > @@ -2848,6 +2869,9 @@ bool bt_gatt_client_cancel_all(struct bt_gatt_client *client) > > queue_remove_all(client->pending_requests, NULL, NULL, cancel_pending); > > + cancel_gatt_request(&client->server_feat_req); > + cancel_gatt_request(&client->db_hash_req); > + > if (client->discovery_req) { > bt_gatt_request_cancel(client->discovery_req); > bt_gatt_request_unref(client->discovery_req); > diff --git a/src/shared/gatt-helpers.c b/src/shared/gatt-helpers.c > index b3d5d8f..f33d387 100644 > --- a/src/shared/gatt-helpers.c > +++ b/src/shared/gatt-helpers.c > @@ -1356,7 +1356,8 @@ done: > discovery_op_complete(op, success, att_ecode); > } > > -bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end, > +struct bt_gatt_request *bt_gatt_read_by_type_request(struct bt_att *att, > + uint16_t start, uint16_t end, > const bt_uuid_t *uuid, > bt_gatt_request_callback_t callback, > void *user_data, > @@ -1366,7 +1367,7 @@ bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end, > uint8_t pdu[4 + get_uuid_len(uuid)]; > > if (!att || !uuid || uuid->type == BT_UUID_UNSPEC) > - return false; > + return NULL; > > op = new0(struct bt_gatt_request, 1); > op->att = att; > @@ -1386,10 +1387,27 @@ bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end, > bt_gatt_request_ref(op), > async_req_unref); > if (op->id) > - return true; > + return bt_gatt_request_ref(op); > > free(op); > - return false; > + return NULL; > +} > + > +bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end, > + const bt_uuid_t *uuid, > + bt_gatt_request_callback_t callback, > + void *user_data, > + bt_gatt_destroy_func_t destroy) > +{ > + struct bt_gatt_request *req; > + > + req = bt_gatt_read_by_type_request(att, start, end, uuid, callback, > + user_data, destroy); > + if (!req) > + return false; > + > + bt_gatt_request_unref(req); > + return true; > } > > static void discover_descs_cb(uint8_t opcode, const void *pdu, > diff --git a/src/shared/gatt-helpers.h b/src/shared/gatt-helpers.h > index 2bf5aad..528ef21 100644 > --- a/src/shared/gatt-helpers.h > +++ b/src/shared/gatt-helpers.h > @@ -102,5 +102,12 @@ bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end, > void *user_data, > bt_gatt_destroy_func_t destroy); > > +struct bt_gatt_request *bt_gatt_read_by_type_request(struct bt_att *att, > + uint16_t start, uint16_t end, > + const bt_uuid_t *uuid, > + bt_gatt_request_callback_t callback, > + void *user_data, > + bt_gatt_destroy_func_t destroy); > + > uint16_t bt_gatt_req_get_end_handle(struct bt_gatt_request *req); > uint16_t bt_gatt_req_get_start_handle(struct bt_gatt_request *req); > diff --git a/unit/test-gatt.c b/unit/test-gatt.c > index 6d6d0c7..d206a44 100644 > --- a/unit/test-gatt.c > +++ b/unit/test-gatt.c > @@ -42,6 +42,7 @@ struct test_pdu { > enum context_type { > ATT, > CLIENT, > + CLIENT_CACHED, > SERVER > }; > > @@ -680,7 +681,13 @@ static struct context *create_context(uint16_t mtu, gconstpointer data) > "bt_gatt_server:", NULL); > break; > case CLIENT: > - context->client_db = gatt_db_new(); > + case CLIENT_CACHED: > + if (test_data->context_type == CLIENT_CACHED) > + context->client_db = > + gatt_db_clone(test_data->source_db); > + else > + context->client_db = gatt_db_new(); > + > g_assert(context->client_db); > > context->client = bt_gatt_client_new(context->client_db, > @@ -1968,6 +1975,22 @@ static void test_client(gconstpointer data) > create_context(512, data); > } > > +static void test_client_cancel(gconstpointer data) > +{ > + struct context *context = create_context(23, data); > + > + context_quit(context); > +} > + > +static void test_client_cancel_all(gconstpointer data) > +{ > + struct context *context = create_context(23, data); > + > + g_assert(bt_gatt_client_cancel_all(context->client)); > + g_assert(bt_gatt_client_cancel_all(context->client)); > + context_quit(context); > +} > + > static void test_server(gconstpointer data) > { > struct context *context = create_context(512, data); > @@ -2480,9 +2503,36 @@ int main(int argc, char *argv[]) > { > struct gatt_db *service_db_1, *service_db_2, *service_db_3; > struct gatt_db *ts_small_db, *ts_large_db_1, *ts_tail_db; > + struct gatt_db *hash_db; > + const struct att_handle_spec hash_specs[] = { > + PRIMARY_SERVICE(0x0001, GATT_UUID, 3), > + CHARACTERISTIC(GATT_CHARAC_DB_HASH, BT_ATT_PERM_READ, > + BT_GATT_CHRC_PROP_READ, 0x00), > + { } > + }; > > tester_init(&argc, &argv); > > + define_test_client("/robustness/client-cancel-queued-discovery", > + test_client_cancel, NULL, NULL, {}); > + > + define_test_client("/robustness/client-cancel-pending-server-features", > + test_client, NULL, NULL, MTU_EXCHANGE_CLIENT_PDUS, > + raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x3a, 0x2b)); > + > + define_test_client("/robustness/client-cancel-all-queued-discovery", > + test_client_cancel_all, NULL, NULL, {}); > + > + hash_db = make_db(hash_specs); > + define_test("/robustness/client-cancel-queued-db-hash", > + test_client_cancel, CLIENT_CACHED, NULL, hash_db, > + NULL, {}); > + > + define_test("/robustness/client-cancel-pending-db-hash", > + test_client, CLIENT_CACHED, NULL, hash_db, NULL, > + CLIENT_INIT_PDUS, > + raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x2a, 0x2b)); > + > service_db_1 = make_service_data_1_db(); > service_db_2 = make_service_data_2_db(); > service_db_3 = make_service_data_3_db(); > -- > 2.56.0 > > -- Luiz Augusto von Dentz ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 0/3] shared/gatt-client: Track internal discovery reads 2026-11-07 6:59 [PATCH] shared/gatt-client: Cancel discovery read-by-type requests Kyle Pepper 2026-11-07 8:45 ` bluez.test.bot 2026-11-07 20:53 ` [PATCH] " Luiz Augusto von Dentz @ 2026-11-11 21:42 ` Kyle Pepper 2026-11-11 21:43 ` [PATCH v2 1/3] shared/gatt-client: Support pending GATT helper requests Kyle Pepper ` (3 more replies) 2 siblings, 4 replies; 9+ messages in thread From: Kyle Pepper @ 2026-11-11 21:42 UTC (permalink / raw) To: linux-bluetooth; +Cc: marcel, luiz.dentz Track Server Features and discovery Database Hash reads in pending_requests so client cancellation releases them before the client is freed. Patch 1 adds shared request support. Patches 2 and 3 fix each read with separate native ATT tests. Both depend only on patch 1; either fix and its tests can be reverted independently. Changes in v2: - Reuse pending_requests instead of adding per-read client fields. - Separate shared support from each fix and its tests. - Test queued, pending and continued reads. Cache Server Features in the Database Hash tests so they exercise that fix independently. - Rebase onto current master, preserving its GATT parser updates. GCC and Clang ASan/UBSan and GCC LTO: 236 passed, zero failed, one not run. All six regressions reproduce the use-after-free on the unchanged base. Removing either fix reproduces only that read's three regressions; the other three still pass. Both reverts apply cleanly. Checkpatch passes. Native make check passes all 35 programs with Valgrind disabled; the host's Valgrind crashes in the dynamic loader before executing tests. Previous version: https://lore.kernel.org/linux-bluetooth/20261107065854.2147141-1-cochcoder@proton.me/ Kyle Pepper (3): shared/gatt-client: Support pending GATT helper requests shared/gatt-client: Track pending Server Features reads shared/gatt-client: Track pending discovery Database Hash reads src/shared/gatt-client.c | 58 +++++++++++++++++++++++++------- src/shared/gatt-helpers.c | 26 ++++++++++++--- src/shared/gatt-helpers.h | 7 ++++ unit/test-gatt.c | 70 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 144 insertions(+), 17 deletions(-) base-commit: 9659adb6819d7e0284d0d2ba226a3894423d8db4 -- 2.56.0 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 1/3] shared/gatt-client: Support pending GATT helper requests 2026-11-11 21:42 ` [PATCH v2 0/3] shared/gatt-client: Track internal discovery reads Kyle Pepper @ 2026-11-11 21:43 ` Kyle Pepper 2026-11-12 1:58 ` shared/gatt-client: Track internal discovery reads bluez.test.bot 2026-11-11 21:43 ` [PATCH v2 2/3] shared/gatt-client: Track pending Server Features reads Kyle Pepper ` (2 subsequent siblings) 3 siblings, 1 reply; 9+ messages in thread From: Kyle Pepper @ 2026-11-11 21:43 UTC (permalink / raw) To: linux-bluetooth; +Cc: marcel, luiz.dentz Allow pending requests to own a cancellable GATT helper request, so multi-PDU operations can use the existing cancellation queue. Expose a request-returning read-by-type helper and keep the boolean interface for callers that do not retain requests. Assisted-by: Codex:gpt-6 --- src/shared/gatt-client.c | 10 ++++++++++ src/shared/gatt-helpers.c | 26 ++++++++++++++++++++++---- src/shared/gatt-helpers.h | 7 +++++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c index 7bebc50dc..f301a105b 100644 --- a/src/shared/gatt-client.c +++ b/src/shared/gatt-client.c @@ -120,6 +120,7 @@ struct request { int ref_count; unsigned int id; unsigned int att_id; + struct bt_gatt_request *gatt_req; void *data; void (*destroy)(void *); }; @@ -2811,6 +2812,15 @@ static bool cancel_request(struct request *req) { req->removed = true; + if (req->gatt_req) { + struct bt_gatt_request *gatt_req = req->gatt_req; + + req->gatt_req = NULL; + bt_gatt_request_cancel(gatt_req); + bt_gatt_request_unref(gatt_req); + return true; + } + if (req->long_write) return cancel_long_write_req(req->client, req); diff --git a/src/shared/gatt-helpers.c b/src/shared/gatt-helpers.c index ea77a41ef..6d307e893 100644 --- a/src/shared/gatt-helpers.c +++ b/src/shared/gatt-helpers.c @@ -1484,7 +1484,8 @@ done: discovery_op_complete(op, success, att_ecode); } -bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end, +struct bt_gatt_request *bt_gatt_read_by_type_request(struct bt_att *att, + uint16_t start, uint16_t end, const bt_uuid_t *uuid, bt_gatt_request_callback_t callback, void *user_data, @@ -1495,7 +1496,7 @@ bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end, struct iovec req = { pdu, 0 }; if (!att || !uuid || uuid->type == BT_UUID_UNSPEC) - return false; + return NULL; op = new0(struct bt_gatt_request, 1); op->att = att; @@ -1516,10 +1517,27 @@ bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end, bt_gatt_request_ref(op), async_req_unref); if (op->id) - return true; + return bt_gatt_request_ref(op); free(op); - return false; + return NULL; +} + +bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end, + const bt_uuid_t *uuid, + bt_gatt_request_callback_t callback, + void *user_data, + bt_gatt_destroy_func_t destroy) +{ + struct bt_gatt_request *req; + + req = bt_gatt_read_by_type_request(att, start, end, uuid, callback, + user_data, destroy); + if (!req) + return false; + + bt_gatt_request_unref(req); + return true; } static void discover_descs_cb(uint8_t opcode, const void *pdu, diff --git a/src/shared/gatt-helpers.h b/src/shared/gatt-helpers.h index 2bf5aad46..528ef2196 100644 --- a/src/shared/gatt-helpers.h +++ b/src/shared/gatt-helpers.h @@ -102,5 +102,12 @@ bool bt_gatt_read_by_type(struct bt_att *att, uint16_t start, uint16_t end, void *user_data, bt_gatt_destroy_func_t destroy); +struct bt_gatt_request *bt_gatt_read_by_type_request(struct bt_att *att, + uint16_t start, uint16_t end, + const bt_uuid_t *uuid, + bt_gatt_request_callback_t callback, + void *user_data, + bt_gatt_destroy_func_t destroy); + uint16_t bt_gatt_req_get_end_handle(struct bt_gatt_request *req); uint16_t bt_gatt_req_get_start_handle(struct bt_gatt_request *req); -- 2.56.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* RE: shared/gatt-client: Track internal discovery reads 2026-11-11 21:43 ` [PATCH v2 1/3] shared/gatt-client: Support pending GATT helper requests Kyle Pepper @ 2026-11-12 1:58 ` bluez.test.bot 0 siblings, 0 replies; 9+ messages in thread From: bluez.test.bot @ 2026-11-12 1:58 UTC (permalink / raw) To: linux-bluetooth, cochcoder [-- Attachment #1: Type: text/plain, Size: 32640 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/series/1208775/ ---Test result--- Test Summary: CheckPatch PASS 1.17 seconds GitLint PASS 0.76 seconds BuildEll PASS 13.45 seconds BluezMake PASS 173.45 seconds MakeCheck PASS 12.74 seconds MakeDistcheck PASS 104.03 seconds CheckValgrind PASS 226.42 seconds CheckSmatch WARNING 172.25 seconds bluezmakeextell PASS 62.29 seconds TestFunctional FAIL 2977.33 seconds IncrementalBuild PASS 233.51 seconds ScanBuild PASS 598.83 seconds Details ############################## Test: CheckSmatch - WARNING Desc: Run smatch tool with source Output: src/shared/gatt-helpers.c:845:31: warning: Variable length array is used.src/shared/gatt-helpers.c:925:31: warning: Variable length array is used.src/shared/gatt-helpers.c:1462:31: warning: Variable length array is used.src/shared/gatt-helpers.c:1495:23: warning: Variable length array is used.src/shared/gatt-helpers.c:845:31: warning: Variable length array is used.src/shared/gatt-helpers.c:925:31: warning: Variable length array is used.src/shared/gatt-helpers.c:1462:31: warning: Variable length array is used.src/shared/gatt-helpers.c:1495:23: warning: Variable length array is used.src/shared/gatt-helpers.c:845:31: warning: Variable length array is used.src/shared/gatt-helpers.c:925:31: warning: Variable length array is used.src/shared/gatt-helpers.c:1462:31: warning: Variable length array is used.src/shared/gatt-helpers.c:1495:23: warning: Variable length array is used. ############################## Test: TestFunctional - FAIL Desc: Run test-functional Output: FAIL functional.test_adv_monitor::test_adv_monitor_GHSA_hhgc_hfgf_8m4x[hosts1-vm1]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bluetoothctl::test_bluetoothctl_show[hosts16-vm1]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bluetoothctl::test_bluetoothctl_list[hosts16-vm1]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bluetoothctl::test_bluetoothctl_script_show[hosts16-vm1]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bluetoothctl::test_bluetoothctl_script_list[hosts16-vm1]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_btmgmt::test_btmgmt_info[hosts19-vm1]: AssertionError: assert 'addr 00:00:00:00:00:00' in '\x1b[0;91mReading hci0 info failed with status 0x11 (Invalid Index)\n\x1b[0m' + where '\x1b[0;91mReading hci0 info failed with status 0x11 (Invalid Index)\n\x1b[0m' = CompletedProcess(args=['/home/runner/work/bluez/bluez/src/src/tools/btmgmt', '--index', '0', 'info'], returncode=0, stdout='\x1b[0;91mReading hci0 info failed with status 0x11 (Invalid Index)\n\x1b[0m').stdout FAIL functional.test_a2dp::test_a2dp_transport_created[hosts0-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_a2dp::test_a2dp_transport_acquire[hosts0-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_a2dp::test_a2dp_disconnect_during_setconf[hosts0-vm2-accept]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_a2dp::test_a2dp_disconnect_during_setconf[hosts0-vm2-reject]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_a2dp::test_a2dp_reconnect_pending_disconnect[hosts0-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bearer::test_bearer_le_connect[hosts12-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bearer::test_bearer_le_conn_params[hosts12-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bearer::test_bearer_le_connectable[hosts12-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bearer::test_bearer_le_pair[hosts12-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bearer::test_bearer_bredr_pair[hosts13-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bearer::test_bearer_le_conn_update[hosts14-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bearer::test_bearer_le_not_connectable[hosts15-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bluetoothctl::test_bluetoothctl_pair_bredr[hosts17-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bluetoothctl::test_bluetoothctl_pair_le[hosts18-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_agent::test_agent_pair_bredr[accept-hosts2-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_agent::test_agent_pair_bredr[reject-hosts2-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_hog::test_hog[no-sci-hosts20-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_hog::test_hog[sci-hosts20-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_mpris_proxy::test_mpris_proxy_playback_control[bredr-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_mpris_proxy::test_mpris_proxy_track_control[bredr-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_obex::test_obex_ftp_list[hosts24-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_obex::test_obex_ftp_get[hosts24-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_obex::test_obexctl_list[hosts24-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_avrcp::test_avrcp_GHSA_m2vx_pw5f_rc8v[hosts3-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_unicast_transport_created[hosts4-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_unicast_transport_acquire[hosts4-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_unicast_transport_resume[0-hosts4-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_unicast_transport_resume[0.1-hosts4-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_unicast_transport_resume[1.0-hosts4-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_unicast_reconfigure_metadata[empty-hosts5-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_unicast_reconfigure_metadata[media-hosts5-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_unicast_desync[hosts6-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_unicast_duplex_enable_one[hosts6-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_broadcast_transport_created[lc3-hosts7-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_broadcast_transport_created[pbp-hosts7-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_broadcast_transport_acquire[lc3-hosts7-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_broadcast_transport_acquire[pbp-hosts7-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bass_past_transport_acquire[hosts9-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_unicast_set_transport_created[hosts10-vm3-sc]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_unicast_set_transport_created[hosts10-vm3-legacy]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_unicast_set_transport_acquire[hosts10-vm3]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bass_past_earbuds_transport_acquire[hosts11-vm3]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_broadcast_earbuds_transport_created[hosts8-vm3]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_bap::test_bap_broadcast_earbuds_transport_acquire[hosts8-vm3]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_mpris_proxy::test_mpris_proxy_playback_control[le-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" FAIL functional.test_mpris_proxy::test_mpris_proxy_track_control[le-vm2]: failed on setup with "pytest_bluezenv.rpc.RemoteError: load failed Remote traceback: Traceback (most recent call last): File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/rpc.py", line 102, in server_stream result = method(*msg["a"], **msg["kw"]) File "/usr/local/lib/python3.14/dist-packages/pytest_bluezenv/../pytest_bluezenv/env.py", line 238, in wait_load raise RuntimeError("load failed") RuntimeError: load failed" https://github.com/bluez/bluez/pull/2810 --- Regards, Linux Bluetooth ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 2/3] shared/gatt-client: Track pending Server Features reads 2026-11-11 21:42 ` [PATCH v2 0/3] shared/gatt-client: Track internal discovery reads Kyle Pepper 2026-11-11 21:43 ` [PATCH v2 1/3] shared/gatt-client: Support pending GATT helper requests Kyle Pepper @ 2026-11-11 21:43 ` Kyle Pepper 2026-11-11 21:44 ` [PATCH v2 3/3] shared/gatt-client: Track pending discovery Database Hash reads Kyle Pepper 2026-11-12 17:50 ` [PATCH v2 0/3] shared/gatt-client: Track internal discovery reads patchwork-bot+bluetooth 3 siblings, 0 replies; 9+ messages in thread From: Kyle Pepper @ 2026-11-11 21:43 UTC (permalink / raw) To: linux-bluetooth; +Cc: marcel, luiz.dentz The Server Features read retains a discovery operation after the client is released. Its later destruction accesses the freed client. Track the read in pending_requests so client cancellation releases it before the client is freed. Add native ATT regressions for queued, pending and continued reads, including repeated cancellation. Fixes: 76d63c91b27a ("shared/gatt-client: Add support for EATT features") Assisted-by: Codex:gpt-6 --- src/shared/gatt-client.c | 24 ++++++++++++++++++------ unit/test-gatt.c | 25 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c index f301a105b..174325e27 100644 --- a/src/shared/gatt-client.c +++ b/src/shared/gatt-client.c @@ -1560,12 +1560,16 @@ static bool read_db_hash(struct discovery_op *op) static void db_server_feat_read(bool success, uint8_t att_ecode, struct bt_gatt_result *result, void *user_data) { - struct discovery_op *op = user_data; + struct request *req = user_data; + struct discovery_op *op = req->data; struct bt_gatt_client *client = op->client; const uint8_t *value; uint16_t len, handle; struct bt_gatt_iter iter; + bt_gatt_request_unref(req->gatt_req); + req->gatt_req = NULL; + if (!result) return; @@ -1596,6 +1600,7 @@ static void server_feat_read_value(struct gatt_db_attribute *attrib, static void read_server_feat(struct discovery_op *op) { struct bt_gatt_client *client = op->client; + struct request *req; struct gatt_db_attribute *attr = NULL; const uint8_t *feat = NULL; bt_uuid_t uuid; @@ -1612,11 +1617,18 @@ static void read_server_feat(struct discovery_op *op) return; } - if (!bt_gatt_read_by_type(client->att, 0x0001, 0xffff, &uuid, - db_server_feat_read, - discovery_op_ref(op), - discovery_op_unref)) - discovery_op_unref(op); + req = request_create(client); + if (!req) + return; + + req->data = discovery_op_ref(op); + req->destroy = discovery_op_unref; + req->gatt_req = bt_gatt_read_by_type_request(client->att, + 0x0001, 0xffff, &uuid, + db_server_feat_read, req, + request_unref); + if (!req->gatt_req) + request_unref(req); } static void exchange_mtu_cb(bool success, uint8_t att_ecode, void *user_data) diff --git a/unit/test-gatt.c b/unit/test-gatt.c index bf6074107..c8ba2b5bb 100644 --- a/unit/test-gatt.c +++ b/unit/test-gatt.c @@ -2008,6 +2008,15 @@ static void test_client(gconstpointer data) create_context(512, data); } +static void test_client_cancel_features(gconstpointer data) +{ + struct context *context = create_context(23, data); + + g_assert(bt_gatt_client_cancel_all(context->client)); + g_assert(bt_gatt_client_cancel_all(context->client)); + context_quit(context); +} + static struct context *create_server_context(gconstpointer data) { struct context *context = create_context(512, data); @@ -2708,6 +2717,22 @@ int main(int argc, char *argv[]) tester_init(&argc, &argv); + define_test_client("/robustness/server-features/queued", + test_client_cancel_features, NULL, NULL, {}); + + define_test_client("/robustness/server-features/pending", + test_client, NULL, NULL, MTU_EXCHANGE_CLIENT_PDUS, + raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x3a, 0x2b)); + + define_test_client("/robustness/server-features/continuation", + test_client, NULL, NULL, 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, 0x04, 0x00, + 0x01, 0x18), + raw_pdu(0x08, 0x04, 0x00, 0xff, 0xff, 0x3a, 0x2b)); + service_db_1 = make_service_data_1_db(); service_db_2 = make_service_data_2_db(); service_db_3 = make_service_data_3_db(); -- 2.56.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 3/3] shared/gatt-client: Track pending discovery Database Hash reads 2026-11-11 21:42 ` [PATCH v2 0/3] shared/gatt-client: Track internal discovery reads Kyle Pepper 2026-11-11 21:43 ` [PATCH v2 1/3] shared/gatt-client: Support pending GATT helper requests Kyle Pepper 2026-11-11 21:43 ` [PATCH v2 2/3] shared/gatt-client: Track pending Server Features reads Kyle Pepper @ 2026-11-11 21:44 ` Kyle Pepper 2026-11-12 17:50 ` [PATCH v2 0/3] shared/gatt-client: Track internal discovery reads patchwork-bot+bluetooth 3 siblings, 0 replies; 9+ messages in thread From: Kyle Pepper @ 2026-11-11 21:44 UTC (permalink / raw) To: linux-bluetooth; +Cc: marcel, luiz.dentz The discovery Database Hash read retains an operation that can outlive the client. Track the read in pending_requests so cancellation releases it before the client is freed. Add queued, pending and continued-read regressions with cached Server Features, so they exercise the hash read independently of that fix. Fixes: 0f67d5e2f19f ("shared/gatt-client: Read database hash if available") Assisted-by: Codex:gpt-6 --- src/shared/gatt-client.c | 24 +++++++++++++++------ unit/test-gatt.c | 45 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c index 174325e27..e2e7113d0 100644 --- a/src/shared/gatt-client.c +++ b/src/shared/gatt-client.c @@ -1468,12 +1468,16 @@ static void db_hash_read_cb(bool success, uint8_t att_ecode, struct bt_gatt_result *result, void *user_data) { - struct discovery_op *op = user_data; + struct request *req = user_data; + struct discovery_op *op = req->data; struct bt_gatt_client *client = op->client; const uint8_t *hash = NULL, *value; uint16_t len, handle; struct bt_gatt_iter iter; + bt_gatt_request_unref(req->gatt_req); + req->gatt_req = NULL; + if (!success) goto discover; @@ -1532,6 +1536,7 @@ static void get_first_attribute(struct gatt_db_attribute *attrib, static bool read_db_hash(struct discovery_op *op) { struct bt_gatt_client *client = op->client; + struct request *req; bt_uuid_t uuid; /* Check if hash was already been read or there are more services to @@ -1546,11 +1551,18 @@ static bool read_db_hash(struct discovery_op *op) if (!op->hash) return false; - if (!bt_gatt_read_by_type(client->att, 0x0001, 0xffff, &uuid, - db_hash_read_cb, - discovery_op_ref(op), - discovery_op_unref)) { - discovery_op_unref(op); + req = request_create(client); + if (!req) + return false; + + req->data = discovery_op_ref(op); + req->destroy = discovery_op_unref; + req->gatt_req = bt_gatt_read_by_type_request(client->att, + 0x0001, 0xffff, &uuid, + db_hash_read_cb, req, + request_unref); + if (!req->gatt_req) { + request_unref(req); return false; } diff --git a/unit/test-gatt.c b/unit/test-gatt.c index c8ba2b5bb..cd60578ce 100644 --- a/unit/test-gatt.c +++ b/unit/test-gatt.c @@ -42,6 +42,7 @@ struct test_pdu { enum context_type { ATT, CLIENT, + CLIENT_CACHED, SERVER }; @@ -717,9 +718,15 @@ static struct context *create_context(uint16_t mtu, gconstpointer data) "bt_gatt_server:", NULL); break; case CLIENT: + case CLIENT_CACHED: step = test_data->step; - context->client_db = gatt_db_new(); + if (test_data->context_type == CLIENT_CACHED) + context->client_db = + gatt_db_ref(test_data->source_db); + else + context->client_db = gatt_db_new(); + g_assert(context->client_db); context->client = bt_gatt_client_new(context->client_db, @@ -2003,6 +2010,15 @@ static struct gatt_db *make_test_tail_db(void) return make_db(specs); } +static void test_client_cancel_hash(gconstpointer data) +{ + struct context *context = create_context(23, data); + + g_assert(bt_gatt_client_cancel_all(context->client)); + g_assert(bt_gatt_client_cancel_all(context->client)); + context_quit(context); +} + static void test_client(gconstpointer data) { create_context(512, data); @@ -2714,6 +2730,15 @@ int main(int argc, char *argv[]) { struct gatt_db *service_db_1, *service_db_2, *service_db_3; struct gatt_db *ts_small_db, *ts_large_db_1, *ts_tail_db; + struct gatt_db *hash_db; + const struct att_handle_spec hash_specs[] = { + PRIMARY_SERVICE(0x0001, GATT_UUID, 5), + CHARACTERISTIC(GATT_CHARAC_SERVER_FEAT, BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ, 0x00), + CHARACTERISTIC(GATT_CHARAC_DB_HASH, BT_ATT_PERM_READ, + BT_GATT_CHRC_PROP_READ, 0x00), + { } + }; tester_init(&argc, &argv); @@ -2747,6 +2772,24 @@ int main(int argc, char *argv[]) * Server Configuration. */ + hash_db = make_db(hash_specs); + define_test("/robustness/db-hash/queued", test_client_cancel_hash, + CLIENT_CACHED, NULL, hash_db, NULL, {}); + + define_test("/robustness/db-hash/pending", test_client, + CLIENT_CACHED, NULL, hash_db, NULL, + MTU_EXCHANGE_CLIENT_PDUS, + raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x2a, 0x2b)); + + define_test("/robustness/db-hash/continuation", test_client, + CLIENT_CACHED, NULL, hash_db, NULL, + MTU_EXCHANGE_CLIENT_PDUS, + raw_pdu(0x08, 0x01, 0x00, 0xff, 0xff, 0x2a, 0x2b), + raw_pdu(0x09, 0x12, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), + raw_pdu(0x08, 0x06, 0x00, 0xff, 0xff, 0x2a, 0x2b)); + define_test_client("/TP/GAC/CL/BV-01-C", test_client, NULL, NULL, raw_pdu(0x02, 0x00, 0x02)); -- 2.56.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v2 0/3] shared/gatt-client: Track internal discovery reads 2026-11-11 21:42 ` [PATCH v2 0/3] shared/gatt-client: Track internal discovery reads Kyle Pepper ` (2 preceding siblings ...) 2026-11-11 21:44 ` [PATCH v2 3/3] shared/gatt-client: Track pending discovery Database Hash reads Kyle Pepper @ 2026-11-12 17:50 ` patchwork-bot+bluetooth 3 siblings, 0 replies; 9+ messages in thread From: patchwork-bot+bluetooth @ 2026-11-12 17:50 UTC (permalink / raw) To: Kyle Pepper; +Cc: linux-bluetooth, marcel, luiz.dentz Hello: This series was applied to bluetooth/bluez.git (master) by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>: On Wed, 11 Nov 2026 21:42:55 +0000 you wrote: > Track Server Features and discovery Database Hash reads in pending_requests > so client cancellation releases them before the client is freed. > > Patch 1 adds shared request support. Patches 2 and 3 fix each read with > separate native ATT tests. Both depend only on patch 1; either fix and its > tests can be reverted independently. > > [...] Here is the summary with links: - [v2,1/3] shared/gatt-client: Support pending GATT helper requests https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=4be786143db8 - [v2,2/3] shared/gatt-client: Track pending Server Features reads https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=2e6bb945d6fa - [v2,3/3] shared/gatt-client: Track pending discovery Database Hash reads (no matching commit) You are awesome, thank you! -- Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-11-12 17:50 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-11-07 6:59 [PATCH] shared/gatt-client: Cancel discovery read-by-type requests Kyle Pepper 2026-11-07 8:45 ` bluez.test.bot 2026-11-07 20:53 ` [PATCH] " Luiz Augusto von Dentz 2026-11-11 21:42 ` [PATCH v2 0/3] shared/gatt-client: Track internal discovery reads Kyle Pepper 2026-11-11 21:43 ` [PATCH v2 1/3] shared/gatt-client: Support pending GATT helper requests Kyle Pepper 2026-11-12 1:58 ` shared/gatt-client: Track internal discovery reads bluez.test.bot 2026-11-11 21:43 ` [PATCH v2 2/3] shared/gatt-client: Track pending Server Features reads Kyle Pepper 2026-11-11 21:44 ` [PATCH v2 3/3] shared/gatt-client: Track pending discovery Database Hash reads Kyle Pepper 2026-11-12 17:50 ` [PATCH v2 0/3] shared/gatt-client: Track internal discovery reads patchwork-bot+bluetooth
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox