From: Cheng Jiang <cheng.jiang@oss.qualcomm.com>
To: linux-bluetooth@vger.kernel.org
Cc: jinwang.li@oss.qualcomm.com, wei.deng@oss.qualcomm.com,
xiuzhuo.shang@oss.qualcomm.com, shuai.zhang@oss.qualcomm.com,
Cheng Jiang <cheng.jiang@oss.qualcomm.com>
Subject: [PATCH 02/11] shared/gatt-db: Add gatt_db_attribute_indicate()
Date: Thu, 1 Oct 2026 21:18:48 +0800 [thread overview]
Message-ID: <20261001131900.707485-3-cheng.jiang@oss.qualcomm.com> (raw)
In-Reply-To: <20261001131900.707485-1-cheng.jiang@oss.qualcomm.com>
The notify callback leaves the choice between a notification and an
indication entirely to the CCC value written by the client, preferring
notifications whenever the client enabled them. Some services need the
indication transport for a given characteristic regardless: the Ranging
Service must indicate Ranging Data Ready and Ranging Data Overwritten
even when the client subscribed to both transports (RAS 3.4.2, 3.5.2).
Add gatt_db_attribute_indicate() alongside gatt_db_attribute_notify() and
let the callback query which of the two it was invoked from through
gatt_db_attribute_indicate_only(). Both entry points share a helper, so
the CCC lookup stays in one place, and neither gatt_db_notify_t nor the
existing gatt_db_attribute_notify() callers change.
gatt-database honors the request by skipping the notification branch and
sending an indication instead, provided the client enabled indications.
Assisted-by: Claude:claude-opus-4.8
---
src/gatt-database.c | 7 ++++++-
src/shared/gatt-db.c | 35 +++++++++++++++++++++++++++++++++--
src/shared/gatt-db.h | 17 +++++++++++++++++
unit/test-rap.c | 13 +++++++++----
4 files changed, 65 insertions(+), 7 deletions(-)
diff --git a/src/gatt-database.c b/src/gatt-database.c
index 18b7aa667..800f76032 100644
--- a/src/gatt-database.c
+++ b/src/gatt-database.c
@@ -168,6 +168,7 @@ struct notify {
uint16_t len;
bt_gatt_server_conf_func_t conf;
void *user_data;
+ bool indicate_only;
};
#define CLI_FEAT_SIZE 1
@@ -1446,7 +1447,7 @@ static void send_notification_to_device(void *data, void *user_data)
* TODO: If the device is not connected but bonded, send the
* notification/indication when it becomes connected.
*/
- if (ccc->value & 0x0001) {
+ if (!notify->indicate_only && (ccc->value & 0x0001)) {
DBG("GATT server sending notification");
bt_gatt_server_send_notification(server,
notify->handle, notify->value,
@@ -1455,6 +1456,9 @@ static void send_notification_to_device(void *data, void *user_data)
return;
}
+ if (!(ccc->value & 0x0002))
+ return;
+
DBG("GATT server sending indication");
bt_gatt_server_send_indication(server, notify->handle, notify->value,
notify->len, notify->conf,
@@ -1486,6 +1490,7 @@ static void gatt_notify_cb(struct gatt_db_attribute *attrib,
notify.ccc_handle = gatt_db_attribute_get_handle(ccc);
notify.value = (void *) value;
notify.len = len;
+ notify.indicate_only = gatt_db_attribute_indicate_only(attrib);
if (attrib == database->svc_chngd)
notify.conf = service_changed_conf;
diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 751d4c3da..1f6e9ae14 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -123,6 +123,11 @@ struct gatt_db_attribute {
unsigned int next_notify_id;
struct queue *notify_list;
+
+ /* Set only while notify_func is being called on behalf of
+ * gatt_db_attribute_indicate().
+ */
+ bool indicate_only;
};
struct gatt_db_service {
@@ -2440,9 +2445,9 @@ gatt_db_attribute_get_ccc(struct gatt_db_attribute *attrib)
return ccc;
}
-bool gatt_db_attribute_notify(struct gatt_db_attribute *attrib,
+static bool attribute_notify(struct gatt_db_attribute *attrib,
const uint8_t *value, size_t len,
- struct bt_att *att)
+ struct bt_att *att, bool indicate_only)
{
struct gatt_db_attribute *ccc;
struct gatt_db *db;
@@ -2468,11 +2473,37 @@ bool gatt_db_attribute_notify(struct gatt_db_attribute *attrib,
else
notify_user_data = ccc->user_data;
+ attrib->indicate_only = indicate_only;
+
attrib->notify_func(attrib, ccc, value, len, att, notify_user_data);
+ attrib->indicate_only = false;
+
return true;
}
+bool gatt_db_attribute_notify(struct gatt_db_attribute *attrib,
+ const uint8_t *value, size_t len,
+ struct bt_att *att)
+{
+ return attribute_notify(attrib, value, len, att, false);
+}
+
+bool gatt_db_attribute_indicate(struct gatt_db_attribute *attrib,
+ const uint8_t *value, size_t len,
+ struct bt_att *att)
+{
+ return attribute_notify(attrib, value, len, att, true);
+}
+
+bool gatt_db_attribute_indicate_only(const struct gatt_db_attribute *attrib)
+{
+ if (!attrib)
+ return false;
+
+ return attrib->indicate_only;
+}
+
bool gatt_db_attribute_reset(struct gatt_db_attribute *attrib)
{
if (!attrib)
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index da0600c01..63d7f3464 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -300,6 +300,23 @@ bool gatt_db_attribute_notify(struct gatt_db_attribute *attrib,
const uint8_t *value, size_t len,
struct bt_att *att);
+/* Same as gatt_db_attribute_notify() but requests an indication even when the
+ * client has also enabled notifications. Some profiles mandate the indication
+ * transport for specific characteristics (e.g. the RAS Ranging Data Ready and
+ * Ranging Data Overwritten characteristics), which gatt_db_attribute_notify()
+ * cannot express since it prefers notifications whenever the client enabled
+ * them.
+ */
+bool gatt_db_attribute_indicate(struct gatt_db_attribute *attrib,
+ const uint8_t *value, size_t len,
+ struct bt_att *att);
+
+/* Valid only while a gatt_db_notify_t callback is running: tells whether it was
+ * triggered by gatt_db_attribute_indicate() rather than
+ * gatt_db_attribute_notify().
+ */
+bool gatt_db_attribute_indicate_only(const struct gatt_db_attribute *attrib);
+
bool gatt_db_attribute_reset(struct gatt_db_attribute *attrib);
void *gatt_db_attribute_get_user_data(struct gatt_db_attribute *attrib);
diff --git a/unit/test-rap.c b/unit/test-rap.c
index d7da2ff45..5c6033a4e 100644
--- a/unit/test-rap.c
+++ b/unit/test-rap.c
@@ -167,10 +167,15 @@ static void gatt_notify_cb(struct gatt_db_attribute *attrib,
printf("%s: notify.value:%d notify->len:%d\n", __func__,
(int)*(notify.value), notify.len);
- if (!bt_gatt_server_send_notification(data->server,
- notify.handle, notify.value,
- notify.len, false))
- printf("%s: Failed to send notification\n", __func__);
+ if (gatt_db_attribute_indicate_only(attrib)) {
+ if (!bt_gatt_server_send_indication(data->server, notify.handle,
+ notify.value, notify.len, NULL, NULL, NULL) &&
+ tester_use_debug())
+ tester_debug("Failed to send indication");
+ } else if (!bt_gatt_server_send_notification(data->server,
+ notify.handle, notify.value, notify.len, false) &&
+ tester_use_debug())
+ tester_debug("Failed to send notification");
}
static void gatt_ccc_write_cb(struct gatt_db_attribute *attrib,
--
2.43.0
next prev parent reply other threads:[~2026-10-01 13:19 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-01 13:18 [PATCH 00/11] Ranging Profile and Ranging Service PTS fixes Cheng Jiang
2026-10-01 13:18 ` [PATCH 01/11] shared/gatt-client: Allow registering notify with explicit CCC value Cheng Jiang
2026-10-01 16:03 ` Ranging Profile and Ranging Service PTS fixes bluez.test.bot
2026-10-01 13:18 ` Cheng Jiang [this message]
2026-10-01 15:48 ` [PATCH 02/11] shared/gatt-db: Add gatt_db_attribute_indicate() Luiz Augusto von Dentz
2026-10-09 8:45 ` Cheng Jiang
2026-10-01 13:18 ` [PATCH 03/11] shared/rap: Honor CCCD transport for RAS on-demand ranging data Cheng Jiang
2026-10-01 13:18 ` [PATCH 04/11] shared/rap: Add RAS Control Point Abort Operation Cheng Jiang
2026-10-01 13:18 ` [PATCH 05/11] shared/rap: Shorten the requester Control Point response timeout Cheng Jiang
2026-10-01 13:18 ` [PATCH 06/11] shared/rap: Add real-time ranging data delivery on the responder Cheng Jiang
2026-10-01 13:18 ` [PATCH 07/11] shared/rap: Add requester ranging data subscription API Cheng Jiang
2026-10-01 13:18 ` [PATCH 08/11] profiles/ranging: Expose requester ranging data mode over D-Bus Cheng Jiang
2026-10-01 13:18 ` [PATCH 09/11] client: Add Channel Sounding ranging data mode control Cheng Jiang
2026-10-01 13:18 ` [PATCH 10/11] doc: Document " Cheng Jiang
2026-10-01 13:18 ` [PATCH 11/11] doc/qualification: Add RAP/RAS PTS qualification results Cheng Jiang
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=20261001131900.707485-3-cheng.jiang@oss.qualcomm.com \
--to=cheng.jiang@oss.qualcomm.com \
--cc=jinwang.li@oss.qualcomm.com \
--cc=linux-bluetooth@vger.kernel.org \
--cc=shuai.zhang@oss.qualcomm.com \
--cc=wei.deng@oss.qualcomm.com \
--cc=xiuzhuo.shang@oss.qualcomm.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.