From: Martin BTS <martinbts@gmx.net>
To: linux-bluetooth@vger.kernel.org
Cc: hadess@hadess.net, luiz.dentz@gmail.com, vi@endrift.com,
Martin BTS <martinbts@gmx.net>
Subject: [PATCH BlueZ v3 2/6] shared/gatt: Add timeout for secondary service discovery
Date: Fri, 3 Apr 2026 10:55:49 +0200 [thread overview]
Message-ID: <20260403085555.23871-3-martinbts@gmx.net> (raw)
In-Reply-To: <20260403085555.23871-1-martinbts@gmx.net>
Some BLE devices do not respond to secondary service discovery
requests, causing the 30-second ATT timeout to fire and terminate the
connection. Add a 2-second timeout at the GATT client level that
cancels the pending ATT request and proceeds as if no secondary
services were found. This prevents the ATT timeout from killing the
connection while still giving well-behaved devices enough time to
respond.
---
src/shared/gatt-client.c | 62 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 61 insertions(+), 1 deletion(-)
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index e1685809f..3e1c3e525 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -20,6 +20,7 @@
#include "src/shared/queue.h"
#include "src/shared/gatt-db.h"
#include "src/shared/gatt-client.h"
+#include "src/shared/timeout.h"
#include <assert.h>
#include <limits.h>
@@ -33,6 +34,8 @@
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
+#define SECONDARY_DISC_TIMEOUT 2000 /* 2 seconds in ms */
+
#define UUID_BYTES (BT_GATT_UUID_SIZE * sizeof(uint8_t))
#define GATT_SVC_UUID 0x1801
@@ -114,6 +117,7 @@ struct bt_gatt_client {
unsigned int next_request_id;
struct bt_gatt_request *discovery_req;
+ unsigned int sec_disc_timeout_id;
unsigned int mtu_req_id;
/* Pending retry operation for DB out of sync handling */
@@ -1231,6 +1235,42 @@ static bool discovery_parse_services(struct discovery_op *op, bool primary,
return true;
}
+struct sec_disc_timeout_data {
+ struct bt_gatt_client *client;
+ struct discovery_op *op;
+};
+
+static bool sec_disc_timeout_cb(void *user_data)
+{
+ struct sec_disc_timeout_data *data = user_data;
+ struct bt_gatt_client *client = data->client;
+ struct discovery_op *op = data->op;
+
+ DBG(client, "Secondary service discovery timed out, proceeding");
+
+ client->sec_disc_timeout_id = 0;
+
+ /* Cancel the pending ATT request before it hits the 30s ATT timeout */
+ if (client->discovery_req) {
+ bt_gatt_request_cancel(client->discovery_req);
+ bt_gatt_request_unref(client->discovery_req);
+ client->discovery_req = NULL;
+ }
+
+ /* Treat as success — no secondary services found */
+ discovery_op_complete(op, true, 0);
+
+ return false;
+}
+
+static void sec_disc_timeout_destroy(void *user_data)
+{
+ struct sec_disc_timeout_data *data = user_data;
+
+ discovery_op_unref(data->op);
+ free(data);
+}
+
static void discover_secondary_cb(bool success, uint8_t att_ecode,
struct bt_gatt_result *result,
void *user_data)
@@ -1242,6 +1282,11 @@ static void discover_secondary_cb(bool success, uint8_t att_ecode,
discovery_req_clear(client);
+ if (client->sec_disc_timeout_id) {
+ timeout_remove(client->sec_disc_timeout_id);
+ client->sec_disc_timeout_id = 0;
+ }
+
if (!success) {
switch (att_ecode) {
case BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND:
@@ -1354,8 +1399,18 @@ secondary:
discover_secondary_cb,
discovery_op_ref(op),
discovery_op_unref);
- if (client->discovery_req)
+ if (client->discovery_req) {
+ struct sec_disc_timeout_data *td;
+
+ td = new0(struct sec_disc_timeout_data, 1);
+ td->client = client;
+ td->op = discovery_op_ref(op);
+ client->sec_disc_timeout_id = timeout_add(
+ SECONDARY_DISC_TIMEOUT,
+ sec_disc_timeout_cb, td,
+ sec_disc_timeout_destroy);
return;
+ }
DBG(client, "Failed to start secondary service discovery");
@@ -2822,6 +2877,11 @@ bool bt_gatt_client_cancel_all(struct bt_gatt_client *client)
queue_remove_all(client->pending_requests, NULL, NULL, cancel_pending);
+ if (client->sec_disc_timeout_id) {
+ timeout_remove(client->sec_disc_timeout_id);
+ client->sec_disc_timeout_id = 0;
+ }
+
if (client->discovery_req) {
bt_gatt_request_cancel(client->discovery_req);
bt_gatt_request_unref(client->discovery_req);
--
2.47.3
next prev parent reply other threads:[~2026-04-03 8:56 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-03 8:55 [PATCH BlueZ v3 0/6] BLE-HID/Nintendo Switch 2 support Martin BTS
2026-04-03 8:55 ` [PATCH BlueZ v3 1/6] shared/gatt: Add skip_secondary option for GATT client Martin BTS
2026-04-03 10:18 ` BLE-HID/Nintendo Switch 2 support bluez.test.bot
2026-04-03 8:55 ` Martin BTS [this message]
2026-04-03 8:55 ` [PATCH BlueZ v3 3/6] device: Rename set_alias to btd_device_set_alias() Martin BTS
2026-04-03 8:55 ` [PATCH BlueZ v3 4/6] dbus-common: Add Gaming appearance class (0x2a) Martin BTS
2026-04-03 8:55 ` [PATCH BlueZ v3 5/6] plugins/gatt-uhid: Add generic GATT-to-UHID bridge Martin BTS
2026-04-03 8:55 ` [PATCH BlueZ v3 6/6] plugins/switch2: Add Nintendo Switch 2 Controller plugin Martin BTS
-- strict thread matches above, loose matches on Subject: below --
2026-03-17 20:26 [PATCH BlueZ v3 0/6] BLE-HID/Nintendo Switch 2 support Martin BTS
2026-03-17 20:26 ` [PATCH BlueZ v3 2/6] shared/gatt: Add timeout for secondary service discovery Martin BTS
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=20260403085555.23871-3-martinbts@gmx.net \
--to=martinbts@gmx.net \
--cc=hadess@hadess.net \
--cc=linux-bluetooth@vger.kernel.org \
--cc=luiz.dentz@gmail.com \
--cc=vi@endrift.com \
/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