Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH BlueZ 0/3] Add Role property to org.bluez.Device
@ 2026-10-08 13:36 Kevin Dewald
  2026-10-08 13:36 ` [PATCH BlueZ 1/3] org.bluez.Device: Add Role property Kevin Dewald
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Kevin Dewald @ 2026-10-08 13:36 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Kevin Dewald

Applications acting as a peripheral, or in both roles, cannot tell
from org.bluez.Device1 whether a connected device is a central that
connected to the adapter or a peripheral the adapter connected to.
When several applications share the adapter, a device object can
appear because of any of them, so the order of events does not answer
it either.

bluetoothd already knows: the kernel flags connections the adapter
initiated in the Device Connected event, and bluetoothd keeps that per
bearer and uses it, e.g. to decide whether to discover the remote GATT
database. This series exposes it as a Role property, "central" or
"peripheral", present only while the device is connected over LE, and
prints it in bluetoothctl info.

It is limited to LE since an LE connection keeps its roles for its
lifetime, while BR/EDR roles can switch and the switch is not reported
to bluetoothd. It describes the link only, not GATT client and server
roles, and nothing is stored. Other stacks report the same per
connection, e.g. Zephyr's bt_conn_info role and NimBLE's
ble_gap_conn_desc role.

Tested with two btvirt controllers, where the advertising side reports
the other as "central" and the connecting side reports it as
"peripheral", and with a real adapter connecting to an nRF52840. The
property goes away when the connection does.

Kevin Dewald (3):
  org.bluez.Device: Add Role property
  device: Add Role property
  client: Print Role in info

 client/main.c            |  1 +
 doc/org.bluez.Device.rst | 20 ++++++++++++++++++++
 src/device.c             | 31 +++++++++++++++++++++++++++++++
 3 files changed, 52 insertions(+)

-- 
2.54.0 (Apple Git-157)


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH BlueZ 1/3] org.bluez.Device: Add Role property
  2026-10-08 13:36 [PATCH BlueZ 0/3] Add Role property to org.bluez.Device Kevin Dewald
@ 2026-10-08 13:36 ` Kevin Dewald
  2026-10-08 17:46   ` Add Role property to org.bluez.Device bluez.test.bot
  2026-10-08 13:36 ` [PATCH BlueZ 2/3] device: Add Role property Kevin Dewald
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 6+ messages in thread
From: Kevin Dewald @ 2026-10-08 13:36 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Kevin Dewald

This adds Role property which indicates whether the remote device is
the central or the peripheral of the current LE connection, so
applications can tell a central that connected to the adapter from a
peripheral the adapter connected to.

Assisted-by: Claude:claude-opus-5.5
---
 doc/org.bluez.Device.rst | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/doc/org.bluez.Device.rst b/doc/org.bluez.Device.rst
index f3e4bfa4a..27a225a9f 100644
--- a/doc/org.bluez.Device.rst
+++ b/doc/org.bluez.Device.rst
@@ -304,6 +304,26 @@ Indicates if the remote device is currently connected.
 
 A PropertiesChanged signal indicate changes to this status.
 
+string Role [readonly, optional]
+````````````````````````````````
+
+Indicates the role of the remote device in the current LE connection. It is
+only present while the remote device is connected over LE.
+
+Possible values:
+
+:"central":
+
+	The remote device initiated the connection, and the adapter is the
+	peripheral.
+
+:"peripheral":
+
+	The adapter initiated the connection, and the remote device is the
+	peripheral.
+
+A PropertiesChanged signal indicate changes to this status.
+
 boolean Trusted [readwrite]
 ```````````````````````````
 
-- 
2.54.0 (Apple Git-157)


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH BlueZ 2/3] device: Add Role property
  2026-10-08 13:36 [PATCH BlueZ 0/3] Add Role property to org.bluez.Device Kevin Dewald
  2026-10-08 13:36 ` [PATCH BlueZ 1/3] org.bluez.Device: Add Role property Kevin Dewald
@ 2026-10-08 13:36 ` Kevin Dewald
  2026-10-08 13:36 ` [PATCH BlueZ 3/3] client: Print Role in info Kevin Dewald
  2026-10-08 14:37 ` [PATCH BlueZ 0/3] Add Role property to org.bluez.Device Luiz Augusto von Dentz
  3 siblings, 0 replies; 6+ messages in thread
From: Kevin Dewald @ 2026-10-08 13:36 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Kevin Dewald

This implements Role property using the initiator flag of the Device
Connected event, which the kernel sets when the adapter created the
connection as central, and emits PropertiesChanged when an LE
connection is added or removed.

Assisted-by: Claude:claude-opus-5.5
---
 src/device.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/src/device.c b/src/device.c
index 1ab4e5342..1984b3e1c 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1457,6 +1457,28 @@ static gboolean dev_property_get_connected(const GDBusPropertyTable *property,
 	return TRUE;
 }
 
+static gboolean dev_property_get_role(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct btd_device *dev = data;
+	const char *role;
+
+	/* The initiator of an LE connection is always the central */
+	role = dev->le_state.initiator ? "peripheral" : "central";
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &role);
+
+	return TRUE;
+}
+
+static gboolean dev_property_exists_role(const GDBusPropertyTable *property,
+								void *data)
+{
+	struct btd_device *dev = data;
+
+	return dev->le_state.connected;
+}
+
 static gboolean dev_property_get_uuids(const GDBusPropertyTable *property,
 					DBusMessageIter *iter, void *data)
 {
@@ -3796,6 +3818,7 @@ static const GDBusPropertyTable device_properties[] = {
 	{ "CablePairing", "b", dev_property_get_cable_pairing },
 	{ "RSSI", "n", dev_property_get_rssi, NULL, dev_property_exists_rssi },
 	{ "Connected", "b", dev_property_get_connected },
+	{ "Role", "s", dev_property_get_role, NULL, dev_property_exists_role },
 	{ "UUIDs", "as", dev_property_get_uuids },
 	{ "Modalias", "s", dev_property_get_modalias, NULL,
 						dev_property_exists_modalias },
@@ -3944,6 +3967,10 @@ void device_add_connection(struct btd_device *dev, uint8_t bdaddr_type,
 	state->connected = true;
 	state->initiator = flags & BIT(3);
 
+	if (bdaddr_type != BDADDR_BREDR)
+		g_dbus_emit_property_changed(dbus_conn, dev->path,
+						DEVICE_INTERFACE, "Role");
+
 	if (dev->le_state.connected && dev->bredr_state.connected)
 		return;
 
@@ -4060,6 +4087,10 @@ void device_remove_connection(struct btd_device *device, uint8_t bdaddr_type,
 	state->initiator = false;
 	device->general_connect = FALSE;
 
+	if (bdaddr_type != BDADDR_BREDR)
+		g_dbus_emit_property_changed(dbus_conn, device->path,
+						DEVICE_INTERFACE, "Role");
+
 	device_set_svc_refreshed(device, false);
 
 	if (device->disconn_timer > 0) {
-- 
2.54.0 (Apple Git-157)


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH BlueZ 3/3] client: Print Role in info
  2026-10-08 13:36 [PATCH BlueZ 0/3] Add Role property to org.bluez.Device Kevin Dewald
  2026-10-08 13:36 ` [PATCH BlueZ 1/3] org.bluez.Device: Add Role property Kevin Dewald
  2026-10-08 13:36 ` [PATCH BlueZ 2/3] device: Add Role property Kevin Dewald
@ 2026-10-08 13:36 ` Kevin Dewald
  2026-10-08 14:37 ` [PATCH BlueZ 0/3] Add Role property to org.bluez.Device Luiz Augusto von Dentz
  3 siblings, 0 replies; 6+ messages in thread
From: Kevin Dewald @ 2026-10-08 13:36 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Kevin Dewald

This prints the Role property with the likes of info command:

bluetoothctl> info <addr>
...
        Connected: yes
        Role: central

Assisted-by: Claude:claude-opus-5.5
---
 client/main.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/client/main.c b/client/main.c
index f5fdd7d12..7f6b276a8 100644
--- a/client/main.c
+++ b/client/main.c
@@ -2044,6 +2044,7 @@ static void cmd_info(int argc, char *argv[])
 	print_property(proxy, "Trusted");
 	print_property(proxy, "Blocked");
 	print_property(proxy, "Connected");
+	print_property(proxy, "Role");
 	print_property(proxy, "WakeAllowed");
 	print_property(proxy, "LegacyPairing");
 	print_property(proxy, "CablePairing");
-- 
2.54.0 (Apple Git-157)


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH BlueZ 0/3] Add Role property to org.bluez.Device
  2026-10-08 13:36 [PATCH BlueZ 0/3] Add Role property to org.bluez.Device Kevin Dewald
                   ` (2 preceding siblings ...)
  2026-10-08 13:36 ` [PATCH BlueZ 3/3] client: Print Role in info Kevin Dewald
@ 2026-10-08 14:37 ` Luiz Augusto von Dentz
  3 siblings, 0 replies; 6+ messages in thread
From: Luiz Augusto von Dentz @ 2026-10-08 14:37 UTC (permalink / raw)
  To: Kevin Dewald; +Cc: linux-bluetooth

Hi Kevin,

On Thu, Oct 8, 2026 at 9:45 AM Kevin Dewald <kevin@simpleble.org> wrote:
>
> Applications acting as a peripheral, or in both roles, cannot tell
> from org.bluez.Device1 whether a connected device is a central that
> connected to the adapter or a peripheral the adapter connected to.
> When several applications share the adapter, a device object can
> appear because of any of them, so the order of events does not answer
> it either.
>
> bluetoothd already knows: the kernel flags connections the adapter
> initiated in the Device Connected event, and bluetoothd keeps that per
> bearer and uses it, e.g. to decide whether to discover the remote GATT
> database. This series exposes it as a Role property, "central" or
> "peripheral", present only while the device is connected over LE, and
> prints it in bluetoothctl info.
>
> It is limited to LE since an LE connection keeps its roles for its
> lifetime, while BR/EDR roles can switch and the switch is not reported
> to bluetoothd. It describes the link only, not GATT client and server
> roles, and nothing is stored. Other stacks report the same per
> connection, e.g. Zephyr's bt_conn_info role and NimBLE's
> ble_gap_conn_desc role.

Yeah, but if a device ever connects using both bearers, I'm afraid it
should be reported on a bearer interface so users don't assume the
Role applies to all bearers. I'm also afraid this may create problems
where the application might interpret this as all procedure roles
being equivalent to the device role (e.g. central acts as GATT client
vs peripheral is a GATT server). This was one of the reasons we didn't
expose this before. And yes, I agree LE connections don't have a role
switch procedure, but in GATT you can switch roles at will or even
have both client and server roles for profiles that support
simultaneous roles, so I'd leave this to be on a per-bearer basis only
to make it clear it is per connection.

> Tested with two btvirt controllers, where the advertising side reports
> the other as "central" and the connecting side reports it as
> "peripheral", and with a real adapter connecting to an nRF52840. The
> property goes away when the connection does.
>
> Kevin Dewald (3):
>   org.bluez.Device: Add Role property
>   device: Add Role property
>   client: Print Role in info
>
>  client/main.c            |  1 +
>  doc/org.bluez.Device.rst | 20 ++++++++++++++++++++
>  src/device.c             | 31 +++++++++++++++++++++++++++++++
>  3 files changed, 52 insertions(+)
>
> --
> 2.54.0 (Apple Git-157)
>
>


-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: Add Role property to org.bluez.Device
  2026-10-08 13:36 ` [PATCH BlueZ 1/3] org.bluez.Device: Add Role property Kevin Dewald
@ 2026-10-08 17:46   ` bluez.test.bot
  0 siblings, 0 replies; 6+ messages in thread
From: bluez.test.bot @ 2026-10-08 17:46 UTC (permalink / raw)
  To: linux-bluetooth, kevin

[-- Attachment #1: Type: text/plain, Size: 1020 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/1181653/

---Test result---

Test Summary:
CheckPatch                    PASS      0.93 seconds
GitLint                       PASS      0.71 seconds
BuildEll                      PASS      16.00 seconds
BluezMake                     PASS      281.45 seconds
MakeCheck                     PASS      13.81 seconds
MakeDistcheck                 PASS      113.75 seconds
CheckValgrind                 PASS      184.90 seconds
CheckSmatch                   PASS      220.13 seconds
bluezmakeextell               PASS      80.20 seconds
TestFunctional                PASS      940.17 seconds
IncrementalBuild              PASS      282.42 seconds
ScanBuild                     PASS      808.44 seconds



https://github.com/bluez/bluez/pull/2636

---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-10-08 17:46 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-08 13:36 [PATCH BlueZ 0/3] Add Role property to org.bluez.Device Kevin Dewald
2026-10-08 13:36 ` [PATCH BlueZ 1/3] org.bluez.Device: Add Role property Kevin Dewald
2026-10-08 17:46   ` Add Role property to org.bluez.Device bluez.test.bot
2026-10-08 13:36 ` [PATCH BlueZ 2/3] device: Add Role property Kevin Dewald
2026-10-08 13:36 ` [PATCH BlueZ 3/3] client: Print Role in info Kevin Dewald
2026-10-08 14:37 ` [PATCH BlueZ 0/3] Add Role property to org.bluez.Device Luiz Augusto von Dentz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox