* [PATCH BlueZ v2 1/4] org.bluez.Bearer: Add ReadRSSI method
2026-11-13 5:14 [PATCH BlueZ v2 0/4] Bearer.LE1: Add ReadRSSI Kevin Dewald
@ 2026-11-13 5:14 ` Kevin Dewald
2026-11-13 10:44 ` Bearer.LE1: Add ReadRSSI bluez.test.bot
2026-11-13 5:14 ` [PATCH BlueZ v2 2/4] adapter: Add btd_adapter_get_conn_info Kevin Dewald
` (3 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Kevin Dewald @ 2026-11-13 5:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Luiz Augusto von Dentz, Kevin Dewald
Add a testing method to read the RSSI of the current connection on LE
bearer, for diagnostics and production testing. It is only available
when D-Bus testing interfaces are enabled.
Assisted-by: Claude:claude-opus-5.5
---
doc/org.bluez.Bearer.LE.rst | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/doc/org.bluez.Bearer.LE.rst b/doc/org.bluez.Bearer.LE.rst
index 3db5237b4..803adb401 100644
--- a/doc/org.bluez.Bearer.LE.rst
+++ b/doc/org.bluez.Bearer.LE.rst
@@ -57,6 +57,25 @@ Possible errors:
:org.bluez.Error.NotConnected:
+int16 ReadRSSI() [testing]
+``````````````````````````
+
+Reads the Received Signal Strength Indicator of the current connection on LE
+bearer from the controller, in dBm, for diagnostics and production testing.
+
+Available only when D-Bus testing interfaces are enabled.
+
+The kernel caches the value for a few seconds, so calls made in quick succession
+may return the same value. Right after the connection is established, while it
+is still being set up, the method fails with org.bluez.Error.NotReady.
+
+Possible errors:
+
+:org.bluez.Error.NotConnected:
+:org.bluez.Error.NotReady:
+:org.bluez.Error.NotAvailable:
+:org.bluez.Error.Failed:
+
Signals
-------
--
2.54.0 (Apple Git-157)
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH BlueZ v2 2/4] adapter: Add btd_adapter_get_conn_info
2026-11-13 5:14 [PATCH BlueZ v2 0/4] Bearer.LE1: Add ReadRSSI Kevin Dewald
2026-11-13 5:14 ` [PATCH BlueZ v2 1/4] org.bluez.Bearer: Add ReadRSSI method Kevin Dewald
@ 2026-11-13 5:14 ` Kevin Dewald
2026-11-13 5:14 ` [PATCH BlueZ v2 3/4] bearer: Add ReadRSSI method Kevin Dewald
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Kevin Dewald @ 2026-11-13 5:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Luiz Augusto von Dentz, Kevin Dewald
Add a function to send Get Connection Information for a connection, and
one to cancel a pending mgmt request.
Assisted-by: Claude:claude-opus-5.5
---
src/adapter.c | 22 ++++++++++++++++++++++
src/adapter.h | 7 +++++++
2 files changed, 29 insertions(+)
diff --git a/src/adapter.c b/src/adapter.c
index ea438375c..fa55bd87c 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -11628,3 +11628,25 @@ unsigned int btd_adapter_send_cmd_event_sync(struct btd_adapter *adapter,
adapter->dev_id, sizeof(pkt.cp) + length,
&pkt, callback, user_data, destroy);
}
+
+unsigned int btd_adapter_get_conn_info(struct btd_adapter *adapter,
+ const bdaddr_t *bdaddr,
+ uint8_t bdaddr_type,
+ btd_adapter_reply_event_t callback,
+ void *user_data)
+{
+ struct mgmt_cp_get_conn_info cp;
+
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.addr.bdaddr, bdaddr);
+ cp.addr.type = bdaddr_type;
+
+ return mgmt_send(adapter->mgmt, MGMT_OP_GET_CONN_INFO,
+ adapter->dev_id, sizeof(cp), &cp,
+ callback, user_data, NULL);
+}
+
+void btd_adapter_cancel_request(struct btd_adapter *adapter, unsigned int id)
+{
+ mgmt_cancel(adapter->mgmt, id);
+}
diff --git a/src/adapter.h b/src/adapter.h
index 583168f4b..3c777afe1 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -328,3 +328,10 @@ unsigned int btd_adapter_send_cmd_event_sync(struct btd_adapter *adapter,
void *user_data,
btd_adapter_destroy_func_t destroy,
uint8_t timeout);
+
+unsigned int btd_adapter_get_conn_info(struct btd_adapter *adapter,
+ const bdaddr_t *bdaddr,
+ uint8_t bdaddr_type,
+ btd_adapter_reply_event_t callback,
+ void *user_data);
+void btd_adapter_cancel_request(struct btd_adapter *adapter, unsigned int id);
--
2.54.0 (Apple Git-157)
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH BlueZ v2 3/4] bearer: Add ReadRSSI method
2026-11-13 5:14 [PATCH BlueZ v2 0/4] Bearer.LE1: Add ReadRSSI Kevin Dewald
2026-11-13 5:14 ` [PATCH BlueZ v2 1/4] org.bluez.Bearer: Add ReadRSSI method Kevin Dewald
2026-11-13 5:14 ` [PATCH BlueZ v2 2/4] adapter: Add btd_adapter_get_conn_info Kevin Dewald
@ 2026-11-13 5:14 ` Kevin Dewald
2026-11-13 5:14 ` [PATCH BlueZ v2 4/4] test: functional: add bearer ReadRSSI test Kevin Dewald
2026-11-13 16:33 ` [PATCH BlueZ v2 0/4] Bearer.LE1: Add ReadRSSI Luiz Augusto von Dentz
4 siblings, 0 replies; 7+ messages in thread
From: Kevin Dewald @ 2026-11-13 5:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Luiz Augusto von Dentz, Kevin Dewald
Implement Bearer.LE1.ReadRSSI with Get Connection Information, as a
testing method. The kernel reads the RSSI from the controller, or
returns the value it read last if that is recent enough
(conn_info_min_age and conn_info_max_age, 1 to 3 seconds by default).
The kernel reports a connection as soon as it is established but only
answers Get Connection Information once it has set it up, so a call made
right after Connect returns fails with NotReady rather than NotConnected.
Calls made while a request is pending get its result rather than sending
another one, as the kernel would answer that with its cached value,
which a new connection does not have yet.
The method is only on Bearer.LE1, as the RSSI of a BR/EDR connection is
relative to the golden receive power range rather than in dBm.
Assisted-by: Claude:claude-opus-5.5
---
src/bearer.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 109 insertions(+), 2 deletions(-)
diff --git a/src/bearer.c b/src/bearer.c
index ebcdc2b4c..3cbb74bcc 100644
--- a/src/bearer.c
+++ b/src/bearer.c
@@ -57,6 +57,10 @@ struct btd_bearer {
*/
DBusMessage *connect; /* connect message */
+ /* ReadRSSI calls waiting for the Get Connection Information reply */
+ unsigned int conn_info_id;
+ struct queue *rssi_reads;
+
/* LE connection parameters, only valid while connected */
bool conn_params;
uint32_t interval; /* in microseconds */
@@ -213,10 +217,93 @@ static DBusMessage *bearer_disconnect(DBusConnection *conn, DBusMessage *msg,
return NULL;
}
-static const GDBusMethodTable bearer_methods[] = {
+static DBusMessage *rssi_reply(struct btd_bearer *bearer, DBusMessage *msg,
+ uint8_t status, uint16_t length,
+ const struct mgmt_rp_get_conn_info *rp)
+{
+ dbus_int16_t rssi;
+
+ /* The kernel reports the connection as soon as it is established, but
+ * only answers once it has set it up, e.g. read the remote features.
+ */
+ if (status == MGMT_STATUS_NOT_CONNECTED) {
+ if (btd_device_bdaddr_type_connected(bearer->device,
+ bearer->type))
+ return btd_error_not_ready(msg);
+
+ return btd_error_not_connected(msg);
+ }
+
+ if (status != MGMT_STATUS_SUCCESS)
+ return btd_error_failed(msg, mgmt_errstr(status));
+
+ if (length < sizeof(*rp))
+ return btd_error_failed(msg, "Invalid response");
+
+ /* 127 means the controller has no RSSI for the connection */
+ if (rp->rssi == 127)
+ return btd_error_not_available(msg);
+
+ rssi = rp->rssi;
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INT16, &rssi,
+ DBUS_TYPE_INVALID);
+}
+
+static void conn_info_complete(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ struct btd_bearer *bearer = user_data;
+ DBusMessage *msg;
+
+ bearer->conn_info_id = 0;
+
+ while ((msg = queue_pop_head(bearer->rssi_reads))) {
+ g_dbus_send_message(btd_get_dbus_connection(),
+ rssi_reply(bearer, msg, status, length, param));
+ dbus_message_unref(msg);
+ }
+}
+
+static DBusMessage *bearer_read_rssi(DBusConnection *conn, DBusMessage *msg,
+ void *user_data)
+{
+ struct btd_bearer *bearer = user_data;
+ struct btd_device *device = bearer->device;
+
+ if (!btd_device_bdaddr_type_connected(device, bearer->type))
+ return btd_error_not_connected(msg);
+
+ /* Calls made while a read is pending get the same result */
+ if (!bearer->conn_info_id) {
+ bearer->conn_info_id = btd_adapter_get_conn_info(
+ device_get_adapter(device),
+ device_get_address(device),
+ device_get_le_address_type(device),
+ conn_info_complete, bearer);
+ if (!bearer->conn_info_id)
+ return btd_error_failed(msg, "Unable to read RSSI");
+ }
+
+ queue_push_tail(bearer->rssi_reads, dbus_message_ref(msg));
+
+ return NULL;
+}
+
+static const GDBusMethodTable bearer_bredr_methods[] = {
+ { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, bearer_connect) },
+ { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL,
+ bearer_disconnect) },
+ {}
+};
+
+static const GDBusMethodTable bearer_le_methods[] = {
{ GDBUS_ASYNC_METHOD("Connect", NULL, NULL, bearer_connect) },
{ GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL,
bearer_disconnect) },
+ { GDBUS_TESTING_ASYNC_METHOD("ReadRSSI", NULL,
+ GDBUS_ARGS({ "rssi", "n" }),
+ bearer_read_rssi) },
{}
};
@@ -404,6 +491,14 @@ static const char *bearer_interface(uint8_t type)
return BTD_BEARER_LE_INTERFACE;
}
+static const GDBusMethodTable *bearer_methods(uint8_t type)
+{
+ if (type == BDADDR_BREDR)
+ return bearer_bredr_methods;
+ else
+ return bearer_le_methods;
+}
+
struct btd_bearer *btd_bearer_new(struct btd_device *device, uint8_t type)
{
struct btd_bearer *bearer;
@@ -426,10 +521,11 @@ struct btd_bearer *btd_bearer_new(struct btd_device *device, uint8_t type)
bearer->type = type;
bearer->path = device_get_path(device);
bearer->disconnects = queue_new();
+ bearer->rssi_reads = queue_new();
if (!g_dbus_register_interface(btd_get_dbus_connection(),
bearer->path, bearer_interface(type),
- bearer_methods, bearer_signals,
+ bearer_methods(type), bearer_signals,
bearer_properties,
bearer, bearer_free)) {
error("Unable to register BREDR interface");
@@ -459,6 +555,17 @@ void btd_bearer_destroy(struct btd_bearer *bearer)
bearer->connect = NULL;
}
+ if (bearer->conn_info_id) {
+ btd_adapter_cancel_request(device_get_adapter(bearer->device),
+ bearer->conn_info_id);
+ bearer->conn_info_id = 0;
+ }
+
+ if (bearer->rssi_reads) {
+ queue_destroy(bearer->rssi_reads, bearer_free_dbus_message);
+ bearer->rssi_reads = NULL;
+ }
+
g_dbus_unregister_interface(btd_get_dbus_connection(), bearer->path,
bearer_interface(bearer->type));
}
--
2.54.0 (Apple Git-157)
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH BlueZ v2 4/4] test: functional: add bearer ReadRSSI test
2026-11-13 5:14 [PATCH BlueZ v2 0/4] Bearer.LE1: Add ReadRSSI Kevin Dewald
` (2 preceding siblings ...)
2026-11-13 5:14 ` [PATCH BlueZ v2 3/4] bearer: Add ReadRSSI method Kevin Dewald
@ 2026-11-13 5:14 ` Kevin Dewald
2026-11-13 16:33 ` [PATCH BlueZ v2 0/4] Bearer.LE1: Add ReadRSSI Luiz Augusto von Dentz
4 siblings, 0 replies; 7+ messages in thread
From: Kevin Dewald @ 2026-11-13 5:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Luiz Augusto von Dentz, Kevin Dewald
Read the RSSI of the LE connection from a host with testing interfaces
enabled, check ReadRSSI fails with NotConnected once disconnected, and
check a host without testing interfaces does not expose it.
Assisted-by: Claude:claude-opus-5.5
---
test/functional/test_bearer.py | 42 ++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/test/functional/test_bearer.py b/test/functional/test_bearer.py
index 59ce8ef7d..41134221a 100644
--- a/test/functional/test_bearer.py
+++ b/test/functional/test_bearer.py
@@ -54,6 +54,9 @@ UPDATE_CONF = LE_CONF + "[LE]\nMinConnectionInterval = 80\nMaxConnectionInterval
CONN_PARAMS = ("Interval", "Latency", "SupervisionTimeout", "Subrate")
+# ReadRSSI is a testing method
+TESTING_CONF = LE_CONF + "Testing = true\n"
+
class Bearers(HostPlugin, EventPluginMixin):
"""
@@ -283,6 +286,45 @@ def test_bearer_le_conn_params(hosts):
assert host.bearers.get(remote.bdaddr, LE_INTERFACE, name) is None
+@host_config(
+ [
+ Bluetoothd(conf=TESTING_CONF, args=ARGS),
+ Agent(capability="NoInputNoOutput"),
+ Bearers(),
+ ],
+ [
+ Bluetoothd(conf=LE_CONF, args=ARGS),
+ LeAdvertiser(),
+ Agent(capability="NoInputNoOutput"),
+ Bearers(),
+ ],
+)
+def test_bearer_le_read_rssi(hosts):
+ host0, host1 = hosts
+
+ connect_le(host0, host1)
+
+ for host, remote in peers(host0, host1):
+ wait_until(
+ lambda: host.bearers.get(remote.bdaddr, LE_INTERFACE, "Connected") is True
+ )
+
+ # The emulated controller reports -1 dBm for every connection
+ host0.bearers.call(host1.bdaddr, LE_INTERFACE, "ReadRSSI")
+ reply = host0.bearers.expect(f"{LE_INTERFACE}.ReadRSSI:reply")
+ assert reply.values == (-1,)
+
+ host1.bearers.call(host0.bdaddr, LE_INTERFACE, "ReadRSSI")
+ error = host1.bearers.expect(f"{LE_INTERFACE}.ReadRSSI:error").error
+ assert error.get_dbus_name() == "org.freedesktop.DBus.Error.UnknownMethod"
+
+ disconnect(host0, host1, LE_INTERFACE)
+
+ host0.bearers.call(host1.bdaddr, LE_INTERFACE, "ReadRSSI")
+ error = host0.bearers.expect(f"{LE_INTERFACE}.ReadRSSI:error").error
+ assert error.get_dbus_name() == "org.bluez.Error.NotConnected"
+
+
@host_config(
[
Bluetoothd(conf=LE_CONF, args=ARGS),
--
2.54.0 (Apple Git-157)
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH BlueZ v2 0/4] Bearer.LE1: Add ReadRSSI
2026-11-13 5:14 [PATCH BlueZ v2 0/4] Bearer.LE1: Add ReadRSSI Kevin Dewald
` (3 preceding siblings ...)
2026-11-13 5:14 ` [PATCH BlueZ v2 4/4] test: functional: add bearer ReadRSSI test Kevin Dewald
@ 2026-11-13 16:33 ` Luiz Augusto von Dentz
4 siblings, 0 replies; 7+ messages in thread
From: Luiz Augusto von Dentz @ 2026-11-13 16:33 UTC (permalink / raw)
To: Kevin Dewald; +Cc: linux-bluetooth
Hi Kevin,
On Fri, Nov 13, 2026 at 12:14 AM Kevin Dewald <kevin@simpleble.org> wrote:
>
> This adds ReadRSSI to Bearer.LE1 as a testing method, for diagnostics
> and production testing, as discussed on v1 [1]. It is only available
> when D-Bus testing interfaces are enabled, with bluetoothd -T or
> Testing = true in main.conf.
>
> Each call sends Get Connection Information, which the kernel answers
> from the controller or with the value it read in the last 1 to 3
> seconds. A call made right after Connect returns fails with NotReady
> until the kernel has read the remote features.
>
> Changes in v2:
> - Make ReadRSSI a testing method and mark it [testing] in the
> documentation.
> - Enable testing interfaces on one host in the functional test, and
> check that the other host does not export ReadRSSI.
> - Rebase on master.
>
> Tested with the functional test on bluetooth-next 3f425f95ba39, and on
> an RTL8761BU connected to an nRF52840. With -T, ReadRSSI returned
> -48 dBm; without it, the method was not exported.
>
> [1] https://lore.kernel.org/linux-bluetooth/20261112032250.37687-1-kevin@simpleble.org/
>
> Kevin Dewald (4):
> org.bluez.Bearer: Add ReadRSSI method
> adapter: Add btd_adapter_get_conn_info
> bearer: Add ReadRSSI method
> test: functional: add bearer ReadRSSI test
>
> doc/org.bluez.Bearer.LE.rst | 19 ++++++
> src/adapter.c | 22 +++++++
> src/adapter.h | 7 +++
> src/bearer.c | 111 ++++++++++++++++++++++++++++++++-
> test/functional/test_bearer.py | 42 +++++++++++++
> 5 files changed, 199 insertions(+), 2 deletions(-)
>
>
> base-commit: 20ffd285b58facfd1f2478d159a5f941b09d5be1
> --
> 2.54.0 (Apple Git-157)
Copilot flagged 2 problems:
https://github.com/bluez/bluez/pull/2820#pullrequestreview-5894592293
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 7+ messages in thread