Linux bluetooth development
 help / color / mirror / Atom feed
* RE: Add Channel Sounding Dbus support and
  2026-07-10  9:49 [PATCH BlueZ v2 1/4] rap: Add Channel Sounding parameter types and APIs Naga Bhavani Akella
@ 2026-07-10 11:57 ` bluez.test.bot
  0 siblings, 0 replies; 7+ messages in thread
From: bluez.test.bot @ 2026-07-10 11:57 UTC (permalink / raw)
  To: linux-bluetooth, naga.akella

[-- Attachment #1: Type: text/plain, Size: 57537 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/project/bluetooth/list/?series=1125291

---Test result---

Test Summary:
CheckPatch                    PASS      2.63 seconds
GitLint                       PASS      1.05 seconds
BuildEll                      PASS      15.57 seconds
BluezMake                     FAIL      384.30 seconds
MakeCheck                     FAIL      17.53 seconds
MakeDistcheck                 PASS      126.15 seconds
CheckValgrind                 FAIL      108.07 seconds
CheckSmatch                   FAIL      204.34 seconds
bluezmakeextell               FAIL      72.71 seconds
IncrementalBuild              FAIL      402.88 seconds
ScanBuild                     FAIL      329.30 seconds

Details
##############################
Test: BluezMake - FAIL
Desc: Build BlueZ
Output:

tools/mgmt-tester.c: In function ‘main’:
tools/mgmt-tester.c:12990:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
12990 | int main(int argc, char *argv[])
      |     ^~~~
unit/test-avdtp.c: In function ‘main’:
unit/test-avdtp.c:766:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
  766 | int main(int argc, char *argv[])
      |     ^~~~
unit/test-avrcp.c: In function ‘main’:
unit/test-avrcp.c:989:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
  989 | int main(int argc, char *argv[])
      |     ^~~~
profiles/ranging/rap.c: In function ‘start_measurement’:
profiles/ranging/rap.c:472:4: error: enumeration value ‘CS_TARGET_SETTINGS’ not handled in switch [-Werror=switch-enum]
  472 |    switch (desc->target) {
      |    ^~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8999: profiles/ranging/bluetoothd-rap.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4175: all] Error 2
##############################
Test: MakeCheck - FAIL
Desc: Run Bluez Make Check
Output:

profiles/ranging/rap.c: In function ‘start_measurement’:
profiles/ranging/rap.c:472:4: error: enumeration value ‘CS_TARGET_SETTINGS’ not handled in switch [-Werror=switch-enum]
  472 |    switch (desc->target) {
      |    ^~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8999: profiles/ranging/bluetoothd-rap.o] Error 1
make: *** [Makefile:10826: check] Error 2
##############################
Test: CheckValgrind - FAIL
Desc: Run Bluez Make Check with Valgrind
Output:

tools/mgmt-tester.c: In function ‘main’:
tools/mgmt-tester.c:12990:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
12990 | int main(int argc, char *argv[])
      |     ^~~~
profiles/ranging/rap.c: In function ‘start_measurement’:
profiles/ranging/rap.c:472:4: error: enumeration value ‘CS_TARGET_SETTINGS’ not handled in switch [-Werror=switch-enum]
  472 |    switch (desc->target) {
      |    ^~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8999: profiles/ranging/bluetoothd-rap.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:10826: check] Error 2
##############################
Test: CheckSmatch - FAIL
Desc: Run smatch tool with source
Output:

src/shared/crypto.c:271:21: warning: Variable length array is used.
src/shared/crypto.c:272: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:1366:23: warning: Variable length array is used.
src/shared/gatt-server.c:271:25: warning: Variable length array is used.
src/shared/gatt-server.c:614:25: warning: Variable length array is used.
src/shared/gatt-server.c:712:25: warning: Variable length array is used.
src/shared/bap.c:318:25: warning: array of flexible structures
src/shared/bap.c: note: in included file:
./src/shared/ascs.h:88:25: warning: array of flexible structures
src/shared/shell.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
src/shared/crypto.c:271:21: warning: Variable length array is used.
src/shared/crypto.c:272: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:1366:23: warning: Variable length array is used.
src/shared/gatt-server.c:271:25: warning: Variable length array is used.
src/shared/gatt-server.c:614:25: warning: Variable length array is used.
src/shared/gatt-server.c:712:25: warning: Variable length array is used.
src/shared/bap.c:318:25: warning: array of flexible structures
src/shared/bap.c: note: in included file:
./src/shared/ascs.h:88:25: warning: array of flexible structures
src/shared/shell.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
tools/mesh-cfgtest.c:1453:17: warning: unknown escape sequence: '\%'
tools/sco-tester.c: note: in included file:
./lib/bluetooth/bluetooth.h:232:15: warning: array of flexible structures
./lib/bluetooth/bluetooth.h:237:31: warning: array of flexible structures
tools/bneptest.c:634:39: warning: unknown escape sequence: '\%'
tools/seq2bseq.c:57:26: warning: Variable length array is used.
tools/obex-client-tool.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
client/btpclient/gatt.c: note: in included file:
./src/shared/btp.h:335:41: warning: array of flexible structures
./src/shared/btp.h:340:55: warning: array of flexible structures
./src/shared/btp.h:363:47: warning: array of flexible structures
./src/shared/btp.h:392:42: warning: array of flexible structures
src/advertising.c: note: in included file:
./src/shared/mgmt.h:95:25: error: redefinition of unsigned int enum mgmt_io_capability
src/agent.c: note: in included file:
src/shared/queue.h:19:20: error: redefinition of struct queue_entry
src/adv_monitor.c: note: in included file:
./src/shared/mgmt.h:95:25: error: redefinition of unsigned int enum mgmt_io_capability
unit/avctp.c:505:34: warning: Variable length array is used.
unit/avctp.c:556:34: warning: Variable length array is used.
unit/test-avrcp.c:373:26: warning: Variable length array is used.
unit/test-avrcp.c:398:26: warning: Variable length array is used.
unit/test-avrcp.c:414:24: warning: Variable length array is used.
unit/avrcp-lib.c:1085:34: warning: Variable length array is used.
unit/avrcp-lib.c:1583:34: warning: Variable length array is used.
unit/avrcp-lib.c:1612:34: warning: Variable length array is used.
unit/avrcp-lib.c:1638:34: warning: Variable length array is used.
src/advertising.c: note: in included file:
./src/shared/mgmt.h:95:25: error: redefinition of unsigned int enum mgmt_io_capability
src/agent.c: note: in included file:
src/shared/queue.h:19:20: error: redefinition of struct queue_entry
src/adv_monitor.c: note: in included file:
./src/shared/mgmt.h:95:25: error: redefinition of unsigned int enum mgmt_io_capability
src/main.c: note: in included file (through src/device.h):
./src/shared/queue.h:19:20: error: redefinition of struct queue_entry
mesh/mesh-io-mgmt.c:525:67: warning: Variable length array is used.
client/display.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
src/shared/crypto.c:271:21: warning: Variable length array is used.
src/shared/crypto.c:272: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-server.c:271:25: warning: Variable length array is used.
src/shared/gatt-helpers.c:1335:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1366:23: warning: Variable length array is used.
src/shared/gatt-server.c:614:25: warning: Variable length array is used.
src/shared/gatt-server.c:712:25: warning: Variable length array is used.
src/shared/bap.c:318:25: warning: array of flexible structures
src/shared/bap.c: note: in included file:
./src/shared/ascs.h:88:25: warning: array of flexible structures
src/shared/shell.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
monitor/packet.c:2002:26: warning: Variable length array is used.
monitor/packet.c: note: in included file:
monitor/bt.h:3924:52: warning: array of flexible structures
monitor/bt.h:3912:40: warning: array of flexible structures
monitor/msft.c: note: in included file:
monitor/msft.h:88:44: warning: array of flexible structures
tools/rctest.c:631:33: warning: non-ANSI function declaration of function 'automated_send_recv'
tools/hex2hcd.c:136:26: warning: Variable length array is used.
tools/meshctl.c:324:33: warning: non-ANSI function declaration of function 'forget_mesh_devices'
tools/mesh-gatt/node.c:456:39: warning: non-ANSI function declaration of function 'node_get_local_node'
tools/mesh-gatt/net.c:1239:30: warning: non-ANSI function declaration of function 'get_next_seq'
tools/mesh-gatt/net.c:2193:29: warning: non-ANSI function declaration of function 'net_get_default_ttl'
tools/mesh-gatt/net.c:2207:26: warning: non-ANSI function declaration of function 'net_get_seq_num'
tools/mesh-gatt/prov.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
tools/mesh-gatt/onoff-model.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
ell/log.c:431:65: warning: non-ANSI function declaration of function 'register_debug_section'
ell/log.c:439:68: warning: non-ANSI function declaration of function 'free_debug_sections'
ell/random.c:60:42: warning: non-ANSI function declaration of function 'l_getrandom_is_supported'
ell/cipher.c:660:28: warning: non-ANSI function declaration of function 'init_supported'
ell/checksum.c:382:28: warning: non-ANSI function declaration of function 'init_supported'
ell/checksum.c:444:47: warning: non-ANSI function declaration of function 'l_checksum_cmac_aes_supported'
ell/cipher.c:519:24: warning: Variable length array is used.
ell/cert-crypto.c:36:33: warning: Variable length array is used.
ell/cert-crypto.c:142:36: warning: Variable length array is used.
ell/cert-crypto.c:198:36: warning: Variable length array is used.
ell/cert-crypto.c:251:31: warning: Variable length array is used.
ell/key.c:550:25: warning: Variable length array is used.
ell/dbus-service.c:548:49: warning: non-ANSI function declaration of function '_dbus_object_tree_new'
ell/dbus-filter.c:233:46: warning: Variable length array is used.
ell/tls.c:45:25: warning: Variable length array is used.
ell/tls.c:86:22: warning: Variable length array is used.
ell/tls.c:86:46: warning: Variable length array is used.
ell/tls-suites.c:1079:25: warning: Variable length array is used.
ell/tls-suites.c:1081:34: warning: Variable length array is used.
ell/tls-suites.c:1084:41: warning: Variable length array is used.
ell/tls-suites.c:1133:41: warning: Variable length array is used.
ell/tls.c:1819:26: warning: Variable length array is used.
emulator/btdev.c:478:29: warning: Variable length array is used.
emulator/bthost.c:703:28: warning: Variable length array is used.
emulator/bthost.c:704:32: warning: Variable length array is used.
emulator/bthost.c:944:28: warning: Variable length array is used.
emulator/bthost.c:978:28: warning: Variable length array is used.
emulator/bthost.c:979:32: warning: Variable length array is used.
attrib/gatttool.c:236:23: warning: Variable length array is used.
attrib/interactive.c: note: in included file (through /usr/include/readline/readline.h):
/usr/include/readline/rltypedefs.h:35:23: warning: non-ANSI function declaration of function 'Function'
/usr/include/readline/rltypedefs.h:36:25: warning: non-ANSI function declaration of function 'VFunction'
/usr/include/readline/rltypedefs.h:37:27: warning: non-ANSI function declaration of function 'CPFunction'
/usr/include/readline/rltypedefs.h:38:29: warning: non-ANSI function declaration of function 'CPPFunction'
attrib/interactive.c:175:27: warning: non-ANSI function declaration of function 'disconnect_io'
attrib/interactive.c:300:23: warning: Variable length array is used.
profiles/ranging/rap.c: In function ‘start_measurement’:
profiles/ranging/rap.c:472:4: error: enumeration value ‘CS_TARGET_SETTINGS’ not handled in switch [-Werror=switch-enum]
  472 |    switch (desc->target) {
      |    ^~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8999: profiles/ranging/bluetoothd-rap.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4175: all] Error 2
##############################
Test: bluezmakeextell - FAIL
Desc: Build Bluez with External ELL
Output:

profiles/ranging/rap.c: In function ‘start_measurement’:
profiles/ranging/rap.c:472:4: error: enumeration value ‘CS_TARGET_SETTINGS’ not handled in switch [-Werror=switch-enum]
  472 |    switch (desc->target) {
      |    ^~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8999: profiles/ranging/bluetoothd-rap.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4175: all] Error 2
##############################
Test: IncrementalBuild - FAIL
Desc: Incremental build with the patches in the series
Output:

profiles/ranging/rap.c: In function ‘start_measurement’:
profiles/ranging/rap.c:472:4: error: enumeration value ‘CS_TARGET_SETTINGS’ not handled in switch [-Werror=switch-enum]
  472 |    switch (desc->target) {
      |    ^~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8994: profiles/ranging/bluetoothd-rap.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4173: all] Error 2
[BlueZ,v2,3/4] profiles: Add D-Bus Channel Sounding control APIs

profiles/ranging/rap.c: In function ‘start_measurement’:
profiles/ranging/rap.c:472:4: error: enumeration value ‘CS_TARGET_SETTINGS’ not handled in switch [-Werror=switch-enum]
  472 |    switch (desc->target) {
      |    ^~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8994: profiles/ranging/bluetoothd-rap.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4173: all] Error 2
##############################
Test: ScanBuild - FAIL
Desc: Run Scan Build
Output:

src/shared/gatt-client.c:447:21: warning: Use of memory after it is freed
        gatt_db_unregister(op->client->db, op->db_id);
                           ^~~~~~~~~~
src/shared/gatt-client.c:692:2: warning: Use of memory after it is freed
        discovery_op_complete(op, false, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:992:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1098:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1292:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1357:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1632:6: warning: Use of memory after it is freed
        if (read_db_hash(op)) {
            ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1637:2: warning: Use of memory after it is freed
        discover_all(op);
        ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1693:56: warning: Use of memory after it is freed
        notify_data->chrc->ccc_write_id = notify_data->att_id = att_id;
                                          ~~~~~~~~~~~~~~~~~~~ ^
src/shared/gatt-client.c:2146:6: warning: Use of memory after it is freed
        if (read_db_hash(op)) {
            ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:2154:8: warning: Use of memory after it is freed
                                                        discovery_op_ref(op),
                                                        ^~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3332:2: warning: Use of memory after it is freed
        complete_write_long_op(req, success, 0, false);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3354:2: warning: Use of memory after it is freed
        request_unref(req);
        ^~~~~~~~~~~~~~~~~~
13 warnings generated.
src/shared/bap.c:1543:8: warning: Use of memory after it is freed
        bap = bt_bap_ref_safe(bap);
              ^~~~~~~~~~~~~~~~~~~~
src/shared/bap.c:2354:20: warning: Use of memory after it is freed
        return queue_find(stream->bap->streams, NULL, stream);
                          ^~~~~~~~~~~~~~~~~~~~
2 warnings generated.
src/shared/gatt-client.c:447:21: warning: Use of memory after it is freed
        gatt_db_unregister(op->client->db, op->db_id);
                           ^~~~~~~~~~
src/shared/gatt-client.c:692:2: warning: Use of memory after it is freed
        discovery_op_complete(op, false, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:992:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1098:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1292:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1357:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1632:6: warning: Use of memory after it is freed
        if (read_db_hash(op)) {
            ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1637:2: warning: Use of memory after it is freed
        discover_all(op);
        ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1693:56: warning: Use of memory after it is freed
        notify_data->chrc->ccc_write_id = notify_data->att_id = att_id;
                                          ~~~~~~~~~~~~~~~~~~~ ^
src/shared/gatt-client.c:2146:6: warning: Use of memory after it is freed
        if (read_db_hash(op)) {
            ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:2154:8: warning: Use of memory after it is freed
                                                        discovery_op_ref(op),
                                                        ^~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3332:2: warning: Use of memory after it is freed
        complete_write_long_op(req, success, 0, false);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3354:2: warning: Use of memory after it is freed
        request_unref(req);
        ^~~~~~~~~~~~~~~~~~
13 warnings generated.
tools/hciattach.c:817:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
        if ((n = read_hci_event(fd, resp, 10)) < 0) {
             ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:865:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
        if ((n = read_hci_event(fd, resp, 4)) < 0) {
             ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:887:8: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
                if ((n = read_hci_event(fd, resp, 10)) < 0) {
                     ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:909:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
        if ((n = read_hci_event(fd, resp, 4)) < 0) {
             ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:930:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
        if ((n = read_hci_event(fd, resp, 4)) < 0) {
             ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/hciattach.c:974:7: warning: Although the value stored to 'n' is used in the enclosing expression, the value is never actually read from 'n'
        if ((n = read_hci_event(fd, resp, 6)) < 0) {
             ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
6 warnings generated.
src/shared/bap.c:1543:8: warning: Use of memory after it is freed
        bap = bt_bap_ref_safe(bap);
              ^~~~~~~~~~~~~~~~~~~~
src/shared/bap.c:2354:20: warning: Use of memory after it is freed
        return queue_find(stream->bap->streams, NULL, stream);
                          ^~~~~~~~~~~~~~~~~~~~
2 warnings generated.
src/oui.c:50:2: warning: Value stored to 'hwdb' is never read
        hwdb = udev_hwdb_unref(hwdb);
        ^      ~~~~~~~~~~~~~~~~~~~~~
src/oui.c:53:2: warning: Value stored to 'udev' is never read
        udev = udev_unref(udev);
        ^      ~~~~~~~~~~~~~~~~
2 warnings generated.
tools/rfcomm.c:234:3: warning: Value stored to 'i' is never read
                i = execvp(cmdargv[0], cmdargv);
                ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/rfcomm.c:234:7: warning: Null pointer passed to 1st parameter expecting 'nonnull'
                i = execvp(cmdargv[0], cmdargv);
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/rfcomm.c:354:8: warning: Although the value stored to 'fd' is used in the enclosing expression, the value is never actually read from 'fd'
                if ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
                     ^    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/rfcomm.c:497:14: warning: Assigned value is garbage or undefined
        req.channel = raddr.rc_channel;
                    ^ ~~~~~~~~~~~~~~~~
tools/rfcomm.c:515:8: warning: Although the value stored to 'fd' is used in the enclosing expression, the value is never actually read from 'fd'
                if ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
                     ^    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 warnings generated.
tools/ciptool.c:351:7: warning: 5th function call argument is an uninitialized value
        sk = do_connect(ctl, dev_id, &src, &dst, psm, (1 << CMTP_LOOPBACK));
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
src/sdp-xml.c:126:10: warning: Assigned value is garbage or undefined
                buf[1] = data[i + 1];
                       ^ ~~~~~~~~~~~
src/sdp-xml.c:306:11: warning: Assigned value is garbage or undefined
                        buf[1] = data[i + 1];
                               ^ ~~~~~~~~~~~
src/sdp-xml.c:344:11: warning: Assigned value is garbage or undefined
                        buf[1] = data[i + 1];
                               ^ ~~~~~~~~~~~
3 warnings generated.
tools/sdptool.c:941:26: warning: Result of 'malloc' is converted to a pointer of type 'uint32_t', which is incompatible with sizeof operand type 'int'
                        uint32_t *value_int = malloc(sizeof(int));
                        ~~~~~~~~~~            ^~~~~~ ~~~~~~~~~~~
tools/sdptool.c:980:4: warning: 1st function call argument is an uninitialized value
                        free(allocArray[i]);
                        ^~~~~~~~~~~~~~~~~~~
tools/sdptool.c:3777:2: warning: Potential leak of memory pointed to by 'si.name'
        return add_service(0, &si);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~
tools/sdptool.c:4112:4: warning: Potential leak of memory pointed to by 'context.svc'
                        return -1;
                        ^~~~~~~~~
4 warnings generated.
tools/avtest.c:243:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 3);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:253:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 4);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:262:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 3);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:276:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf,
                                ^     ~~~~~~~~~~~~~~
tools/avtest.c:283:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf,
                                ^     ~~~~~~~~~~~~~~
tools/avtest.c:290:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf,
                                ^     ~~~~~~~~~~~~~~
tools/avtest.c:297:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf,
                                ^     ~~~~~~~~~~~~~~
tools/avtest.c:309:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 4);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:313:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 2);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:322:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 3);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:326:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 2);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:335:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 3);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:342:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 2);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:364:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 4);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:368:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 2);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:377:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 3);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:381:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 2);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:394:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 4);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:398:5: warning: Value stored to 'len' is never read
                                len = write(sk, buf, 2);
                                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:405:4: warning: Value stored to 'len' is never read
                        len = write(sk, buf, 2);
                        ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:415:4: warning: Value stored to 'len' is never read
                        len = write(sk, buf, 2);
                        ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:580:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 2);
                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:588:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, invalid ? 2 : 3);
                ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/avtest.c:602:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 4 + media_transport_size);
                ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/avtest.c:615:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 3);
                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:625:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 3);
                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:637:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 3);
                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:652:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 3);
                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:664:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 3);
                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:673:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 3);
                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:680:3: warning: Value stored to 'len' is never read
                len = write(sk, buf, 2);
                ^     ~~~~~~~~~~~~~~~~~
tools/avtest.c:716:2: warning: Value stored to 'len' is never read
        len = write(sk, buf, AVCTP_HEADER_LENGTH + sizeof(play_pressed));
        ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32 warnings generated.
tools/btproxy.c:836:15: warning: Null pointer passed to 1st parameter expecting 'nonnull'
                        tcp_port = atoi(optarg);
                                   ^~~~~~~~~~~~
tools/btproxy.c:839:8: warning: Null pointer passed to 1st parameter expecting 'nonnull'
                        if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
                            ^~~~~~~~~~~~~~
2 warnings generated.
tools/create-image.c:76:3: warning: Value stored to 'fd' is never read
                fd = -1;
                ^    ~~
tools/create-image.c:84:3: warning: Value stored to 'fd' is never read
                fd = -1;
                ^    ~~
tools/create-image.c:92:3: warning: Value stored to 'fd' is never read
                fd = -1;
                ^    ~~
tools/create-image.c:105:2: warning: Value stored to 'fd' is never read
        fd = -1;
        ^    ~~
4 warnings generated.
tools/btgatt-server.c:1204:2: warning: Value stored to 'argv' is never read
        argv -= optind;
        ^       ~~~~~~
1 warning generated.
tools/check-selftest.c:42:3: warning: Value stored to 'ptr' is never read
                ptr = fgets(result, sizeof(result), fp);
                ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
tools/btgatt-client.c:1822:2: warning: Value stored to 'argv' is never read
        argv += optind;
        ^       ~~~~~~
1 warning generated.
tools/gatt-service.c:294:2: warning: 2nd function call argument is an uninitialized value
        chr_write(chr, value, len);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
tools/obex-server-tool.c:133:13: warning: Null pointer passed to 1st parameter expecting 'nonnull'
        data->fd = open(name, O_WRONLY | O_CREAT | O_NOCTTY, 0600);
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/obex-server-tool.c:192:13: warning: Null pointer passed to 1st parameter expecting 'nonnull'
        data->fd = open(name, O_RDONLY | O_NOCTTY, 0);
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
tools/test-runner.c:1370:2: warning: Address of stack memory associated with local variable 'kernel_path' is still referred to by the global variable 'kernel_image' upon returning to the caller.  This will be a dangling reference
        return EXIT_SUCCESS;
        ^~~~~~~~~~~~~~~~~~~
1 warning generated.
client/btpclient/btpclientctl.c:402:3: warning: Value stored to 'bit' is never read
                bit = 0;
                ^     ~
client/btpclient/btpclientctl.c:1655:2: warning: Null pointer passed to 2nd parameter expecting 'nonnull'
        memcpy(cp->data, ad_data, ad_len);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
src/sdp-client.c:353:14: warning: Access to field 'cb' results in a dereference of a null pointer
        (*ctxt)->cb = cb;
        ~~~~~~~~~~~~^~~~
1 warning generated.
src/sdpd-request.c:209:13: warning: Result of 'malloc' is converted to a pointer of type 'char', which is incompatible with sizeof operand type 'uint16_t'
                                pElem = malloc(sizeof(uint16_t));
                                        ^~~~~~ ~~~~~~~~~~~~~~~~
src/sdpd-request.c:237:13: warning: Result of 'malloc' is converted to a pointer of type 'char', which is incompatible with sizeof operand type 'uint32_t'
                                pElem = malloc(sizeof(uint32_t));
                                        ^~~~~~ ~~~~~~~~~~~~~~~~
2 warnings generated.
src/gatt-database.c:1171:10: warning: Value stored to 'bits' during its initialization is never read
        uint8_t bits[] = { BT_GATT_CHRC_CLI_FEAT_ROBUST_CACHING,
                ^~~~     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
src/gatt-client.c:1569:2: warning: Use of memory after it is freed
        notify_client_unref(client);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
unit/avrcp-lib.c:1968:3: warning: 1st function call argument is an uninitialized value
                g_free(text[i]);
                ^~~~~~~~~~~~~~~
1 warning generated.
unit/avdtp.c:756:25: warning: Use of memory after it is freed
                session->prio_queue = g_slist_remove(session->prio_queue, req);
                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
unit/avdtp.c:763:24: warning: Use of memory after it is freed
                session->req_queue = g_slist_remove(session->req_queue, req);
                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
unit/test-util.c:33:8: warning: Potential leak of memory pointed to by 'p1'
        p2[0] = 1;
        ~~~~~~^~~
unit/test-util.c:36:3: warning: Potential leak of memory pointed to by 'p2'
                _cleanup_free_ uint8_t *data = NULL;
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/shared/util.h:134:24: note: expanded from macro '_cleanup_free_'
#define _cleanup_free_ _cleanup_(freep)
                       ^
./src/shared/util.h:132:22: note: expanded from macro '_cleanup_'
#define _cleanup_(f) __attribute__((cleanup(f)))
                     ^
unit/test-util.c:42:3: warning: Potential leak of memory pointed to by 'data'
                assert(is_null_too == NULL);
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/assert.h:108:11: note: expanded from macro 'assert'
  ((void) sizeof ((expr) ? 1 : 0), __extension__ ({                     \
          ^~~~~~~~~~~~~~~~~~~~~~~
unit/test-util.c:50:2: warning: Potential leak of memory pointed to by 'data'
        assert(is_null == NULL);
        ^~~~~~~~~~~~~~~~~~~~~~~
/usr/include/assert.h:108:11: note: expanded from macro 'assert'
  ((void) sizeof ((expr) ? 1 : 0), __extension__ ({                     \
          ^~~~~~~~~~~~~~~~~~~~~~~
4 warnings generated.
profiles/audio/avdtp.c:895:25: warning: Use of memory after it is freed
                session->prio_queue = g_slist_remove(session->prio_queue, req);
                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
profiles/audio/avdtp.c:902:24: warning: Use of memory after it is freed
                session->req_queue = g_slist_remove(session->req_queue, req);
                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
profiles/audio/a2dp.c:442:8: warning: Use of memory after it is freed
                if (!cb->resume_cb)
                     ^~~~~~~~~~~~~
profiles/audio/a2dp.c:3354:20: warning: Access to field 'starting' results in a dereference of a null pointer (loaded from variable 'stream')
                stream->starting = TRUE;
                ~~~~~~           ^
profiles/audio/a2dp.c:3357:8: warning: Access to field 'suspending' results in a dereference of a null pointer (loaded from variable 'stream')
                if (!stream->suspending && stream->suspend_timer) {
                     ^~~~~~~~~~~~~~~~~~
profiles/audio/a2dp.c:3417:22: warning: Access to field 'suspending' results in a dereference of a null pointer (loaded from variable 'stream')
                stream->suspending = TRUE;
                ~~~~~~             ^
4 warnings generated.
profiles/audio/avrcp.c:1968:2: warning: Value stored to 'operands' is never read
        operands += sizeof(*pdu);
        ^           ~~~~~~~~~~~~
1 warning generated.
attrib/gatt.c:970:2: warning: Potential leak of memory pointed to by 'long_write'
        return prepare_write(long_write);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
src/sdpd-request.c:209:13: warning: Result of 'malloc' is converted to a pointer of type 'char', which is incompatible with sizeof operand type 'uint16_t'
                                pElem = malloc(sizeof(uint16_t));
                                        ^~~~~~ ~~~~~~~~~~~~~~~~
src/sdpd-request.c:237:13: warning: Result of 'malloc' is converted to a pointer of type 'char', which is incompatible with sizeof operand type 'uint32_t'
                                pElem = malloc(sizeof(uint32_t));
                                        ^~~~~~ ~~~~~~~~~~~~~~~~
2 warnings generated.
src/sdp-client.c:353:14: warning: Access to field 'cb' results in a dereference of a null pointer
        (*ctxt)->cb = cb;
        ~~~~~~~~~~~~^~~~
1 warning generated.
src/sdp-xml.c:126:10: warning: Assigned value is garbage or undefined
                buf[1] = data[i + 1];
                       ^ ~~~~~~~~~~~
src/sdp-xml.c:306:11: warning: Assigned value is garbage or undefined
                        buf[1] = data[i + 1];
                               ^ ~~~~~~~~~~~
src/sdp-xml.c:344:11: warning: Assigned value is garbage or undefined
                        buf[1] = data[i + 1];
                               ^ ~~~~~~~~~~~
3 warnings generated.
src/gatt-database.c:1171:10: warning: Value stored to 'bits' during its initialization is never read
        uint8_t bits[] = { BT_GATT_CHRC_CLI_FEAT_ROBUST_CACHING,
                ^~~~     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
src/gatt-client.c:1569:2: warning: Use of memory after it is freed
        notify_client_unref(client);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
gobex/gobex-header.c:95:2: warning: Null pointer passed to 2nd parameter expecting 'nonnull'
        memcpy(to, from, count);
        ^~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
gobex/gobex-transfer.c:423:7: warning: Use of memory after it is freed
        if (!g_slist_find(transfers, transfer))
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
mesh/main.c:162:3: warning: Value stored to 'optarg' is never read
                optarg += strlen("auto");
                ^         ~~~~~~~~~~~~~~
1 warning generated.
lib/bluetooth/hci.c:93:4: warning: Value stored to 'ptr' is never read
                        ptr += sprintf(ptr, "%s", m->str);
                        ^      ~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
client/player.c:2363:8: warning: Null pointer passed to 2nd parameter expecting 'nonnull'
                if (!strcmp(ep->path, pattern))
                     ^~~~~~~~~~~~~~~~~~~~~~~~~
client/player.c:3640:16: warning: Null pointer passed to 1st parameter expecting 'nonnull'
        codec->name = strdup(name);
                      ^~~~~~~~~~~~
2 warnings generated.
gdbus/watch.c:226:3: warning: Attempt to free released memory
                g_free(l->data);
                ^~~~~~~~~~~~~~~
1 warning generated.
lib/bluetooth/sdp.c:509:17: warning: Dereference of undefined pointer value
                uint8_t dtd = *(uint8_t *) dtds[i];
                              ^~~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:539:17: warning: Dereference of undefined pointer value
                uint8_t dtd = *(uint8_t *) dtds[i];
                              ^~~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:1891:26: warning: Potential leak of memory pointed to by 'ap'
        for (; pdlist; pdlist = pdlist->next) {
                                ^~~~~~
lib/bluetooth/sdp.c:1905:6: warning: Potential leak of memory pointed to by 'pds'
                ap = sdp_list_append(ap, pds);
                ~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:1950:10: warning: Potential leak of memory pointed to by 'u'
                        *seqp = sdp_list_append(*seqp, u);
                        ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:2055:4: warning: Potential leak of memory pointed to by 'lang'
                        sdp_list_free(*langSeq, free);
                        ^~~~~~~~~~~~~
lib/bluetooth/sdp.c:2144:9: warning: Potential leak of memory pointed to by 'profDesc'
        return 0;
               ^
lib/bluetooth/sdp.c:3276:8: warning: Potential leak of memory pointed to by 'pSvcRec'
                pSeq = sdp_list_append(pSeq, pSvcRec);
                ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:3277:9: warning: Potential leak of memory pointed to by 'pSeq'
                pdata += sizeof(uint32_t);
                ~~~~~~^~~~~~~~~~~~~~~~~~~
lib/bluetooth/sdp.c:4613:13: warning: Potential leak of memory pointed to by 'rec_list'
                        } while (scanned < attr_list_len && pdata_len > 0);
                                 ^~~~~~~
lib/bluetooth/sdp.c:4909:40: warning: Potential leak of memory pointed to by 'tseq'
        for (d = sdpdata->val.dataseq; d; d = d->next) {
                                              ^
lib/bluetooth/sdp.c:4945:8: warning: Potential leak of memory pointed to by 'subseq'
                tseq = sdp_list_append(tseq, subseq);
                ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12 warnings generated.
src/shared/gatt-client.c:447:21: warning: Use of memory after it is freed
        gatt_db_unregister(op->client->db, op->db_id);
                           ^~~~~~~~~~
src/shared/gatt-client.c:692:2: warning: Use of memory after it is freed
        discovery_op_complete(op, false, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:992:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1098:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1292:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1357:2: warning: Use of memory after it is freed
        discovery_op_complete(op, success, att_ecode);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1632:6: warning: Use of memory after it is freed
        if (read_db_hash(op)) {
            ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1637:2: warning: Use of memory after it is freed
        discover_all(op);
        ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1693:56: warning: Use of memory after it is freed
        notify_data->chrc->ccc_write_id = notify_data->att_id = att_id;
                                          ~~~~~~~~~~~~~~~~~~~ ^
src/shared/gatt-client.c:2146:6: warning: Use of memory after it is freed
        if (read_db_hash(op)) {
            ^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:2154:8: warning: Use of memory after it is freed
                                                        discovery_op_ref(op),
                                                        ^~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3332:2: warning: Use of memory after it is freed
        complete_write_long_op(req, success, 0, false);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3354:2: warning: Use of memory after it is freed
        request_unref(req);
        ^~~~~~~~~~~~~~~~~~
13 warnings generated.
src/shared/bap.c:1543:8: warning: Use of memory after it is freed
        bap = bt_bap_ref_safe(bap);
              ^~~~~~~~~~~~~~~~~~~~
src/shared/bap.c:2354:20: warning: Use of memory after it is freed
        return queue_find(stream->bap->streams, NULL, stream);
                          ^~~~~~~~~~~~~~~~~~~~
2 warnings generated.
monitor/hwdb.c:59:2: warning: Value stored to 'hwdb' is never read
        hwdb = udev_hwdb_unref(hwdb);
        ^      ~~~~~~~~~~~~~~~~~~~~~
monitor/hwdb.c:64:2: warning: Value stored to 'udev' is never read
        udev = udev_unref(udev);
        ^      ~~~~~~~~~~~~~~~~
monitor/hwdb.c:106:2: warning: Value stored to 'hwdb' is never read
        hwdb = udev_hwdb_unref(hwdb);
        ^      ~~~~~~~~~~~~~~~~~~~~~
monitor/hwdb.c:111:2: warning: Value stored to 'udev' is never read
        udev = udev_unref(udev);
        ^      ~~~~~~~~~~~~~~~~
4 warnings generated.
monitor/l2cap.c:1676:4: warning: Value stored to 'data' is never read
                        data += len;
                        ^       ~~~
monitor/l2cap.c:1677:4: warning: Value stored to 'size' is never read
                        size -= len;
                        ^       ~~~
2 warnings generated.
tools/bluemoon.c:1102:8: warning: Null pointer passed to 1st parameter expecting 'nonnull'
                        if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
                            ^~~~~~~~~~~~~~
1 warning generated.
tools/meshctl.c:326:19: warning: Access to field 'mesh_devices' results in a dereference of a null pointer (loaded from variable 'default_ctrl')
        g_list_free_full(default_ctrl->mesh_devices, g_free);
                         ^~~~~~~~~~~~~~~~~~~~~~~~~~
tools/meshctl.c:762:2: warning: 2nd function call argument is an uninitialized value
        bt_shell_printf("Attempting to disconnect from %s\n", addr);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tools/meshctl.c:1957:2: warning: Value stored to 'len' is never read
        len = len + extra + strlen("local_node.json");
        ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 warnings generated.
In file included from tools/mesh-gatt/crypto.c:32:
./src/shared/util.h:291:9: warning: 1st function call argument is an uninitialized value
        return be32_to_cpu(get_unaligned((const uint32_t *) ptr));
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/shared/util.h:41:26: note: expanded from macro 'be32_to_cpu'
#define be32_to_cpu(val) bswap_32(val)
                         ^~~~~~~~~~~~~
/usr/include/byteswap.h:34:21: note: expanded from macro 'bswap_32'
#define bswap_32(x) __bswap_32 (x)
                    ^~~~~~~~~~~~~~
In file included from tools/mesh-gatt/crypto.c:32:
./src/shared/util.h:301:9: warning: 1st function call argument is an uninitialized value
        return be64_to_cpu(get_unaligned((const uint64_t *) ptr));
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./src/shared/util.h:42:26: note: expanded from macro 'be64_to_cpu'
#define be64_to_cpu(val) bswap_64(val)
                         ^~~~~~~~~~~~~
/usr/include/byteswap.h:37:21: note: expanded from macro 'bswap_64'
#define bswap_64(x) __bswap_64 (x)
                    ^~~~~~~~~~~~~~
2 warnings generated.
ell/util.c:853:8: warning: The left operand of '>' is a garbage value
        if (x > UINT8_MAX)
            ~ ^
ell/util.c:871:8: warning: The left operand of '>' is a garbage value
        if (x > UINT16_MAX)
            ~ ^
2 warnings generated.
ell/pem.c:131:8: warning: Dereference of null pointer (loaded from variable 'eol')
                        if (*eol == '\r' || *eol == '\n')
                            ^~~~
ell/pem.c:166:18: warning: Dereference of null pointer (loaded from variable 'eol')
                if (buf_len && *eol == '\r' && *buf_ptr == '\n') {
                               ^~~~
ell/pem.c:166:34: warning: Dereference of null pointer (loaded from variable 'buf_ptr')
                if (buf_len && *eol == '\r' && *buf_ptr == '\n') {
                                               ^~~~~~~~
ell/pem.c:304:11: warning: 1st function call argument is an uninitialized value
        result = pem_load_buffer(file.data, file.st.st_size,
                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ell/pem.c:469:9: warning: 1st function call argument is an uninitialized value
        list = l_pem_load_certificate_list_from_data(file.data,
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 warnings generated.
ell/cert.c:645:41: warning: Access to field 'asn1_len' results in a dereference of a null pointer (loaded from variable 'cert')
        key = l_key_new(L_KEY_RSA, cert->asn1, cert->asn1_len);
                                               ^~~~~~~~~~~~~~
1 warning generated.
ell/gvariant-util.c:143:18: warning: The left operand of '>' is a garbage value
                        if (alignment > max_alignment)
                            ~~~~~~~~~ ^
ell/gvariant-util.c:456:5: warning: Dereference of null pointer
                        !children[0].fixed_size) {
                         ^~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
emulator/serial.c:150:2: warning: Assigned value is garbage or undefined
        enum btdev_type uninitialized_var(type);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
emulator/serial.c:150:36: warning: Value stored to 'type' during its initialization is never read
        enum btdev_type uninitialized_var(type);
                                          ^~~~
emulator/serial.c:36:30: note: expanded from macro 'uninitialized_var'
#define uninitialized_var(x) x = x
                             ^   ~
emulator/serial.c:213:2: warning: Assigned value is garbage or undefined
        enum btdev_type uninitialized_var(dev_type);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
emulator/serial.c:213:36: warning: Value stored to 'dev_type' during its initialization is never read
        enum btdev_type uninitialized_var(dev_type);
                                          ^~~~~~~~
emulator/serial.c:36:30: note: expanded from macro 'uninitialized_var'
#define uninitialized_var(x) x = x
                             ^   ~
4 warnings generated.
ell/ecc-external.c:77:11: warning: Assigned value is garbage or undefined
                dest[i] = src[i];
                        ^ ~~~~~~
ell/ecc-external.c:160:18: warning: The right operand of '-' is a garbage value
                diff = left[i] - right[i] - borrow;
                               ^ ~~~~~~~~
ell/ecc-external.c:227:14: warning: 2nd function call argument is an uninitialized value
                        product = mul_64_64(left[i], right[k - i]);
                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ell/ecc-external.c:408:9: warning: Assigned value is garbage or undefined
        tmp[1] = product[3];
               ^ ~~~~~~~~~~
ell/ecc-external.c:435:22: warning: The left operand of '&' is a garbage value
        tmp[1] = product[3] & 0xffffffff00000000ull;
                 ~~~~~~~~~~ ^
ell/ecc-external.c:483:22: warning: The left operand of '&' is a garbage value
        tmp[1] = product[5] & 0xffffffff00000000ull;
                 ~~~~~~~~~~ ^
ell/ecc-external.c:688:28: warning: The left operand of '>>' is a garbage value
                tmp[i] = (product[8 + i] >> 9) | (product[9 + i] << 55);
                          ~~~~~~~~~~~~~~ ^
7 warnings generated.
emulator/server.c:230:2: warning: Assigned value is garbage or undefined
        enum btdev_type uninitialized_var(type);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
emulator/server.c:230:36: warning: Value stored to 'type' during its initialization is never read
        enum btdev_type uninitialized_var(type);
                                          ^~~~
emulator/server.c:36:30: note: expanded from macro 'uninitialized_var'
#define uninitialized_var(x) x = x
                             ^   ~
2 warnings generated.
emulator/b1ee.c:258:3: warning: Potential leak of memory pointed to by 'server_port'
                int opt;
                ^~~~~~~
emulator/b1ee.c:258:3: warning: Potential leak of memory pointed to by 'sniffer_port'
                int opt;
                ^~~~~~~
emulator/b1ee.c:289:2: warning: Value stored to 'argc' is never read
        argc = argc - optind;
        ^      ~~~~~~~~~~~~~
3 warnings generated.
gobex/gobex-header.c:95:2: warning: Null pointer passed to 2nd parameter expecting 'nonnull'
        memcpy(to, from, count);
        ^~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
gobex/gobex-transfer.c:423:7: warning: Use of memory after it is freed
        if (!g_slist_find(transfers, transfer))
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
attrib/gatt.c:970:2: warning: Potential leak of memory pointed to by 'long_write'
        return prepare_write(long_write);
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
emulator/btdev.c:6662:20: warning: Access to field 'link' results in a dereference of a null pointer (loaded from variable 'acl')
                le_past_received(acl->link, pa);
                                 ^~~~~~~~~
emulator/btdev.c:6762:25: warning: Access to field 'link' results in a dereference of a null pointer (loaded from variable 'acl')
                le_past_info_received(acl->link, ea);
                                      ^~~~~~~~~
2 warnings generated.
profiles/ranging/rap.c: In function ‘start_measurement’:
profiles/ranging/rap.c:472:4: error: enumeration value ‘CS_TARGET_SETTINGS’ not handled in switch [-Werror=switch-enum]
  472 |    switch (desc->target) {
      |    ^~~~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:8994: profiles/ranging/bluetoothd-rap.o] Error 1
make[1]: *** Waiting for unfinished jobs....
profiles/audio/media.c:1117:7: warning: Use of memory after it is freed
                if (req->cb != pac_select_cb) {
                    ^~~~~~~
1 warning generated.
make: *** [Makefile:4173: all] Error 2


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

---
Regards,
Linux Bluetooth


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

* [PATCH BlueZ v3 0/4] Add Channel Sounding Dbus support and
@ 2026-07-12 12:17 Naga Bhavani Akella
  2026-07-12 12:17 ` [PATCH BlueZ v3 1/4] rap: Add Channel Sounding parameter types and APIs Naga Bhavani Akella
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Naga Bhavani Akella @ 2026-07-12 12:17 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
	Naga Bhavani Akella

This series adds user-facing control and configuration support for
Bluetooth LE Channel Sounding (CS) through a new DBus interface and
bluetoothctl integration.

The RAP profile is extended to expose an
org.bluez.ChannelSounding1 interface, allowing external applications
to configure default Channel Sounding settings and start or stop
measurement procedures. CS configuration, frequency, and default
settings are moved from hardcoded values into shared parameter
structures and accessor APIs, enabling runtime configuration from the
DBus layer.

To make the new functionality accessible from the command line,
bluetoothctl adds a dedicated "cs" submenu for configuring parameters,
starting and stopping measurements, and monitoring active sessions.

The series also ensures the Channel Sounding interface is available on
reflector devices by registering relevant GATT profiles even when GATT
client discovery is skipped

Changes in v3:
- Add an explicit case CS_TARGET_SETTINGS to satisfy the condition

Changes in v2:
- Add patches 3-4 to support channel sounding dbus implementation


Naga Bhavani Akella (4):
  rap: Add Channel Sounding parameter types and APIs
  src: Register GATT profiles for Channel Sounding reflector
  profiles: Add D-Bus Channel Sounding control APIs
  client: Add Channel Sounding shell submenu

 Makefile.am                |    2 +-
 Makefile.tools             |    3 +-
 client/cs.c                | 1157 ++++++++++++++++++++++++++++++++++++
 client/cs.h                |   18 +
 client/main.c              |   27 +-
 profiles/ranging/rap.c     |  350 ++++++++++-
 profiles/ranging/rap_hci.c |  531 +++++++++++------
 src/device.c               |   28 +-
 src/shared/cs-types.h      |   50 ++
 src/shared/rap.h           |   27 +-
 10 files changed, 2003 insertions(+), 190 deletions(-)
 create mode 100644 client/cs.c
 create mode 100644 client/cs.h
 create mode 100644 src/shared/cs-types.h

-- 

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

* [PATCH BlueZ v3 1/4] rap: Add Channel Sounding parameter types and APIs
  2026-07-12 12:17 [PATCH BlueZ v3 0/4] Add Channel Sounding Dbus support and Naga Bhavani Akella
@ 2026-07-12 12:17 ` Naga Bhavani Akella
  2026-07-12 13:24   ` Add Channel Sounding Dbus support and bluez.test.bot
  2026-07-12 12:17 ` [PATCH BlueZ v3 2/4] src: Register GATT profiles for Channel Sounding reflector Naga Bhavani Akella
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 7+ messages in thread
From: Naga Bhavani Akella @ 2026-07-12 12:17 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
	Naga Bhavani Akella

Add shared Channel Sounding parameter structures
(bt_rap_le_cs_config, bt_rap_le_cs_frequency and
bt_rap_le_cs_default_settings) for exchanging
CS configuration, frequency, and default settings
between the RAP DBus layer and HCI state machine.

Add getter/setter APIs for CS config, frequency
and default settings, add measurement.
---
 Makefile.am           |  2 +-
 src/shared/cs-types.h | 50 +++++++++++++++++++++++++++++++++++++++++++
 src/shared/rap.h      | 27 ++++++++++++++++++++++-
 3 files changed, 77 insertions(+), 2 deletions(-)
 create mode 100644 src/shared/cs-types.h

diff --git a/Makefile.am b/Makefile.am
index 76c4ab5d4..a7b063c6e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -249,7 +249,7 @@ shared_sources = src/shared/io.h src/shared/timeout.h \
 			src/shared/asha.h src/shared/asha.c \
 			src/shared/battery.h src/shared/battery.c \
 			src/shared/uinput.h src/shared/uinput.c \
-			src/shared/rap.h src/shared/rap.c
+			src/shared/rap.h src/shared/rap.c src/shared/cs-types.h
 
 
 if READLINE
diff --git a/src/shared/cs-types.h b/src/shared/cs-types.h
new file mode 100644
index 000000000..0d53d4ab8
--- /dev/null
+++ b/src/shared/cs-types.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+struct bt_rap_le_cs_config {
+	uint8_t config_id;
+	uint8_t main_mode_type;
+	uint8_t sub_mode_type;
+	uint8_t main_mode_min_steps;
+	uint8_t main_mode_max_steps;
+	uint8_t main_mode_repetition;
+	uint8_t mode0_steps;
+	uint8_t role;
+	uint8_t rtt_types;
+	uint8_t cs_sync_phy;
+	uint8_t channel_map[10];
+	uint8_t channel_map_repetition;
+	uint8_t channel_selection_type;
+	uint8_t channel_shape;
+	uint8_t channel_jump;
+	uint8_t companion_signal_enable;
+};
+
+struct bt_rap_le_cs_frequency {
+	uint16_t max_procedure_duration;
+	uint16_t min_period_between_procedures;
+	uint16_t max_period_between_procedures;
+	uint16_t max_procedure_count;
+	uint8_t  min_sub_event_len[3];
+	uint8_t  max_sub_event_len[3];
+	uint8_t  tone_antenna_config_selection;
+	uint8_t  phy;
+	uint8_t  tx_power_delta;
+	uint8_t  preferred_peer_antenna;
+	uint8_t  snr_control_initiator;
+	uint8_t  snr_control_reflector;
+};
+
+struct bt_rap_le_cs_default_settings {
+	uint8_t role;
+	uint8_t cs_sync_ant_sel;
+	int8_t  max_tx_power;
+};
diff --git a/src/shared/rap.h b/src/shared/rap.h
index 7bc49f03d..5582635e6 100644
--- a/src/shared/rap.h
+++ b/src/shared/rap.h
@@ -9,8 +9,8 @@
 #include <inttypes.h>
 
 #include "src/shared/io.h"
-#include "bluetooth/mgmt.h"
 #include "src/shared/hci.h"
+#include "src/shared/cs-types.h"
 
 struct bt_rap;
 struct gatt_db;
@@ -189,6 +189,23 @@ bool bt_rap_unregister(unsigned int id);
 
 struct bt_rap *bt_rap_new(struct gatt_db *ldb, struct gatt_db *rdb);
 
+bool bt_rap_set_cs_config_params(void *hci_sm,
+				const struct bt_rap_le_cs_config *config);
+bool bt_rap_set_cs_freq_params(void *hci_sm,
+				const struct bt_rap_le_cs_frequency *frequency);
+bool bt_rap_set_default_settings_params(void *hci_sm,
+				const struct bt_rap_le_cs_default_settings *s);
+bool bt_rap_get_cs_config_params(void *hci_sm,
+				struct bt_rap_le_cs_config *config);
+bool bt_rap_get_cs_freq_params(void *hci_sm,
+				struct bt_rap_le_cs_frequency *frequency);
+bool bt_rap_get_default_settings_params(void *hci_sm,
+				struct bt_rap_le_cs_default_settings *s);
+/* Distance measurement control */
+bool bt_rap_start_measurement(void *hci_sm, uint16_t conn_handle,
+				uint32_t duration_secs);
+bool bt_rap_stop_measurement(void *hci_sm);
+
 /* HCI Raw Channel Approach */
 void bt_rap_hci_cs_config_complete_callback(uint16_t length,
 					     const void *param,
@@ -220,3 +237,11 @@ bool bt_rap_set_conn_hndl(void *hci_sm,
 			bool is_central);
 
 void bt_rap_clear_conn_handle(void *hci_sm, uint16_t handle);
+
+bool bt_rap_is_procedure_active(void *hci_sm);
+
+void bt_rap_set_timeout_cb(void *hci_sm, void (*func)(void *),
+				void *user_data);
+
+void bt_rap_set_proc_active_cb(void *hci_sm, void (*func)(bool, void *),
+				void *user_data);
-- 


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

* [PATCH BlueZ v3 2/4] src: Register GATT profiles for Channel Sounding reflector
  2026-07-12 12:17 [PATCH BlueZ v3 0/4] Add Channel Sounding Dbus support and Naga Bhavani Akella
  2026-07-12 12:17 ` [PATCH BlueZ v3 1/4] rap: Add Channel Sounding parameter types and APIs Naga Bhavani Akella
@ 2026-07-12 12:17 ` Naga Bhavani Akella
  2026-07-12 12:17 ` [PATCH BlueZ v3 3/4] profiles: Add D-Bus Channel Sounding control APIs Naga Bhavani Akella
  2026-07-12 12:17 ` [PATCH BlueZ v3 4/4] client: Add Channel Sounding shell submenu Naga Bhavani Akella
  3 siblings, 0 replies; 7+ messages in thread
From: Naga Bhavani Akella @ 2026-07-12 12:17 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
	Naga Bhavani Akella

Probe and accept GATT_UUID profiles on non-initiator (reflector)
devices before gatt_client discovery checks,
ensuring RAP's org.bluez.ChannelSounding1 DBus interface is registered
even when GATT client discovery is skipped.
---
 src/device.c | 28 +++++++++++++++++++++-------
 1 file changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/device.c b/src/device.c
index 65d84be56..cedfe3a20 100644
--- a/src/device.c
+++ b/src/device.c
@@ -6301,17 +6301,31 @@ static void gatt_debug(const char *str, void *user_data)
 static void gatt_client_init(struct btd_device *device)
 {
 	uint8_t features;
+	GSList *uuid_list;
 
 	gatt_client_cleanup(device);
 
-	if (!btd_device_is_initiator(device) && !btd_opts.reverse_discovery) {
-		DBG("Reverse service discovery disabled: skipping GATT client");
-		return;
-	}
+	if (!btd_device_is_initiator(device)) {
+		/*
+		 * For the reflector role GATT client discovery is skipped, but
+		 * profiles that match GATT_UUID still need to be probed and
+		 * accepted so they can register their D-Bus interfaces (e.g.
+		 * org.bluez.ChannelSounding1).
+		 */
+		uuid_list = g_slist_append(NULL, (char *)GATT_UUID);
+		device_probe_profiles(device, uuid_list);
+		g_slist_free(uuid_list);
+		device_accept_gatt_profiles(device);
 
-	if (!btd_device_is_initiator(device) && !btd_opts.gatt_client) {
-		DBG("GATT client disabled: skipping GATT client");
-		return;
+		if (!btd_opts.reverse_discovery) {
+			DBG("Reverse srvc disc disabled: skip GATT client");
+			return;
+		}
+
+		if (!btd_opts.gatt_client) {
+			DBG("GATT client disabled: skipping GATT client");
+			return;
+		}
 	}
 
 	features =  BT_GATT_CHRC_CLI_FEAT_ROBUST_CACHING
-- 


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

* [PATCH BlueZ v3 3/4] profiles: Add D-Bus Channel Sounding control APIs
  2026-07-12 12:17 [PATCH BlueZ v3 0/4] Add Channel Sounding Dbus support and Naga Bhavani Akella
  2026-07-12 12:17 ` [PATCH BlueZ v3 1/4] rap: Add Channel Sounding parameter types and APIs Naga Bhavani Akella
  2026-07-12 12:17 ` [PATCH BlueZ v3 2/4] src: Register GATT profiles for Channel Sounding reflector Naga Bhavani Akella
@ 2026-07-12 12:17 ` Naga Bhavani Akella
  2026-07-12 12:17 ` [PATCH BlueZ v3 4/4] client: Add Channel Sounding shell submenu Naga Bhavani Akella
  3 siblings, 0 replies; 7+ messages in thread
From: Naga Bhavani Akella @ 2026-07-12 12:17 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
	Naga Bhavani Akella

Expose org.bluez.ChannelSounding1 on the device path,
adding SetDefaultSettings, StartMeasurement, and StopMeasurement methods
and an Active property to let external clients configure and
control CS ranging sessions.

Replace hardcoded CS configuration values with configurable HCI accessors
(bt_rap_{get,set}_cs_config_params, bt_rap_{get,set}_cs_freq_params,
bt_rap_{get,set}_default_settings_params).
Add measurement control APIs (bt_rap_start_measurement,
bt_rap_stop_measurement) with optional timeout-based auto-stop
and callbacks for timeout and procedure-state changes,
allowing DBus Active state to reflect actual controller procedure status.
---
 profiles/ranging/rap.c     | 350 +++++++++++++++++++++++-
 profiles/ranging/rap_hci.c | 531 +++++++++++++++++++++++++------------
 2 files changed, 702 insertions(+), 179 deletions(-)

diff --git a/profiles/ranging/rap.c b/profiles/ranging/rap.c
index fa3e27328..3ffc0da76 100644
--- a/profiles/ranging/rap.c
+++ b/profiles/ranging/rap.c
@@ -10,6 +10,7 @@
 #endif
 
 #include <stdbool.h>
+#include <stddef.h>
 #include <errno.h>
 
 #include <glib.h>
@@ -35,7 +36,11 @@
 #include "src/shared/rap.h"
 #include "attrib/att.h"
 #include "src/log.h"
+#include "src/shared/cs-types.h"
 #include "src/btd.h"
+#include "src/dbus-common.h"
+
+#define CS_INTERFACE "org.bluez.ChannelSounding1"
 
 struct rap_adapter_data {
 	struct btd_adapter *adapter;
@@ -43,6 +48,14 @@ struct rap_adapter_data {
 	int ref_count;  /* Number of devices using this adapter */
 };
 
+struct cs_session {
+	bool active;
+	uint32_t duration_secs;
+	struct bt_rap_le_cs_default_settings settings;
+	struct bt_rap_le_cs_config    cfg;
+	struct bt_rap_le_cs_frequency freq;
+};
+
 struct rap_data {
 	struct btd_device *device;
 	struct btd_service *service;
@@ -50,6 +63,8 @@ struct rap_data {
 	unsigned int ready_id;
 	struct rap_adapter_data *adapter_data;  /* Shared adapter-level HCI */
 	void *hci_sm;  /* Per-device HCI state machine */
+	uint16_t conn_handle;  /* Last known connection handle */
+	struct cs_session active_session;  /* active==false when idle */
 };
 
 static struct queue *sessions;
@@ -293,6 +308,306 @@ static void rap_attached(struct bt_rap *rap, void *user_data)
 	rap_data_add(data);
 }
 
+enum cs_dict_target {
+	CS_TARGET_SETTINGS,
+	CS_TARGET_CFG,
+	CS_TARGET_FREQ,
+};
+
+struct cs_dict_param_desc {
+	const char *key;
+	enum cs_dict_target target;
+	int vtype;
+	size_t offset;
+};
+
+#define CS_SETTINGS_FIELD(_key, _field) \
+	{ _key, CS_TARGET_SETTINGS, DBUS_TYPE_BYTE, \
+		offsetof(struct bt_rap_le_cs_default_settings, _field) }
+#define CS_CFG_FIELD(_key, _field) \
+	{ _key, CS_TARGET_CFG, DBUS_TYPE_BYTE, \
+		offsetof(struct bt_rap_le_cs_config, _field) }
+#define CS_FREQ_U8_FIELD(_key, _field) \
+	{ _key, CS_TARGET_FREQ, DBUS_TYPE_BYTE, \
+		offsetof(struct bt_rap_le_cs_frequency, _field) }
+#define CS_FREQ_U16_FIELD(_key, _field) \
+	{ _key, CS_TARGET_FREQ, DBUS_TYPE_UINT16, \
+		offsetof(struct bt_rap_le_cs_frequency, _field) }
+
+static const struct cs_dict_param_desc cs_dict_param_table[] = {
+	CS_SETTINGS_FIELD("role", role),
+	CS_SETTINGS_FIELD("sync_ant_sel", cs_sync_ant_sel),
+	CS_CFG_FIELD("config_id", config_id),
+	CS_CFG_FIELD("main_mode_type", main_mode_type),
+	CS_CFG_FIELD("sub_mode_type", sub_mode_type),
+	CS_CFG_FIELD("main_mode_min_steps", main_mode_min_steps),
+	CS_CFG_FIELD("main_mode_max_steps", main_mode_max_steps),
+	CS_CFG_FIELD("main_mode_repetition", main_mode_repetition),
+	CS_CFG_FIELD("mode0_steps", mode0_steps),
+	CS_CFG_FIELD("rtt_types", rtt_types),
+	CS_CFG_FIELD("sync_phy", cs_sync_phy),
+	CS_CFG_FIELD("channel_map_repetition", channel_map_repetition),
+	CS_CFG_FIELD("channel_selection_type", channel_selection_type),
+	CS_CFG_FIELD("channel_shape", channel_shape),
+	CS_CFG_FIELD("channel_jump", channel_jump),
+	CS_CFG_FIELD("companion_signal_enable", companion_signal_enable),
+	CS_FREQ_U16_FIELD("max_procedure_duration", max_procedure_duration),
+	CS_FREQ_U16_FIELD("min_period_between_procedures",
+				min_period_between_procedures),
+	CS_FREQ_U16_FIELD("max_period_between_procedures",
+				max_period_between_procedures),
+	CS_FREQ_U16_FIELD("max_procedure_count", max_procedure_count),
+	CS_FREQ_U8_FIELD("tone_antenna_config_selection",
+				tone_antenna_config_selection),
+	CS_FREQ_U8_FIELD("phy", phy),
+	CS_FREQ_U8_FIELD("tx_power_delta", tx_power_delta),
+	CS_FREQ_U8_FIELD("preferred_peer_antenna", preferred_peer_antenna),
+	CS_FREQ_U8_FIELD("snr_control_initiator", snr_control_initiator),
+	CS_FREQ_U8_FIELD("snr_control_reflector", snr_control_reflector),
+};
+
+static const struct cs_dict_param_desc *cs_find_dict_param_desc(
+							const char *key)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(cs_dict_param_table); i++) {
+		if (!strcmp(cs_dict_param_table[i].key, key))
+			return &cs_dict_param_table[i];
+	}
+
+	return NULL;
+}
+
+static DBusMessage *start_measurement(DBusConnection *conn,
+				DBusMessage *msg, void *user_data)
+{
+	struct rap_data *data = user_data;
+	struct bt_rap_le_cs_config cfg = { 0 };
+	struct bt_rap_le_cs_frequency freq = { 0 };
+	struct bt_rap_le_cs_default_settings settings = { 0 };
+	uint32_t duration_secs = 0;
+	DBusMessageIter iter = { 0 }, dict = { 0 };
+	DBusMessageIter entry = { 0 }, variant = { 0 };
+	const char *key = NULL;
+	int vtype = 0;
+	const struct cs_dict_param_desc *desc = NULL;
+	void *base = NULL;
+
+	if (data->active_session.active)
+		return g_dbus_create_error(msg,
+					"org.bluez.Error.InProgress",
+					"Measurement already active");
+
+	/* Seed locals from current state-machine defaults */
+	bt_rap_get_cs_config_params(data->hci_sm, &cfg);
+	bt_rap_get_cs_freq_params(data->hci_sm, &freq);
+	bt_rap_get_default_settings_params(data->hci_sm, &settings);
+
+	dbus_message_iter_init(msg, &iter);
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+		return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
+					   "Expected a{sv} dictionary");
+
+	dbus_message_iter_recurse(&iter, &dict);
+
+	while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+		dbus_message_iter_recurse(&dict, &entry);
+		dbus_message_iter_get_basic(&entry, &key);
+		dbus_message_iter_next(&entry);
+		dbus_message_iter_recurse(&entry, &variant);
+		vtype = dbus_message_iter_get_arg_type(&variant);
+
+		if (strcmp(key, "duration_secs") == 0) {
+			if (vtype != DBUS_TYPE_UINT32)
+				goto bad_type;
+			dbus_message_iter_get_basic(&variant, &duration_secs);
+		} else if (strcmp(key, "max_tx_power") == 0) {
+			uint8_t bval = 0;
+
+			if (vtype != DBUS_TYPE_BYTE)
+				goto bad_type;
+			dbus_message_iter_get_basic(&variant, &bval);
+			settings.max_tx_power = (int8_t)bval;
+		} else if (strcmp(key, "channel_map") == 0) {
+			DBusMessageIter array = { 0 };
+			uint8_t *bytes = NULL;
+			int len = 0;
+
+			if (vtype != DBUS_TYPE_ARRAY)
+				goto bad_type;
+			dbus_message_iter_recurse(&variant, &array);
+			dbus_message_iter_get_fixed_array(&array, &bytes, &len);
+			if (len != 10)
+				return g_dbus_create_error(msg,
+						DBUS_ERROR_INVALID_ARGS,
+						"channel_map must be 10 bytes");
+			memcpy(cfg.channel_map, bytes, 10);
+		} else if (strcmp(key, "min_sub_event_len") == 0 ||
+			   strcmp(key, "max_sub_event_len") == 0) {
+			DBusMessageIter array = { 0 };
+			uint8_t *bytes = NULL;
+			int len = 0;
+
+			if (vtype != DBUS_TYPE_ARRAY)
+				goto bad_type;
+			dbus_message_iter_recurse(&variant, &array);
+			dbus_message_iter_get_fixed_array(&array, &bytes, &len);
+			if (len != 3)
+				return g_dbus_create_error(msg,
+						DBUS_ERROR_INVALID_ARGS,
+						"sub_event_len must be 3 bytes");
+			if (strcmp(key, "min_sub_event_len") == 0)
+				memcpy(freq.min_sub_event_len, bytes, 3);
+			else
+				memcpy(freq.max_sub_event_len, bytes, 3);
+		} else {
+			desc = cs_find_dict_param_desc(key);
+			if (!desc)
+				goto bad_type;
+
+			if (vtype != desc->vtype)
+				goto bad_type;
+
+			switch (desc->target) {
+			case CS_TARGET_CFG:
+				base = &cfg;
+				break;
+			case CS_TARGET_FREQ:
+				base = &freq;
+				break;
+			case CS_TARGET_SETTINGS:
+				base = &settings;
+				break;
+			default:
+				base = &settings;
+				break;
+			}
+
+			if (desc->vtype == DBUS_TYPE_UINT16)
+				dbus_message_iter_get_basic(&variant,
+					(uint16_t *)((uint8_t *)base +
+								desc->offset));
+			else
+				dbus_message_iter_get_basic(&variant,
+					(uint8_t *)base + desc->offset);
+		}
+
+		dbus_message_iter_next(&dict);
+		continue;
+bad_type:
+		return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
+					   "Unexpected variant type for key");
+	}
+
+	if (data->conn_handle == 0)
+		return g_dbus_create_error(msg, DBUS_ERROR_INVALID_ARGS,
+					   "Device not connected");
+
+	if (!bt_rap_set_default_settings_params(data->hci_sm, &settings))
+		return g_dbus_create_error(msg, DBUS_ERROR_FAILED,
+					   "Set default settings failed");
+
+	if (!bt_rap_set_cs_config_params(data->hci_sm, &cfg))
+		return g_dbus_create_error(msg, DBUS_ERROR_FAILED,
+					   "Set CS config params failed");
+
+	if (!bt_rap_set_cs_freq_params(data->hci_sm, &freq))
+		return g_dbus_create_error(msg, DBUS_ERROR_FAILED,
+					   "Set CS freq params failed");
+
+	/* Reflector never initiates a CS procedure locally: apply the
+	 * settings so the controller is ready to respond to the remote
+	 * Initiator, but do not arm a local measurement session.
+	 */
+	if (settings.role == 0x02)
+		return dbus_message_new_method_return(msg);
+
+	if (!bt_rap_start_measurement(data->hci_sm, data->conn_handle,
+							duration_secs))
+		return g_dbus_create_error(msg, DBUS_ERROR_FAILED,
+					   "Start measurement failed");
+
+	data->active_session.active        = true;
+	data->active_session.duration_secs = duration_secs;
+	data->active_session.settings      = settings;
+	data->active_session.cfg           = cfg;
+	data->active_session.freq          = freq;
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *stop_measurement(DBusConnection *conn,
+				DBusMessage *msg, void *user_data)
+{
+	struct rap_data *data = user_data;
+
+	if (!data->active_session.active)
+		return g_dbus_create_error(msg,
+					"org.bluez.Error.NotConnected",
+					"No active measurement");
+
+	if (!bt_rap_stop_measurement(data->hci_sm))
+		return g_dbus_create_error(msg, DBUS_ERROR_FAILED,
+					"Stop measurement failed");
+
+	memset(&data->active_session, 0, sizeof(data->active_session));
+
+	g_dbus_emit_property_changed(btd_get_dbus_connection(),
+				device_get_path(data->device),
+				CS_INTERFACE, "Active");
+
+	return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable cs_dbus_methods[] = {
+	{ GDBUS_METHOD("StartMeasurement",
+			GDBUS_ARGS({ "params", "a{sv}" }),
+			NULL,
+			start_measurement) },
+	{ GDBUS_METHOD("StopMeasurement",
+			NULL,
+			NULL,
+			stop_measurement) },
+	{ }
+};
+
+static gboolean cs_property_get_active(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *user_data)
+{
+	struct rap_data *data = user_data;
+	dbus_bool_t active = data->active_session.active ||
+				bt_rap_is_procedure_active(data->hci_sm);
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &active);
+	return TRUE;
+}
+
+static const GDBusPropertyTable cs_dbus_properties[] = {
+	{ "Active", "b", cs_property_get_active, NULL, NULL, 0 },
+	{ }
+};
+
+static void rap_measurement_timeout_cb(void *user_data)
+{
+	struct rap_data *data = user_data;
+
+	memset(&data->active_session, 0, sizeof(data->active_session));
+
+	g_dbus_emit_property_changed(btd_get_dbus_connection(),
+				device_get_path(data->device),
+				CS_INTERFACE, "Active");
+}
+
+static void rap_proc_active_changed(bool active, void *user_data)
+{
+	struct rap_data *data = user_data;
+
+	g_dbus_emit_property_changed(btd_get_dbus_connection(),
+				device_get_path(data->device),
+				CS_INTERFACE, "Active");
+}
+
 static int rap_probe(struct btd_service *service)
 {
 	struct btd_device *device = btd_service_get_device(service);
@@ -347,6 +662,10 @@ static void rap_remove(struct btd_service *service)
 		return;
 	}
 
+	g_dbus_unregister_interface(btd_get_dbus_connection(),
+				    device_get_path(device),
+				    CS_INTERFACE);
+
 	rap_data_remove(data);
 }
 
@@ -395,6 +714,11 @@ static int rap_accept(struct btd_service *service)
 			return -EINVAL;
 		}
 		DBG("HCI state machine attached successfully for device");
+
+		bt_rap_set_timeout_cb(data->hci_sm, rap_measurement_timeout_cb,
+					data);
+		bt_rap_set_proc_active_cb(data->hci_sm, rap_proc_active_changed,
+					data);
 	}
 
 	if (!bt_rap_attach(data->rap, client)) {
@@ -411,8 +735,7 @@ static int rap_accept(struct btd_service *service)
 		if (bt_hci_get_conn_handle(data->adapter_data->hci,
 					(const uint8_t *) bdaddr, &handle)) {
 			DBG("Found conn handle 0x%04X for %s", handle, addr);
-			DBG("Setting up handle mapping: handle=0x%04X",
-				handle);
+			data->conn_handle = handle;
 			bt_rap_set_conn_hndl(data->hci_sm,
 					data->rap, handle,
 					(const uint8_t *) bdaddr,
@@ -426,12 +749,33 @@ static int rap_accept(struct btd_service *service)
 
 	btd_service_connecting_complete(service, 0);
 
+	g_dbus_register_interface(btd_get_dbus_connection(),
+				  device_get_path(data->device),
+				  CS_INTERFACE, cs_dbus_methods,
+				  NULL, cs_dbus_properties, data, NULL);
+
 	return 0;
 }
 
 static int rap_disconnect(struct btd_service *service)
 {
-	DBG(" ");
+	struct rap_data *data = btd_service_get_user_data(service);
+	char addr[18];
+
+	ba2str(device_get_address(btd_service_get_device(service)), addr);
+	DBG("%s", addr);
+	if (!data) {
+		error("RAP Service not handled by profile");
+		return -EINVAL;
+	}
+
+	if (data && data->hci_sm && data->conn_handle) {
+		bt_rap_clear_conn_handle(data->hci_sm, data->conn_handle);
+		data->conn_handle = 0;
+	}
+
+	memset(&data->active_session, 0, sizeof(data->active_session));
+
 	btd_service_disconnecting_complete(service, 0);
 	return 0;
 }
diff --git a/profiles/ranging/rap_hci.c b/profiles/ranging/rap_hci.c
index 13f1365f3..e57f967a2 100644
--- a/profiles/ranging/rap_hci.c
+++ b/profiles/ranging/rap_hci.c
@@ -21,6 +21,8 @@
 #include "lib/bluetooth/bluetooth.h"
 #include "src/shared/util.h"
 #include "src/shared/queue.h"
+#include "src/shared/timeout.h"
+#include "src/shared/cs-types.h"
 #include "src/shared/rap.h"
 #include "src/shared/att.h"
 #include "src/log.h"
@@ -60,19 +62,28 @@ _Static_assert(ARRAY_SIZE(state_names) == CS_STATE_UNSPECIFIED + 1,
 typedef void (*cs_callback_t)(uint16_t length,
 			const void *param, void *user_data);
 
-/* State Machine Context */
+typedef void (*cs_timeout_func_t)(void *user_data);
+
 struct cs_state_machine {
 	enum cs_state current_state;
 	enum cs_state old_state;
 	struct bt_hci *hci;
 	struct bt_rap *rap;
 	struct queue *event_ids;
+	unsigned int measurement_timeout_id;
 	bool initiator;
 	bool procedure_active;
 	struct bt_rap_hci_cs_options cs_opt;  /* Per-instance CS options */
 	uint8_t role_enable;  /* Role value for HCI commands (1, 2, or 3) */
 	struct queue *conn_mappings;  /* Per-instance connection mappings */
+	uint16_t active_conn_handle;  /* current measurement handle */
 	struct timespec last_chan_class_time;  /* For 1-second rate limit */
+	struct bt_rap_le_cs_config   cs_config;
+	struct bt_rap_le_cs_frequency cs_frequency;
+	cs_timeout_func_t timeout_func;
+	void *timeout_data;
+	void (*proc_active_func)(bool active, void *user_data);
+	void *proc_active_data;
 };
 
 /* Connection Handle Mapping */
@@ -85,7 +96,83 @@ struct rap_conn_mapping {
 	struct bt_rap *rap;
 };
 
-/* Connection Mapping Helper Functions */
+bool bt_rap_set_cs_config_params(void *hci_sm,
+				 const struct bt_rap_le_cs_config *config)
+{
+	struct cs_state_machine *sm = hci_sm;
+
+	if (!sm || !config)
+		return false;
+
+	sm->cs_config = *config;
+	return true;
+}
+
+bool bt_rap_set_cs_freq_params(void *hci_sm,
+			       const struct bt_rap_le_cs_frequency *frequency)
+{
+	struct cs_state_machine *sm = hci_sm;
+
+	if (!sm || !frequency)
+		return false;
+
+	sm->cs_frequency = *frequency;
+	return true;
+}
+
+bool bt_rap_set_default_settings_params(void *hci_sm,
+			const struct bt_rap_le_cs_default_settings *settings)
+{
+	struct cs_state_machine *sm = hci_sm;
+
+	if (!sm || !settings)
+		return false;
+
+	sm->role_enable            = settings->role;
+	sm->cs_opt.role            = settings->role;
+	sm->cs_opt.cs_sync_ant_sel = settings->cs_sync_ant_sel;
+	sm->cs_opt.max_tx_power    = settings->max_tx_power;
+	return true;
+}
+
+bool bt_rap_get_cs_config_params(void *hci_sm,
+				 struct bt_rap_le_cs_config *config)
+{
+	struct cs_state_machine *sm = hci_sm;
+
+	if (!sm || !config)
+		return false;
+
+	*config = sm->cs_config;
+	return true;
+}
+
+bool bt_rap_get_cs_freq_params(void *hci_sm,
+			       struct bt_rap_le_cs_frequency *frequency)
+{
+	struct cs_state_machine *sm = hci_sm;
+
+	if (!sm || !frequency)
+		return false;
+
+	*frequency = sm->cs_frequency;
+	return true;
+}
+
+bool bt_rap_get_default_settings_params(void *hci_sm,
+			struct bt_rap_le_cs_default_settings *settings)
+{
+	struct cs_state_machine *sm = hci_sm;
+
+	if (!sm || !settings)
+		return false;
+
+	settings->role            = sm->cs_opt.role;
+	settings->cs_sync_ant_sel = sm->cs_opt.cs_sync_ant_sel;
+	settings->max_tx_power    = sm->cs_opt.max_tx_power;
+	return true;
+}
+
 static void mapping_free(void *data)
 {
 	struct rap_conn_mapping *mapping = data;
@@ -173,6 +260,11 @@ static void cs_state_machine_init(struct cs_state_machine *sm,
 				uint8_t role, uint8_t cs_sync_ant_sel,
 				int8_t max_tx_power)
 {
+	static const uint8_t ch_map[10] = {
+		0xFC, 0xFF, 0x7F, 0xFC, 0xFF,
+		0xFF, 0xFF, 0xFF, 0xFF, 0x1F
+	};
+
 	if (!sm)
 		return;
 
@@ -185,15 +277,44 @@ static void cs_state_machine_init(struct cs_state_machine *sm,
 
 	/* Store role_enable for HCI commands (1, 2, or 3 from config) */
 	sm->role_enable = role;
-
-	/* Initialize per-instance CS options
-	 * Note: cs_opt.role will be overwritten with actual role (0x00 or 0x01)
-	 * from config complete event, but role_enable preserves the HCI value
-	 */
-	sm->cs_opt.role = role;
+	sm->cs_opt.role            = role;
 	sm->cs_opt.cs_sync_ant_sel = cs_sync_ant_sel;
-	sm->cs_opt.max_tx_power = max_tx_power;
-	sm->cs_opt.rtt_type = 0;  /* Will be set from config complete event */
+	sm->cs_opt.max_tx_power    = max_tx_power;
+	sm->cs_opt.rtt_type        = 0;
+
+	sm->cs_config.config_id              = 0;
+	sm->cs_config.main_mode_type         = 0x01;
+	sm->cs_config.sub_mode_type          = 0xFF;
+	sm->cs_config.main_mode_min_steps    = 0x02;
+	sm->cs_config.main_mode_max_steps    = 0x03;
+	sm->cs_config.main_mode_repetition   = 0x01;
+	sm->cs_config.mode0_steps            = 0x02;
+	sm->cs_config.role                   = 0x00;
+	sm->cs_config.rtt_types              = 0x00;
+	sm->cs_config.cs_sync_phy            = 0x01;
+	memcpy(sm->cs_config.channel_map, ch_map, 10);
+	sm->cs_config.channel_map_repetition = 0x01;
+	sm->cs_config.channel_selection_type = 0x00;
+	sm->cs_config.channel_shape          = 0x00;
+	sm->cs_config.channel_jump           = 0x02;
+	sm->cs_config.companion_signal_enable = 0x00;
+
+	sm->cs_frequency.max_procedure_duration        = 0x0640;
+	sm->cs_frequency.min_period_between_procedures = 0x001E;
+	sm->cs_frequency.max_period_between_procedures = 0x0096;
+	sm->cs_frequency.max_procedure_count           = 0x0000;
+	sm->cs_frequency.min_sub_event_len[0]          = 0x00;
+	sm->cs_frequency.min_sub_event_len[1]          = 0x20;
+	sm->cs_frequency.min_sub_event_len[2]          = 0x00;
+	sm->cs_frequency.max_sub_event_len[0]          = 0x03;
+	sm->cs_frequency.max_sub_event_len[1]          = 0x20;
+	sm->cs_frequency.max_sub_event_len[2]          = 0x00;
+	sm->cs_frequency.tone_antenna_config_selection = 0x07;
+	sm->cs_frequency.phy                           = 0x01;
+	sm->cs_frequency.tx_power_delta                = 0x80;
+	sm->cs_frequency.preferred_peer_antenna        = 0x03;
+	sm->cs_frequency.snr_control_initiator         = 0xFF;
+	sm->cs_frequency.snr_control_reflector         = 0xFF;
 }
 
 /* State Transition Logic */
@@ -228,7 +349,15 @@ static enum cs_state cs_get_current_state(struct cs_state_machine *sm)
 
 static bool is_initiator_role(const struct cs_state_machine *sm)
 {
-	return sm->role_enable == 0x01 || sm->role_enable == 0x03;
+	return sm->role_enable == 0x01;
+}
+
+/* For role_enable=0x03 (Both), Central acts as Initiator and Peripheral as
+ * Reflector — the link layer topology determines the CS role assignment.
+ */
+static bool is_both_role(const struct cs_state_machine *sm)
+{
+	return sm->role_enable == 0x03;
 }
 
 /* Helper function to send read remote capabilities for all connections */
@@ -262,20 +391,6 @@ static bool bt_rap_read_remote_supported_capabilities(void *hci_sm,
 	return true;
 }
 
-/* Helper function to send read remote capabilities for all connections */
-static void send_read_remote_cap_for_mapping(void *data, void *user_data)
-{
-	struct rap_conn_mapping *mapping = data;
-	struct cs_state_machine *sm = user_data;
-
-	if (!mapping || !sm)
-		return;
-
-	DBG("Sending read remote capabilities for handle 0x%04X",
-		mapping->handle);
-	bt_rap_read_remote_supported_capabilities(sm, mapping->handle);
-}
-
 /* HCI Event Callbacks */
 static void rap_rd_loc_supp_cap_done_cb(const void *data, uint8_t size,
 					void *user_data)
@@ -324,12 +439,9 @@ static void rap_rd_loc_supp_cap_done_cb(const void *data, uint8_t size,
 	/* Transition to INIT state before reading remote capabilities */
 	cs_set_state(sm, CS_STATE_INIT);
 
-	/* Send read remote capabilities for all connected devices */
-	if (sm->conn_mappings) {
-		DBG("Sending read remote capabilities for all connections");
-		queue_foreach(sm->conn_mappings,
-				send_read_remote_cap_for_mapping, sm);
-	}
+	DBG("Sending read remote capabilities for handle 0x%04X",
+		sm->active_conn_handle);
+	bt_rap_read_remote_supported_capabilities(sm, sm->active_conn_handle);
 }
 
 static void rap_send_hci_cs_create_config_command(struct cs_state_machine *sm,
@@ -338,11 +450,6 @@ static void rap_send_hci_cs_create_config_command(struct cs_state_machine *sm,
 	struct bt_hci_cmd_le_cs_create_config cmd;
 	unsigned int status;
 
-	uint8_t channel_map[10] = {
-		0xFC, 0xFF, 0x7F, 0xFC, 0xFF,
-		0xFF, 0xFF, 0xFF, 0xFF, 0x1F
-	};
-
 	if (!sm || !sm->hci) {
 		error("CS Create Config: sm or hci is null");
 		return;
@@ -352,23 +459,23 @@ static void rap_send_hci_cs_create_config_command(struct cs_state_machine *sm,
 
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.handle = cpu_to_le16(handle);
-	cmd.create_context = 1;
-	/* Default values, will change to pick user given values later */
-	cmd.config_id              = 0x00;
-	cmd.main_mode_type         = 0x01;
-	cmd.sub_mode_type          = 0xFF;
-	cmd.min_main_mode_steps    = 0x02;
-	cmd.max_main_mode_steps    = 0x03;
-	cmd.main_mode_repetition   = 0x01;
-	cmd.mode_0_steps           = 0x02;
-	cmd.role                   = 0x00;
-	cmd.rtt_type               = 0x00;
-	cmd.cs_sync_phy            = 0x01;
-	memcpy(cmd.channel_map, channel_map, 10);
-	cmd.channel_map_repetition = 0x01;
-	cmd.channel_selection_type = 0x00;
-	cmd.ch3c_shape             = 0x00;
-	cmd.ch3c_jump              = 0x02;
+	cmd.create_context = 0x01; /* Initiates cs config procedure */
+
+	cmd.config_id              = sm->cs_config.config_id;
+	cmd.main_mode_type         = sm->cs_config.main_mode_type;
+	cmd.sub_mode_type          = sm->cs_config.sub_mode_type;
+	cmd.min_main_mode_steps    = sm->cs_config.main_mode_min_steps;
+	cmd.max_main_mode_steps    = sm->cs_config.main_mode_max_steps;
+	cmd.main_mode_repetition   = sm->cs_config.main_mode_repetition;
+	cmd.mode_0_steps           = sm->cs_config.mode0_steps;
+	cmd.role                   = sm->cs_config.role;
+	cmd.rtt_type               = sm->cs_config.rtt_types;
+	cmd.cs_sync_phy            = sm->cs_config.cs_sync_phy;
+	memcpy(cmd.channel_map, sm->cs_config.channel_map, 10);
+	cmd.channel_map_repetition = sm->cs_config.channel_map_repetition;
+	cmd.channel_selection_type = sm->cs_config.channel_selection_type;
+	cmd.ch3c_shape             = sm->cs_config.channel_shape;
+	cmd.ch3c_jump              = sm->cs_config.channel_jump;
 	cmd.reserved               = 0x00;
 
 	status = bt_hci_send(sm->hci, BT_HCI_CMD_LE_CS_CREATE_CONFIG,
@@ -388,6 +495,7 @@ static void rap_def_settings_done_cb(const void *data, uint8_t size,
 {
 	const struct bt_hci_rsp_le_cs_set_def_settings *rp;
 	struct cs_state_machine *sm = user_data;
+	struct rap_conn_mapping *m;
 
 	if (!sm || !data || size < sizeof(*rp))
 		return;
@@ -403,14 +511,24 @@ static void rap_def_settings_done_cb(const void *data, uint8_t size,
 	}
 
 	if (rp->status == 0) {
-		/* Success - proceed to configuration */
 		cs_set_state(sm, CS_STATE_WAIT_CONFIG_CMPLT);
 
-		/* If role is initiator, send CS Create Config command */
-		if (is_initiator_role(sm))
+		/* Send CS Create Config if we are (or will act as) Initiator.
+		 * For role_enable=Both, Central acts as Initiator.
+		 */
+		if (is_initiator_role(sm)) {
 			rap_send_hci_cs_create_config_command(sm, rp->handle);
-		else
+		} else if (is_both_role(sm)) {
+			m = find_mapping_by_handle(sm, rp->handle);
+
+			if (m && m->is_central)
+				rap_send_hci_cs_create_config_command(sm,
+								rp->handle);
+			else
+				DBG("Both role: Wait for CS Config Cmpl");
+		} else {
 			DBG("Reflector role: Waiting for CS Config Completed");
+		}
 	} else {
 		/* Error - transition to stopped */
 		error("CS Set default setting failed with status 0x%02X",
@@ -434,7 +552,7 @@ static void rap_send_hci_cs_remove_config_command(struct cs_state_machine *sm,
 
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.handle = cpu_to_le16(handle);
-	cmd.config_id = 0x00;  /* Default config ID */
+	cmd.config_id = sm->cs_config.config_id;
 
 	status = bt_hci_send(sm->hci, BT_HCI_CMD_LE_CS_REMOVE_CONFIG,
 				&cmd, sizeof(cmd), NULL, sm, NULL);
@@ -481,13 +599,6 @@ static bool rap_send_hci_cs_set_procedure_parameters(
 {
 	struct bt_hci_cmd_le_cs_set_proc_params cmd;
 	unsigned int status;
-	uint8_t min_sub_event_len[3] = {
-		0x00, 0x20, 0x00
-	};
-
-	uint8_t max_sub_event_len[3] = {
-		0x03, 0x20, 0x00
-	};
 
 	if (!sm || !sm->hci) {
 		error("CS Set Procedure Parameters: sm or hci is null");
@@ -498,20 +609,25 @@ static bool rap_send_hci_cs_set_procedure_parameters(
 
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.handle = cpu_to_le16(handle);
-	/* Default values, will change to pick user given values later */
-	cmd.config_id = 0x00;
-	cmd.max_procedure_len = 0x0640;
-	cmd.min_procedure_interval = 0x1E;
-	cmd.max_procedure_interval = 0x96;
-	cmd.max_procedure_count = 0x00;
-	memcpy(cmd.min_subevent_len, min_sub_event_len, 3);
-	memcpy(cmd.max_subevent_len, max_sub_event_len, 3);
-	cmd.tone_antenna_config_selection = 0x07;
-	cmd.phy                    = 0x01;
-	cmd.tx_power_delta         = 0x80;
-	cmd.preferred_peer_antenna = 0x03;
-	cmd.snr_control_initiator  = 0xFF;
-	cmd.snr_control_reflector  = 0xFF;
+
+	cmd.config_id = sm->cs_config.config_id;
+	cmd.max_procedure_len =
+		cpu_to_le16(sm->cs_frequency.max_procedure_duration);
+	cmd.min_procedure_interval =
+		cpu_to_le16(sm->cs_frequency.min_period_between_procedures);
+	cmd.max_procedure_interval =
+		cpu_to_le16(sm->cs_frequency.max_period_between_procedures);
+	cmd.max_procedure_count =
+		cpu_to_le16(sm->cs_frequency.max_procedure_count);
+	memcpy(cmd.min_subevent_len, sm->cs_frequency.min_sub_event_len, 3);
+	memcpy(cmd.max_subevent_len, sm->cs_frequency.max_sub_event_len, 3);
+	cmd.tone_antenna_config_selection =
+		sm->cs_frequency.tone_antenna_config_selection;
+	cmd.phy                    = sm->cs_frequency.phy;
+	cmd.tx_power_delta         = sm->cs_frequency.tx_power_delta;
+	cmd.preferred_peer_antenna = sm->cs_frequency.preferred_peer_antenna;
+	cmd.snr_control_initiator  = sm->cs_frequency.snr_control_initiator;
+	cmd.snr_control_reflector  = sm->cs_frequency.snr_control_reflector;
 
 	status = bt_hci_send(sm->hci, BT_HCI_CMD_LE_CS_SET_PROC_PARAMS,
 				&cmd, sizeof(cmd), NULL, sm, NULL);
@@ -541,7 +657,7 @@ static bool rap_send_hci_cs_procedure_enable(struct cs_state_machine *sm,
 
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.handle = cpu_to_le16(handle);
-	cmd.config_id = 0x00; /* Default config Id */
+	cmd.config_id = sm->cs_config.config_id;
 	cmd.enable = enable_proc ? 0x01 : 0x00;
 
 	status = bt_hci_send(sm->hci, BT_HCI_CMD_LE_CS_PROC_ENABLE,
@@ -591,6 +707,8 @@ static void rap_rd_rem_fae_cmplt_evt(const void *data, uint8_t size,
 {
 	struct cs_state_machine *sm = (struct cs_state_machine *) user_data;
 	const struct bt_hci_evt_le_cs_rd_rem_fae_complete *evt;
+	struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete tmp_ev;
+	struct rap_conn_mapping *m;
 	struct iovec iov;
 	int i;
 
@@ -598,11 +716,9 @@ static void rap_rd_rem_fae_cmplt_evt(const void *data, uint8_t size,
 		size < sizeof(struct bt_hci_evt_le_cs_rd_rem_fae_complete))
 		return;
 
-	/* Initialize iovec with the event data */
 	iov.iov_base = (void *) data;
 	iov.iov_len = size;
 
-	/* Pull the entire structure at once */
 	evt = util_iov_pull_mem(&iov, sizeof(*evt));
 
 	if (!evt) {
@@ -612,21 +728,20 @@ static void rap_rd_rem_fae_cmplt_evt(const void *data, uint8_t size,
 
 	DBG("status=0x%02X, handle=0x%04X", evt->status, evt->handle);
 
-	/* Check status */
 	if (evt->status != 0) {
 		/* Status 0x11 (Unsupported Feature or Parameter Value) means
 		 * the remote has zero FAE, the procedure continues
 		 * to the Default Settings step.
 		 */
 		if (evt->status == 0x11) {
-			DBG("Remote FAE=0 (No_FAE), proceed to Def Settings");
-			if (is_initiator_role(sm)) {
-				struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete
-								tmp_ev;
+			m = find_mapping_by_handle(sm, evt->handle);
 
+			DBG("Remote FAE=0 (No_FAE), proceed to Def Settings");
+			if (is_initiator_role(sm) ||
+			    (is_both_role(sm) && m && m->is_central)) {
 				memset(&tmp_ev, 0, sizeof(tmp_ev));
 				tmp_ev.handle = evt->handle;
-				DBG("Initiator: send def settings (No_FAE)");
+				DBG("Init/Both: send def settings (No_FAE)");
 				rap_send_hci_def_settings_command(sm, &tmp_ev);
 			} else {
 				DBG("Reflector role: continuing after No_FAE");
@@ -651,13 +766,13 @@ static void rap_rd_rem_fae_cmplt_evt(const void *data, uint8_t size,
 	}
 
 	/* After receiving FAE Table, send default settings */
-	/* Local capabilities already read before this event */
-	if (is_initiator_role(sm)) {
-		struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete tmp_ev;
+	m = find_mapping_by_handle(sm, evt->handle);
 
+	if (is_initiator_role(sm) ||
+	    (is_both_role(sm) && m && m->is_central)) {
 		memset(&tmp_ev, 0, sizeof(tmp_ev));
 		tmp_ev.handle = evt->handle;
-		DBG("Initiator role: send def settings after FAE table");
+		DBG("Init/Both: send def settings after FAE");
 		rap_send_hci_def_settings_command(sm, &tmp_ev);
 	} else {
 		DBG("Reflector role: Proceeding after FAE Table");
@@ -698,6 +813,7 @@ static void rap_rd_rmt_supp_cap_cmplt_evt(const void *data, uint8_t size,
 {
 	struct cs_state_machine *sm = user_data;
 	const struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete *evt;
+	struct rap_conn_mapping *m;
 	struct iovec iov;
 	uint16_t subfeatures_supported;
 
@@ -745,9 +861,11 @@ static void rap_rd_rmt_supp_cap_cmplt_evt(const void *data, uint8_t size,
 		return;
 	}
 
-	/* Local capabilities already read before this event */
-	if (is_initiator_role(sm)) {
-		DBG("Initiator role: send def settings cmd for handle 0x%04X",
+	m = find_mapping_by_handle(sm, evt->handle);
+
+	if (is_initiator_role(sm) ||
+	    (is_both_role(sm) && m && m->is_central)) {
+		DBG("Init/Both: send def settings for 0x%04X",
 			evt->handle);
 		rap_send_hci_def_settings_command(sm, evt);
 	} else {
@@ -763,6 +881,7 @@ static void rap_cs_config_cmplt_evt(const void *data, uint8_t size,
 	struct cs_state_machine *sm = user_data;
 	const struct bt_hci_evt_le_cs_config_complete *evt;
 	struct rap_ev_cs_config_cmplt rap_ev;
+	struct rap_conn_mapping *mapping;
 	struct iovec iov;
 
 	if (!sm || !data || size < sizeof(*evt))
@@ -855,9 +974,6 @@ static void rap_cs_config_cmplt_evt(const void *data, uint8_t size,
 
 	/* CS Security Enable may only be issued by the BLE Central */
 	if (rap_ev.role == 0x00) {
-		/* Initiator role */
-		struct rap_conn_mapping *mapping;
-
 		mapping = find_mapping_by_handle(sm, evt->handle);
 		if (!mapping || !mapping->is_central) {
 			error("CS Security Enable skipped: not BLE Central");
@@ -980,8 +1096,8 @@ static void rap_cs_proc_enable_cmplt_evt(const void *data, uint8_t size,
 
 	DBG("size=0x%02X", size);
 
-	/* State Check */
-	if (cs_get_current_state(sm) != CS_STATE_WAIT_PROC_CMPLT) {
+	if ((cs_get_current_state(sm) != CS_STATE_WAIT_PROC_CMPLT) &&
+		(cs_get_current_state(sm) != CS_STATE_STARTED)) {
 		DBG("Event received in Wrong State!! ");
 		DBG("Expected : CS_STATE_WAIT_PROC_CMPLT");
 		return;
@@ -1002,6 +1118,8 @@ static void rap_cs_proc_enable_cmplt_evt(const void *data, uint8_t size,
 			evt->status);
 		cs_set_state(sm, CS_STATE_STOPPED);
 		sm->procedure_active = false;
+		if (sm->proc_active_func)
+			sm->proc_active_func(false, sm->proc_active_data);
 		return;
 	}
 
@@ -1030,9 +1148,13 @@ static void rap_cs_proc_enable_cmplt_evt(const void *data, uint8_t size,
 	if (rap_ev.state == 0x01) {
 		cs_set_state(sm, CS_STATE_STARTED);
 		sm->procedure_active = true;
+		if (sm->proc_active_func)
+			sm->proc_active_func(true, sm->proc_active_data);
 	} else if (rap_ev.state == 0x00) {
 		cs_set_state(sm, CS_STATE_STOPPED);
 		sm->procedure_active = false;
+		if (sm->proc_active_func)
+			sm->proc_active_func(false, sm->proc_active_data);
 	}
 
 	/* Send callback to RAP Profile */
@@ -1080,7 +1202,7 @@ static void parse_mode_zero_data(struct iovec *iov,
 	util_iov_pull_u8(iov, &mode_data->packet_ant);
 	DBG("CS Step mode 0");
 
-	if (cs_role == CS_INITIATOR && iov->iov_len >= 4) {
+	if (cs_role == CS_INITIATOR && iov->iov_len >= 2) {
 		util_iov_pull_le16(iov, &freq_offset);
 		mode_data->init_measured_freq_offset = freq_offset;
 	}
@@ -1171,7 +1293,6 @@ static void parse_mode_three_data(struct iovec *iov,
 				uint8_t cs_role, uint8_t cs_rtt_type,
 				uint8_t max_paths)
 {
-	uint8_t k;
 	struct cs_mode_one_data *mode_one = &mode_data->mode_one_data;
 	struct cs_mode_two_data *mode_two = &mode_data->mode_two_data;
 
@@ -1186,21 +1307,7 @@ static void parse_mode_three_data(struct iovec *iov,
 	parse_mode_one_data(iov, mode_one, cs_role, cs_rtt_type);
 
 	/* Parse Mode 2 portion */
-	if (iov->iov_len >= 1) {
-		util_iov_pull_u8(iov, &mode_two->ant_perm_index);
-		for (k = 0; k < max_paths; k++) {
-			int16_t i_val, q_val;
-
-			if (iov->iov_len < 4)
-				break;
-			parse_i_q_sample(iov, &i_val, &q_val);
-			mode_two->tone_pct[k].i_sample = i_val;
-			mode_two->tone_pct[k].q_sample = q_val;
-
-			util_iov_pull_u8(iov,
-					 &mode_two->tone_quality_indicator[k]);
-		}
-	}
+	parse_mode_two_data(iov, mode_two, max_paths);
 }
 
 /* Parse a single CS step */
@@ -1537,8 +1644,27 @@ void *bt_rap_attach_hci(struct bt_rap *rap, struct bt_hci *hci,
 			uint8_t role, uint8_t cs_sync_ant_sel,
 			int8_t max_tx_power)
 {
+	static const struct {
+		uint8_t subevent;
+		bt_hci_callback_func_t callback;
+	} subevents[] = {
+		{ BT_HCI_EVT_LE_CS_RD_REM_SUPP_CAP_COMPLETE,
+					rap_rd_rmt_supp_cap_cmplt_evt },
+		{ BT_HCI_EVT_LE_CS_RD_REM_FAE_COMPLETE,
+					rap_rd_rem_fae_cmplt_evt },
+		{ BT_HCI_EVT_LE_CS_CONFIG_COMPLETE,
+					rap_cs_config_cmplt_evt },
+		{ BT_HCI_EVT_LE_CS_SEC_ENABLE_COMPLETE,
+					rap_cs_sec_enable_cmplt_evt },
+		{ BT_HCI_EVT_LE_CS_PROC_ENABLE_COMPLETE,
+					rap_cs_proc_enable_cmplt_evt },
+		{ BT_HCI_EVT_LE_CS_SUBEVENT_RESULT,
+					rap_cs_subevt_result_evt },
+		{ BT_HCI_EVT_LE_CS_SUBEVENT_RESULT_CONTINUE,
+					rap_cs_subevt_result_cont_evt },
+	};
 	struct cs_state_machine *sm;
-	unsigned int id;
+	unsigned int i;
 
 	if (!rap || !hci) {
 		error("rap or hci null");
@@ -1564,78 +1690,95 @@ void *bt_rap_attach_hci(struct bt_rap *rap, struct bt_hci *hci,
 	}
 
 	/* Register each LE Meta subevent individually */
-	id = bt_hci_register_subevent(hci,
-			BT_HCI_EVT_LE_CS_RD_REM_SUPP_CAP_COMPLETE,
-			rap_rd_rmt_supp_cap_cmplt_evt, sm, NULL);
-	if (!id)
-		goto fail;
+	for (i = 0; i < ARRAY_SIZE(subevents); i++) {
+		unsigned int id = bt_hci_register_subevent(hci,
+						subevents[i].subevent,
+						subevents[i].callback,
+						sm, NULL);
+		if (!id) {
+			error("Failed to register hci le meta subevents");
+			queue_foreach(sm->event_ids, unregister_event_id, hci);
+			queue_destroy(sm->event_ids, NULL);
+			queue_destroy(sm->conn_mappings, mapping_free);
+			free(sm);
+			return NULL;
+		}
 
-	queue_push_tail(sm->event_ids, UINT_TO_PTR(id));
+		queue_push_tail(sm->event_ids, UINT_TO_PTR(id));
+	}
 
-	id = bt_hci_register_subevent(hci,
-		BT_HCI_EVT_LE_CS_RD_REM_FAE_COMPLETE,
-		rap_rd_rem_fae_cmplt_evt, sm, NULL);
+	DBG("HCI state machine attached (role=%u, ant=0x%02x, power=%d)",
+		sm->role_enable, sm->cs_opt.cs_sync_ant_sel,
+		sm->cs_opt.max_tx_power);
 
-	if (!id)
-		goto fail;
+	return sm;
+}
 
-	queue_push_tail(sm->event_ids, UINT_TO_PTR(id));
+static bool measurement_timeout_cb(void *user_data)
+{
+	struct cs_state_machine *sm = user_data;
 
-	id = bt_hci_register_subevent(hci,
-			BT_HCI_EVT_LE_CS_CONFIG_COMPLETE,
-			rap_cs_config_cmplt_evt, sm, NULL);
-	if (!id)
-		goto fail;
+	sm->measurement_timeout_id = 0;
 
-	queue_push_tail(sm->event_ids, UINT_TO_PTR(id));
+	DBG("Measurement duration expired, stopping CS procedure");
+	bt_rap_stop_measurement(sm);
 
-	id = bt_hci_register_subevent(hci,
-			BT_HCI_EVT_LE_CS_SEC_ENABLE_COMPLETE,
-			rap_cs_sec_enable_cmplt_evt, sm, NULL);
-	if (!id)
-		goto fail;
+	if (sm->timeout_func)
+		sm->timeout_func(sm->timeout_data);
 
-	queue_push_tail(sm->event_ids, UINT_TO_PTR(id));
+	return false;
+}
 
-	id = bt_hci_register_subevent(hci,
-			BT_HCI_EVT_LE_CS_PROC_ENABLE_COMPLETE,
-			rap_cs_proc_enable_cmplt_evt, sm, NULL);
-	if (!id)
-		goto fail;
+bool bt_rap_start_measurement(void *hci_sm, uint16_t conn_handle,
+			      uint32_t duration_secs)
+{
+	struct cs_state_machine *sm = hci_sm;
 
-	queue_push_tail(sm->event_ids, UINT_TO_PTR(id));
+	if (!sm || !sm->hci)
+		return false;
 
-	id = bt_hci_register_subevent(hci,
-			BT_HCI_EVT_LE_CS_SUBEVENT_RESULT,
-			rap_cs_subevt_result_evt, sm, NULL);
-	if (!id)
-		goto fail;
+	if (!find_mapping_by_handle(sm, conn_handle)) {
+		error("start_measurement: hndl 0x%04X not found", conn_handle);
+		return false;
+	}
 
-	queue_push_tail(sm->event_ids, UINT_TO_PTR(id));
+	sm->active_conn_handle = conn_handle;
 
-	id = bt_hci_register_subevent(hci,
-			BT_HCI_EVT_LE_CS_SUBEVENT_RESULT_CONTINUE,
-			rap_cs_subevt_result_cont_evt, sm, NULL);
-	if (!id)
-		goto fail;
+	if (sm->measurement_timeout_id) {
+		timeout_remove(sm->measurement_timeout_id);
+		sm->measurement_timeout_id = 0;
+	}
 
-	queue_push_tail(sm->event_ids, UINT_TO_PTR(id));
+	if (!bt_rap_read_local_supported_capabilities(sm))
+		return false;
 
-	DBG("CS options: role=%u, cs_sync_ant_sel=%u, max_tx_power=%d",
-		role, cs_sync_ant_sel, max_tx_power);
+	if (duration_secs > 0)
+		sm->measurement_timeout_id = timeout_add_seconds(duration_secs,
+					measurement_timeout_cb, sm, NULL);
 
-	/* place holder, need DBus API to be called */
-	bt_rap_read_local_supported_capabilities(sm);
+	return true;
+}
 
-	return sm;
+bool bt_rap_stop_measurement(void *hci_sm)
+{
+	struct cs_state_machine *sm = hci_sm;
+
+	if (!sm || !sm->hci)
+		return false;
+
+	if (sm->measurement_timeout_id) {
+		timeout_remove(sm->measurement_timeout_id);
+		sm->measurement_timeout_id = 0;
+	}
 
-fail:
-	error("Failed to register hci le meta subevents");
-	queue_foreach(sm->event_ids, unregister_event_id, hci);
-	queue_destroy(sm->event_ids, NULL);
-	queue_destroy(sm->conn_mappings, mapping_free);
-	free(sm);
-	return NULL;
+	if (!find_mapping_by_handle(sm, sm->active_conn_handle)) {
+		error("stop_measurement: handle 0x%04X not found",
+		      sm->active_conn_handle);
+		return false;
+	}
+
+	return rap_send_hci_cs_procedure_enable(sm, sm->active_conn_handle,
+						false);
 }
 
 bool bt_rap_set_conn_hndl(void *hci_sm, struct bt_rap *rap,
@@ -1672,6 +1815,40 @@ void bt_rap_clear_conn_handle(void *hci_sm, uint16_t handle)
 
 	DBG("Clearing connection mapping: handle=0x%04X", handle);
 	remove_conn_mapping(sm, handle);
+	sm->procedure_active = false;
+}
+
+bool bt_rap_is_procedure_active(void *hci_sm)
+{
+	struct cs_state_machine *sm = hci_sm;
+
+	if (!sm)
+		return false;
+
+	return sm->procedure_active;
+}
+
+void bt_rap_set_timeout_cb(void *hci_sm, void (*func)(void *), void *user_data)
+{
+	struct cs_state_machine *sm = hci_sm;
+
+	if (!sm)
+		return;
+
+	sm->timeout_func = func;
+	sm->timeout_data = user_data;
+}
+
+void bt_rap_set_proc_active_cb(void *hci_sm, void (*func)(bool, void *),
+				void *user_data)
+{
+	struct cs_state_machine *sm = hci_sm;
+
+	if (!sm)
+		return;
+
+	sm->proc_active_func = func;
+	sm->proc_active_data = user_data;
 }
 
 void bt_rap_detach_hci(struct bt_rap *rap, void *hci_sm)
@@ -1690,12 +1867,14 @@ void bt_rap_detach_hci(struct bt_rap *rap, void *hci_sm)
 			queue_foreach(sm->event_ids, unregister_event_id,
 								sm->hci);
 
+		if (sm->measurement_timeout_id) {
+			timeout_remove(sm->measurement_timeout_id);
+			sm->measurement_timeout_id = 0;
+		}
+
 		queue_destroy(sm->event_ids, NULL);
 
-		/* Clean up per-instance connection mappings.
-		 * Each state machine owns its own conn_mappings queue;
-		 * this destroys all mappings for this instance only.
-		 */
+		/* destroys mappings for this instance only */
 		queue_destroy(sm->conn_mappings, mapping_free);
 
 		/* Free the state machine */
-- 


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

* [PATCH BlueZ v3 4/4] client: Add Channel Sounding shell submenu
  2026-07-12 12:17 [PATCH BlueZ v3 0/4] Add Channel Sounding Dbus support and Naga Bhavani Akella
                   ` (2 preceding siblings ...)
  2026-07-12 12:17 ` [PATCH BlueZ v3 3/4] profiles: Add D-Bus Channel Sounding control APIs Naga Bhavani Akella
@ 2026-07-12 12:17 ` Naga Bhavani Akella
  3 siblings, 0 replies; 7+ messages in thread
From: Naga Bhavani Akella @ 2026-07-12 12:17 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
	Naga Bhavani Akella

Add a cs bt_shell submenu for controlling
org.bluez.ChannelSounding1, supporting measurement start/stop,
default-setting configuration, and session status display.
Maintain reusable validated CS parameters and
track active sessions via D-Bus Active state,
replies, and disconnects.
Integrate with client/main.c to manage per-adapter
ChannelSounding proxies, device resolution,
property updates, and session cleanup.
---
 Makefile.tools |    3 +-
 client/cs.c    | 1157 ++++++++++++++++++++++++++++++++++++++++++++++++
 client/cs.h    |   18 +
 client/main.c  |   27 +-
 4 files changed, 1203 insertions(+), 2 deletions(-)
 create mode 100644 client/cs.c
 create mode 100644 client/cs.h

diff --git a/Makefile.tools b/Makefile.tools
index 6188449f1..b5f7ef8da 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -16,7 +16,8 @@ client_bluetoothctl_SOURCES = client/main.c \
 					client/mgmt.h client/mgmt.c \
 					client/assistant.h client/assistant.c \
 					client/hci.h client/hci.c \
-					client/telephony.h client/telephony.c
+					client/telephony.h client/telephony.c \
+					client/cs.h client/cs.c
 client_bluetoothctl_LDADD = lib/libbluetooth-internal.la \
 			gdbus/libgdbus-internal.la src/libshared-glib.la \
 			$(GLIB_LIBS) $(DBUS_LIBS) -lreadline
diff --git a/client/cs.c b/client/cs.c
new file mode 100644
index 000000000..89251b502
--- /dev/null
+++ b/client/cs.c
@@ -0,0 +1,1157 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "gdbus/gdbus.h"
+#include "src/shared/shell.h"
+#include "src/shared/util.h"
+#include "cs.h"
+
+static GList * cs_proxies;
+static GList **cs_device_list;
+static DBusConnection *dbus_conn;
+
+#define RANGING_INTERFACE "org.bluez.ChannelSoundingRanging1"
+#define RANGE_ESTIMATE     "RangeEstimate"
+
+/* One signal watch per device proxy, so each device's RangeEstimate
+ * watch can be independently added/removed instead of clobbering a
+ * single shared handle.
+ */
+struct cs_watch {
+	GDBusProxy *proxy;
+	guint watch_id;
+};
+
+static GList *cs_watches;
+
+/* ---- Per-device active session ---- */
+
+struct cs_session {
+	GDBusProxy *proxy;
+};
+
+static GList *cs_sessions;
+
+static struct cs_session *cs_find_session(GDBusProxy *proxy);
+
+/* ---- Parameter state (used to build the StartMeasurement dict) ---- */
+
+static uint8_t cs_role        = 0x03;
+static uint8_t cs_sync_ant    = 0xFF;
+static int8_t  cs_max_tx_power = 0x14;
+
+static struct {
+	uint8_t config_id;
+	uint8_t main_mode_type;
+	uint8_t sub_mode_type;
+	uint8_t main_mode_min_steps;
+	uint8_t main_mode_max_steps;
+	uint8_t main_mode_repetition;
+	uint8_t mode0_steps;
+	uint8_t role;
+	uint8_t rtt_types;
+	uint8_t cs_sync_phy;
+	uint8_t channel_map[10];
+	uint8_t channel_map_repetition;
+	uint8_t channel_selection_type;
+	uint8_t channel_shape;
+	uint8_t channel_jump;
+	uint8_t companion_signal_enable;
+} cs_cfg = {
+	.config_id               = 0x00,
+	.main_mode_type          = 0x01,
+	.sub_mode_type           = 0xFF,
+	.main_mode_min_steps     = 0x02,
+	.main_mode_max_steps     = 0x03,
+	.main_mode_repetition    = 0x01,
+	.mode0_steps             = 0x02,
+	.role                    = 0x00,
+	.rtt_types               = 0x00,
+	.cs_sync_phy             = 0x01,
+	.channel_map             = { 0xFC, 0xFF, 0x7F, 0xFC, 0xFF,
+				     0xFF, 0xFF, 0xFF, 0xFF, 0x1F },
+	.channel_map_repetition  = 0x01,
+	.channel_selection_type  = 0x00,
+	.channel_shape           = 0x00,
+	.channel_jump            = 0x02,
+	.companion_signal_enable = 0x00,
+};
+
+static struct {
+	uint16_t max_procedure_duration;
+	uint16_t min_period_between_procedures;
+	uint16_t max_period_between_procedures;
+	uint16_t max_procedure_count;
+	uint8_t  min_sub_event_len[3];
+	uint8_t  max_sub_event_len[3];
+	uint8_t  tone_antenna_config_selection;
+	uint8_t  phy;
+	uint8_t  tx_power_delta;
+	uint8_t  preferred_peer_antenna;
+	uint8_t  snr_control_initiator;
+	uint8_t  snr_control_reflector;
+} cs_freq = {
+	.max_procedure_duration        = 0x0640,
+	.min_period_between_procedures = 0x001E,
+	.max_period_between_procedures = 0x0096,
+	.max_procedure_count           = 0x0000,
+	.min_sub_event_len             = { 0x00, 0x20, 0x00 },
+	.max_sub_event_len             = { 0x03, 0x20, 0x00 },
+	.tone_antenna_config_selection = 0x07,
+	.phy                           = 0x01,
+	.tx_power_delta                = 0x80,
+	.preferred_peer_antenna        = 0x03,
+	.snr_control_initiator         = 0xFF,
+	.snr_control_reflector         = 0xFF,
+};
+
+enum cs_param_type {
+	CS_PARAM_U8,
+	CS_PARAM_U8_RANGE,
+	CS_PARAM_U16,
+};
+
+struct cs_param_desc {
+	const char *name;
+	enum cs_param_type type;
+	void *field;
+	unsigned long min;
+	unsigned long max;
+	const char *range_error;
+};
+
+static const struct cs_param_desc cs_param_table[] = {
+	{ .name = "sync_ant_sel", .type = CS_PARAM_U8, .field = &cs_sync_ant },
+	{ .name = "config_id", .type = CS_PARAM_U8,
+		.field = &cs_cfg.config_id },
+	{ .name = "main_mode_type", .type = CS_PARAM_U8,
+		.field = &cs_cfg.main_mode_type },
+	{ .name = "sub_mode_type", .type = CS_PARAM_U8,
+		.field = &cs_cfg.sub_mode_type },
+	{ .name = "main_mode_min_steps", .type = CS_PARAM_U8,
+		.field = &cs_cfg.main_mode_min_steps },
+	{ .name = "main_mode_max_steps", .type = CS_PARAM_U8,
+		.field = &cs_cfg.main_mode_max_steps },
+	{ .name = "main_mode_repetition", .type = CS_PARAM_U8,
+		.field = &cs_cfg.main_mode_repetition },
+	{ .name = "mode0_steps", .type = CS_PARAM_U8,
+		.field = &cs_cfg.mode0_steps },
+	{ .name = "rtt_types", .type = CS_PARAM_U8,
+		.field = &cs_cfg.rtt_types },
+	{ .name = "role", .type = CS_PARAM_U8_RANGE, .field = &cs_role,
+		.min = 0x01, .max = 0x03,
+		.range_error = "role: 01=Initiator 02=Reflector 03=Both\n" },
+	{ .name = "sync_phy", .type = CS_PARAM_U8_RANGE,
+		.field = &cs_cfg.cs_sync_phy, .min = 0x01, .max = 0x02,
+		.range_error = "sync_phy: 0x01=LE 1M 0x02=LE 2M\n" },
+	{ .name = "channel_map_repetition", .type = CS_PARAM_U8,
+		.field = &cs_cfg.channel_map_repetition },
+	{ .name = "channel_selection_type", .type = CS_PARAM_U8,
+		.field = &cs_cfg.channel_selection_type },
+	{ .name = "channel_shape", .type = CS_PARAM_U8,
+		.field = &cs_cfg.channel_shape },
+	{ .name = "channel_jump", .type = CS_PARAM_U8,
+		.field = &cs_cfg.channel_jump },
+	{ .name = "companion_signal_enable", .type = CS_PARAM_U8_RANGE,
+		.field = &cs_cfg.companion_signal_enable, .min = 0, .max = 1,
+		.range_error = "companion_signal_enable: 0 or 1\n" },
+	{ .name = "max_procedure_duration", .type = CS_PARAM_U16,
+		.field = &cs_freq.max_procedure_duration },
+	{ .name = "min_period_between_procedures", .type = CS_PARAM_U16,
+		.field = &cs_freq.min_period_between_procedures },
+	{ .name = "max_period_between_procedures", .type = CS_PARAM_U16,
+		.field = &cs_freq.max_period_between_procedures },
+	{ .name = "max_procedure_count", .type = CS_PARAM_U16,
+		.field = &cs_freq.max_procedure_count },
+	{ .name = "tone_antenna_config_selection", .type = CS_PARAM_U8,
+		.field = &cs_freq.tone_antenna_config_selection },
+	{ .name = "phy", .type = CS_PARAM_U8_RANGE, .field = &cs_freq.phy,
+		.min = 0x01, .max = 0x02,
+		.range_error = "phy: 0x01=LE 1M  0x02=LE 2M\n" },
+	{ .name = "tx_power_delta", .type = CS_PARAM_U8,
+		.field = &cs_freq.tx_power_delta },
+	{ .name = "preferred_peer_antenna", .type = CS_PARAM_U8,
+		.field = &cs_freq.preferred_peer_antenna },
+	{ .name = "snr_control_initiator", .type = CS_PARAM_U8,
+		.field = &cs_freq.snr_control_initiator },
+	{ .name = "snr_control_reflector", .type = CS_PARAM_U8,
+		.field = &cs_freq.snr_control_reflector },
+};
+
+static gboolean range_estimate_cb(DBusConnection *connection,
+					DBusMessage *msg, void *user_data)
+{
+	GDBusProxy *proxy = user_data;
+	DBusMessageIter iter;
+	double distance;
+	uint8_t confidence;
+
+	if (!dbus_message_iter_init(msg, &iter))
+		return TRUE;
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_DOUBLE)
+		return TRUE;
+
+	dbus_message_iter_get_basic(&iter, &distance);
+	dbus_message_iter_next(&iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BYTE)
+		return TRUE;
+
+	dbus_message_iter_get_basic(&iter, &confidence);
+
+	bt_shell_printf("[CS] %s Distance: %.3f m  Confidence: %u%%\n",
+			g_dbus_proxy_get_path(proxy), distance, confidence);
+
+	return TRUE;
+}
+
+static struct cs_watch *cs_find_watch(GDBusProxy *proxy)
+{
+	struct cs_watch *w;
+	GList *list;
+
+	for (list = g_list_first(cs_watches); list; list = g_list_next(list)) {
+		w = list->data;
+
+		if (w->proxy == proxy)
+			return w;
+	}
+
+	return NULL;
+}
+
+void cs_proxy_added(GDBusProxy *proxy)
+{
+	struct cs_watch *w;
+
+	cs_proxies = g_list_append(cs_proxies, proxy);
+
+	if (!dbus_conn)
+		dbus_conn = bt_shell_get_env("DBUS_CONNECTION");
+
+	if (!dbus_conn)
+		return;
+
+	w = g_new0(struct cs_watch, 1);
+	w->proxy = proxy;
+	w->watch_id = g_dbus_add_signal_watch(dbus_conn, NULL,
+					g_dbus_proxy_get_path(proxy),
+					RANGING_INTERFACE, RANGE_ESTIMATE,
+					range_estimate_cb, proxy, NULL);
+	cs_watches = g_list_append(cs_watches, w);
+}
+
+void cs_proxy_removed(GDBusProxy *proxy)
+{
+	struct cs_session *s;
+	struct cs_watch *w;
+	GList *list;
+
+	cs_proxies = g_list_remove(cs_proxies, proxy);
+
+	for (list = g_list_first(cs_sessions); list;
+	     list = g_list_next(list)) {
+		s = list->data;
+
+		if (s->proxy == proxy) {
+			cs_sessions = g_list_remove(cs_sessions, s);
+			g_free(s);
+			break;
+		}
+	}
+
+	w = cs_find_watch(proxy);
+	if (w) {
+		g_dbus_remove_watch(dbus_conn, w->watch_id);
+		cs_watches = g_list_remove(cs_watches, w);
+		g_free(w);
+	}
+}
+
+/* Drop any active CS session for a device proxy path on disconnect. */
+void cs_device_disconnected(const char *dev_path)
+{
+	struct cs_session *s;
+	GList *list;
+
+	for (list = g_list_first(cs_sessions); list;
+	     list = g_list_next(list)) {
+		s = list->data;
+
+		if (!strcmp(g_dbus_proxy_get_path(s->proxy), dev_path)) {
+			bt_shell_printf("Measurement stopped (disconnected)"
+					" on %s\n", dev_path);
+			cs_sessions = g_list_remove(cs_sessions, s);
+			g_free(s);
+			break;
+		}
+	}
+}
+
+/* Drop active CS session when the daemon reports the measurement stopped. */
+void cs_measurement_stopped(GDBusProxy *proxy)
+{
+	struct cs_session *s = cs_find_session(proxy);
+
+	if (!s)
+		return;
+
+	bt_shell_printf("Measurement stopped (timer expired) on %s\n",
+			g_dbus_proxy_get_path(proxy));
+	cs_sessions = g_list_remove(cs_sessions, s);
+	g_free(s);
+}
+
+/* Record a measurement started by the remote side (Reflector role). */
+void cs_measurement_started(GDBusProxy *proxy)
+{
+	struct cs_session *s;
+
+	if (cs_find_session(proxy))
+		return;
+
+	s = g_new0(struct cs_session, 1);
+	s->proxy = proxy;
+	cs_sessions = g_list_append(cs_sessions, s);
+
+	bt_shell_printf("Measurement started on %s\n",
+			g_dbus_proxy_get_path(proxy));
+}
+
+void cs_set_device_list(GList **devices)
+{
+	cs_device_list = devices;
+}
+
+/* Resolve a Bluetooth address to the device's D-Bus object path. */
+static const char *cs_resolve_address(const char *address)
+{
+	GDBusProxy *proxy;
+	DBusMessageIter iter;
+	const char *str;
+	GList *list;
+
+	if (!cs_device_list) {
+		bt_shell_printf("DBG: cs_device_list is NULL\n");
+		return NULL;
+	}
+
+	if (!*cs_device_list) {
+		bt_shell_printf("DBG: *cs_device_list is empty\n");
+		return NULL;
+	}
+
+	for (list = g_list_first(*cs_device_list); list;
+	     list = g_list_next(list)) {
+		proxy = list->data;
+
+		if (!g_dbus_proxy_get_property(proxy, "Address", &iter)) {
+			bt_shell_printf("DBG: proxy %s has no Address\n",
+					g_dbus_proxy_get_path(proxy));
+			continue;
+		}
+
+		dbus_message_iter_get_basic(&iter, &str);
+
+		if (!strcasecmp(str, address))
+			return g_dbus_proxy_get_path(proxy);
+	}
+
+	return NULL;
+}
+
+/* Find the ChannelSounding1 proxy for the device at the given object path. */
+static GDBusProxy *cs_find_proxy(const char *dev_path)
+{
+	GDBusProxy *proxy;
+	const char *path;
+	GList *list;
+
+	if (!cs_proxies) {
+		bt_shell_printf("DBG: cs_proxies is empty\n");
+		return NULL;
+	}
+
+	for (list = g_list_first(cs_proxies); list;
+	     list = g_list_next(list)) {
+		proxy = list->data;
+		path = g_dbus_proxy_get_path(proxy);
+
+		if (!strcmp(path, dev_path))
+			return proxy;
+	}
+
+	return NULL;
+}
+
+static struct cs_session *cs_find_session(GDBusProxy *proxy)
+{
+	struct cs_session *s;
+	GList *list;
+
+	for (list = g_list_first(cs_sessions); list;
+	     list = g_list_next(list)) {
+		s = list->data;
+
+		if (s->proxy == proxy)
+			return s;
+	}
+
+	return NULL;
+}
+
+/* ---- dict helpers ---- */
+
+static void dict_append_byte(DBusMessageIter *dict, const char *key,
+			     uint8_t val)
+{
+	DBusMessageIter entry, variant;
+
+	dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+					 NULL, &entry);
+	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+	dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+					 DBUS_TYPE_BYTE_AS_STRING, &variant);
+	dbus_message_iter_append_basic(&variant, DBUS_TYPE_BYTE, &val);
+	dbus_message_iter_close_container(&entry, &variant);
+	dbus_message_iter_close_container(dict, &entry);
+}
+
+static void dict_append_uint16(DBusMessageIter *dict, const char *key,
+			       uint16_t val)
+{
+	DBusMessageIter entry, variant;
+
+	dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+					 NULL, &entry);
+	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+	dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+					 "q", &variant);
+	dbus_message_iter_append_basic(&variant, DBUS_TYPE_UINT16, &val);
+	dbus_message_iter_close_container(&entry, &variant);
+	dbus_message_iter_close_container(dict, &entry);
+}
+
+static void dict_append_uint32(DBusMessageIter *dict, const char *key,
+			       uint32_t val)
+{
+	DBusMessageIter entry, variant;
+
+	dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+					 NULL, &entry);
+	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+	dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+					 "u", &variant);
+	dbus_message_iter_append_basic(&variant, DBUS_TYPE_UINT32, &val);
+	dbus_message_iter_close_container(&entry, &variant);
+	dbus_message_iter_close_container(dict, &entry);
+}
+
+static void dict_append_byte_array(DBusMessageIter *dict, const char *key,
+				   const uint8_t *bytes, int len)
+{
+	DBusMessageIter entry, variant, array;
+
+	dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+					 NULL, &entry);
+	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+	dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+					 "ay", &variant);
+	dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
+					 DBUS_TYPE_BYTE_AS_STRING, &array);
+	dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
+					     &bytes, len);
+	dbus_message_iter_close_container(&variant, &array);
+	dbus_message_iter_close_container(&entry, &variant);
+	dbus_message_iter_close_container(dict, &entry);
+}
+
+/* ---- start ---- */
+
+static uint32_t pending_duration_secs;
+static const char *pending_dev_path;
+
+static void start_measurement_setup(DBusMessageIter *iter, void *user_data)
+{
+	DBusMessageIter dict;
+	uint8_t tx = (uint8_t)cs_max_tx_power;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+					 "{sv}", &dict);
+
+	/* timing */
+	dict_append_uint32(&dict, "duration_secs", pending_duration_secs);
+
+	/* default settings */
+	dict_append_byte(&dict, "role",            cs_role);
+	dict_append_byte(&dict, "sync_ant_sel", cs_sync_ant);
+	dict_append_byte(&dict, "max_tx_power",    tx);
+
+	/* CS config */
+	dict_append_byte(&dict, "config_id",
+			 cs_cfg.config_id);
+	dict_append_byte(&dict, "main_mode_type",
+			 cs_cfg.main_mode_type);
+	dict_append_byte(&dict, "sub_mode_type",
+			 cs_cfg.sub_mode_type);
+	dict_append_byte(&dict, "main_mode_min_steps",
+			 cs_cfg.main_mode_min_steps);
+	dict_append_byte(&dict, "main_mode_max_steps",
+			 cs_cfg.main_mode_max_steps);
+	dict_append_byte(&dict, "main_mode_repetition",
+			 cs_cfg.main_mode_repetition);
+	dict_append_byte(&dict, "mode0_steps",
+			 cs_cfg.mode0_steps);
+	dict_append_byte(&dict, "rtt_types",
+			 cs_cfg.rtt_types);
+	dict_append_byte(&dict, "sync_phy",
+			 cs_cfg.cs_sync_phy);
+	dict_append_byte_array(&dict, "channel_map",
+			       cs_cfg.channel_map, 10);
+	dict_append_byte(&dict, "channel_map_repetition",
+			 cs_cfg.channel_map_repetition);
+	dict_append_byte(&dict, "channel_selection_type",
+			 cs_cfg.channel_selection_type);
+	dict_append_byte(&dict, "channel_shape",
+			 cs_cfg.channel_shape);
+	dict_append_byte(&dict, "channel_jump",
+			 cs_cfg.channel_jump);
+	dict_append_byte(&dict, "companion_signal_enable",
+			 cs_cfg.companion_signal_enable);
+
+	/* CS frequency */
+	dict_append_uint16(&dict, "max_procedure_duration",
+			   cs_freq.max_procedure_duration);
+	dict_append_uint16(&dict, "min_period_between_procedures",
+			   cs_freq.min_period_between_procedures);
+	dict_append_uint16(&dict, "max_period_between_procedures",
+			   cs_freq.max_period_between_procedures);
+	dict_append_uint16(&dict, "max_procedure_count",
+			   cs_freq.max_procedure_count);
+	dict_append_byte_array(&dict, "min_sub_event_len",
+			       cs_freq.min_sub_event_len, 3);
+	dict_append_byte_array(&dict, "max_sub_event_len",
+			       cs_freq.max_sub_event_len, 3);
+	dict_append_byte(&dict, "tone_antenna_config_selection",
+			 cs_freq.tone_antenna_config_selection);
+	dict_append_byte(&dict, "phy",
+			 cs_freq.phy);
+	dict_append_byte(&dict, "tx_power_delta",
+			 cs_freq.tx_power_delta);
+	dict_append_byte(&dict, "preferred_peer_antenna",
+			 cs_freq.preferred_peer_antenna);
+	dict_append_byte(&dict, "snr_control_initiator",
+			 cs_freq.snr_control_initiator);
+	dict_append_byte(&dict, "snr_control_reflector",
+			 cs_freq.snr_control_reflector);
+
+	dbus_message_iter_close_container(iter, &dict);
+}
+
+/* ---- cs_set_param: apply name=value to the local parameter state ---- */
+static bool parse_hex_bytes(const char *name, const char *valstr,
+					uint8_t *out, unsigned int count)
+{
+	const char *str = valstr;
+	char *endptr;
+	unsigned long uval;
+	unsigned int i = 0;
+
+	while (i < count) {
+		uval = strtoul(str, &endptr, 16);
+		if (endptr == str || uval > 0xFF) {
+			bt_shell_printf("%s: invalid byte at index %u\n",
+					name, i);
+			return false;
+		}
+		out[i++] = (uint8_t)uval;
+		if (*endptr == '\0')
+			break;
+		if (*endptr != ':') {
+			bt_shell_printf("%s: expected ':' separator\n", name);
+			return false;
+		}
+		str = endptr + 1;
+	}
+
+	if (i != count) {
+		bt_shell_printf("%s: need exactly %u colon-separated hex"
+				" bytes\n", name, count);
+		return false;
+	}
+
+	return true;
+}
+
+static const struct cs_param_desc *cs_find_param_desc(const char *name)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(cs_param_table); i++) {
+		if (!strcmp(cs_param_table[i].name, name))
+			return &cs_param_table[i];
+	}
+
+	return NULL;
+}
+
+static bool cs_set_param(const char *name, const char *valstr)
+{
+	const struct cs_param_desc *desc;
+	char *endptr;
+	unsigned long uval;
+	long sval;
+
+	/* Byte-array: channel_map — 10 colon-separated hex bytes */
+	if (strcmp(name, "channel_map") == 0) {
+		if (!parse_hex_bytes(name, valstr, cs_cfg.channel_map, 10))
+			return false;
+		return true;
+	}
+
+	/* Byte-array: min/max_sub_event_len — 3 colon-separated hex bytes */
+	if (strcmp(name, "min_sub_event_len") == 0)
+		return parse_hex_bytes(name, valstr,
+					cs_freq.min_sub_event_len, 3);
+	if (strcmp(name, "max_sub_event_len") == 0)
+		return parse_hex_bytes(name, valstr,
+					cs_freq.max_sub_event_len, 3);
+
+	/* max_tx_power is signed (-127 to +20 dBm) */
+	if (strcmp(name, "max_tx_power") == 0) {
+		sval = strtol(valstr, &endptr, 0);
+
+		if (*endptr != '\0' || sval < -127 || sval > 20) {
+			bt_shell_printf("max_tx_power: valid range -127"
+					" to 20 dBm\n");
+			return false;
+		}
+		cs_max_tx_power = (int8_t)sval;
+		return true;
+	}
+
+	desc = cs_find_param_desc(name);
+	if (!desc) {
+		bt_shell_printf("Unknown parameter: %s\n", name);
+		return false;
+	}
+
+	/* All remaining parameters are unsigned */
+	uval = strtoul(valstr, &endptr, 0);
+	if (*endptr != '\0') {
+		bt_shell_printf("%s: invalid value '%s'\n", name, valstr);
+		return false;
+	}
+
+	if (desc->type == CS_PARAM_U8_RANGE &&
+			(uval < desc->min || uval > desc->max)) {
+		bt_shell_printf("%s", desc->range_error);
+		return false;
+	}
+
+	if (desc->type == CS_PARAM_U16)
+		*(uint16_t *)desc->field = (uint16_t)uval;
+	else
+		*(uint8_t *)desc->field = (uint8_t)uval;
+
+	return true;
+}
+
+static void start_measurement_reply(DBusMessage *message, void *user_data)
+{
+	GDBusProxy *proxy = user_data;
+	struct cs_session *s;
+	DBusError error;
+
+	dbus_error_init(&error);
+	if (dbus_set_error_from_message(&error, message)) {
+		bt_shell_printf("StartMeasurement failed: %s\n", error.message);
+		dbus_error_free(&error);
+		return;
+	}
+
+	if (cs_role == 0x02) {
+		bt_shell_printf("Default settings applied on %s;"
+				" Reflector role does not start a local"
+				" measurement\n",
+				g_dbus_proxy_get_path(proxy));
+		return;
+	}
+
+	s = g_new0(struct cs_session, 1);
+	s->proxy    = proxy;
+	cs_sessions = g_list_append(cs_sessions, s);
+
+	bt_shell_printf("Measurement started on %s\n",
+			g_dbus_proxy_get_path(proxy));
+}
+
+static void cs_print_role_hint(uint8_t role)
+{
+	if (role == 0x02)
+		bt_shell_printf("Note: Reflector role only uses"
+				" role/cs_sync_ant_sel/max_tx_power;"
+				" other CS config/frequency parameters"
+				" are ignored.\n");
+	else
+		bt_shell_printf("Note: Initiator role requires dev_addr"
+				" and duration_secs; CS config/frequency"
+				" parameters configure the measurement"
+				" procedure.\n");
+}
+
+/* Generic handler for the per-parameter set commands (cs.role,
+ * cs.main_mode_type, ...); argv[0] is the parameter name (the command
+ * itself), argv[1] is the value.
+ */
+static void cmd_cs_set(int argc, char *argv[])
+{
+	if (argc < 2) {
+		bt_shell_printf("Usage: %s <value>\n", argv[0]);
+		return;
+	}
+
+	if (!cs_set_param(argv[0], argv[1]))
+		return;
+
+	if (!strcmp(argv[0], "role"))
+		cs_print_role_hint(cs_role);
+}
+
+/* Tab completion for params whose only legal values are a small fixed
+ * enum, so users don't need to consult documentation to know what's
+ * valid.
+ */
+static char *cs_value_generator(const char *text, int state,
+					const char * const values[])
+{
+	static unsigned int index, len;
+	const char *value;
+
+	if (!state) {
+		index = 0;
+		len = strlen(text);
+	}
+
+	while ((value = values[index])) {
+		index++;
+
+		if (!strncmp(value, text, len))
+			return strdup(value);
+	}
+
+	return NULL;
+}
+
+static const char * const cs_role_values[] = { "0x01", "0x02", "0x03", NULL };
+
+static char *cs_role_generator(const char *text, int state)
+{
+	return cs_value_generator(text, state, cs_role_values);
+}
+
+static const char * const cs_main_mode_type_values[] = { "1", "2", "3", NULL };
+
+static char *cs_main_mode_type_generator(const char *text, int state)
+{
+	return cs_value_generator(text, state, cs_main_mode_type_values);
+}
+
+static const char * const cs_phy_values[] = { "0x01", "0x02", NULL };
+
+static char *cs_phy_generator(const char *text, int state)
+{
+	return cs_value_generator(text, state, cs_phy_values);
+}
+
+static const char * const cs_bool_values[] = { "0", "1", NULL };
+
+static char *cs_bool_generator(const char *text, int state)
+{
+	return cs_value_generator(text, state, cs_bool_values);
+}
+
+static const char * const cs_sub_mode_type_values[] = { "0x01", "0x02",
+							"0x03", "0xFF", NULL };
+
+static char *cs_sub_mode_type_generator(const char *text, int state)
+{
+	return cs_value_generator(text, state, cs_sub_mode_type_values);
+}
+
+static void cmd_cs_start(int argc, char *argv[])
+{
+	GDBusProxy *proxy;
+	char *endptr;
+	unsigned long val;
+
+	pending_duration_secs = 0;
+	pending_dev_path = NULL;
+
+	if (argc >= 2) {
+		pending_dev_path = cs_resolve_address(argv[1]);
+		if (!pending_dev_path) {
+			bt_shell_printf("Device %s not found\n", argv[1]);
+			return;
+		}
+	}
+
+	if (argc >= 3) {
+		val = strtoul(argv[2], &endptr, 0);
+
+		if (*endptr != '\0') {
+			bt_shell_printf("Invalid duration: %s\n", argv[2]);
+			return;
+		}
+		pending_duration_secs = (uint32_t)val;
+	}
+
+	if (argc > 3) {
+		bt_shell_printf("Too many arguments\n");
+		return;
+	}
+
+	cs_print_role_hint(cs_role);
+
+	if (pending_dev_path) {
+		proxy = cs_find_proxy(pending_dev_path);
+		if (!proxy) {
+			bt_shell_printf("No ChannelSounding1 interface for"
+					" that device\n");
+			return;
+		}
+	} else {
+		if (!cs_proxies) {
+			bt_shell_printf("No ChannelSounding1 interface"
+					" available\n");
+			return;
+		}
+		proxy = cs_proxies->data;
+	}
+
+	if (cs_find_session(proxy)) {
+		bt_shell_printf("Measurement already active on %s\n",
+				g_dbus_proxy_get_path(proxy));
+		return;
+	}
+
+	if (!g_dbus_proxy_method_call(proxy, "StartMeasurement",
+				      start_measurement_setup,
+				      start_measurement_reply, proxy, NULL))
+		bt_shell_printf("Failed to send StartMeasurement\n");
+}
+
+/* ---- stop ---- */
+
+static void stop_measurement_reply(DBusMessage *message, void *user_data)
+{
+	struct cs_session *s = user_data;
+	DBusError error;
+
+	dbus_error_init(&error);
+	if (dbus_set_error_from_message(&error, message)) {
+		bt_shell_printf("StopMeasurement failed: %s\n", error.message);
+		dbus_error_free(&error);
+		return;
+	}
+
+	bt_shell_printf("Measurement stopped on %s\n",
+			g_dbus_proxy_get_path(s->proxy));
+	cs_sessions = g_list_remove(cs_sessions, s);
+	g_free(s);
+}
+
+static void cmd_cs_stop(int argc, char *argv[])
+{
+	const char *dev_path;
+	struct cs_session *s;
+	GDBusProxy *proxy;
+
+	if (argc >= 2) {
+		dev_path = cs_resolve_address(argv[1]);
+
+		if (!dev_path) {
+			bt_shell_printf("Device %s not found\n", argv[1]);
+			return;
+		}
+		proxy = cs_find_proxy(dev_path);
+		if (!proxy) {
+			bt_shell_printf("No ChannelSounding1 interface for"
+					" that device\n");
+			return;
+		}
+		s = cs_find_session(proxy);
+		if (!s) {
+			bt_shell_printf("No active measurement on %s\n",
+					argv[1]);
+			return;
+		}
+	} else {
+		if (!cs_sessions) {
+			bt_shell_printf("No active measurements\n");
+			return;
+		}
+		if (g_list_length(cs_sessions) > 1) {
+			bt_shell_printf("Multiple active measurements —"
+					" specify device address\n");
+			return;
+		}
+		s = cs_sessions->data;
+	}
+
+	if (!g_dbus_proxy_method_call(s->proxy, "StopMeasurement",
+				      NULL,
+				      stop_measurement_reply, s, NULL))
+		bt_shell_printf("Failed to send StopMeasurement\n");
+}
+
+/* ---- show ---- */
+
+static void cmd_cs_show(int argc, char *argv[])
+{
+	struct cs_session *s;
+	size_t j;
+	GList *list;
+
+	bt_shell_printf("Active measurements:\n");
+	if (!cs_sessions) {
+		bt_shell_printf("  none\n");
+	} else {
+		for (list = g_list_first(cs_sessions); list;
+		     list = g_list_next(list)) {
+			s = list->data;
+
+			bt_shell_printf("  %s\n",
+					g_dbus_proxy_get_path(s->proxy));
+		}
+	}
+
+	bt_shell_printf("\n=== Default Settings ===\n");
+	bt_shell_printf("  role           : %u"
+			" (1=Initiator 2=Reflector 3=Both)\n", cs_role);
+	bt_shell_printf("  sync_ant_sel   : 0x%02x\n", cs_sync_ant);
+	bt_shell_printf("  max_tx_power   : %d dBm\n", cs_max_tx_power);
+
+	bt_shell_printf("\n=== CS Config Params ===\n");
+	bt_shell_printf("  config_id               : %u\n",
+			cs_cfg.config_id);
+	bt_shell_printf("  main_mode_type          : 0x%02x\n",
+			cs_cfg.main_mode_type);
+	bt_shell_printf("  sub_mode_type           : 0x%02x\n",
+			cs_cfg.sub_mode_type);
+	bt_shell_printf("  main_mode_min_steps     : %u\n",
+			cs_cfg.main_mode_min_steps);
+	bt_shell_printf("  main_mode_max_steps     : %u\n",
+			cs_cfg.main_mode_max_steps);
+	bt_shell_printf("  main_mode_repetition    : %u\n",
+			cs_cfg.main_mode_repetition);
+	bt_shell_printf("  mode0_steps             : %u\n",
+			cs_cfg.mode0_steps);
+	bt_shell_printf("  configured role         : %u\n",
+			cs_cfg.role);
+	bt_shell_printf("  rtt_types               : %u\n",
+			cs_cfg.rtt_types);
+	bt_shell_printf("  sync_phy                : %u\n",
+			cs_cfg.cs_sync_phy);
+	bt_shell_printf("  channel_map             :");
+	for (j = 0; j < 10; j++)
+		bt_shell_printf(" %02x", cs_cfg.channel_map[j]);
+	bt_shell_printf("\n");
+	bt_shell_printf("  channel_map_repetition  : %u\n",
+			cs_cfg.channel_map_repetition);
+	bt_shell_printf("  channel_selection_type  : %u\n",
+			cs_cfg.channel_selection_type);
+	bt_shell_printf("  channel_shape           : %u\n",
+			cs_cfg.channel_shape);
+	bt_shell_printf("  channel_jump            : %u\n",
+			cs_cfg.channel_jump);
+	bt_shell_printf("  companion_signal_enable : %u\n",
+			cs_cfg.companion_signal_enable);
+
+	bt_shell_printf("\n=== CS Frequency Params ===\n");
+	bt_shell_printf("  max_procedure_duration        : %u\n",
+			cs_freq.max_procedure_duration);
+	bt_shell_printf("  min_period_between_procedures : %u\n",
+			cs_freq.min_period_between_procedures);
+	bt_shell_printf("  max_period_between_procedures : %u\n",
+			cs_freq.max_period_between_procedures);
+	bt_shell_printf("  max_procedure_count           : %u\n",
+			cs_freq.max_procedure_count);
+	bt_shell_printf("  min_sub_event_len             : %02x %02x %02x\n",
+			cs_freq.min_sub_event_len[0],
+			cs_freq.min_sub_event_len[1],
+			cs_freq.min_sub_event_len[2]);
+	bt_shell_printf("  max_sub_event_len             : %02x %02x %02x\n",
+			cs_freq.max_sub_event_len[0],
+			cs_freq.max_sub_event_len[1],
+			cs_freq.max_sub_event_len[2]);
+	bt_shell_printf("  tone_antenna_config_selection : 0x%02x\n",
+			cs_freq.tone_antenna_config_selection);
+	bt_shell_printf("  phy                           : 0x%02x\n",
+			cs_freq.phy);
+	bt_shell_printf("  tx_power_delta                : 0x%02x\n",
+			cs_freq.tx_power_delta);
+	bt_shell_printf("  preferred_peer_antenna        : 0x%02x\n",
+			cs_freq.preferred_peer_antenna);
+	bt_shell_printf("  snr_control_initiator         : 0x%02x\n",
+			cs_freq.snr_control_initiator);
+	bt_shell_printf("  snr_control_reflector         : 0x%02x\n",
+			cs_freq.snr_control_reflector);
+}
+
+static const struct bt_shell_menu cs_menu = {
+	.name = "cs",
+	.desc = "Channel Sounding Submenu",
+	.entries = {
+	{ "start",  "[dev_addr] [duration_secs]",
+				cmd_cs_start,
+				"Start distance measurement using the"
+				" current parameters (see cs.<param>"
+				" commands below).\n"
+				"\t\t\t\t\t\tInitiator (role 0x01/0x03): requires"
+				" dev_addr and duration_secs.\n"
+				"\t\t\t\t\t\tReflector (role 0x02): dev_addr/"
+				"duration_secs are ignored, and no local"
+				" measurement is started.",
+				NULL },
+	{ "stop",   "[dev_addr]",
+				cmd_cs_stop,
+				"Stop the active distance measurement;"
+				" address required when multiple are active" },
+	{ "show",   NULL,
+				cmd_cs_show,
+				"Show active session id and current"
+				" CS parameters" },
+	{ "role", "<0x01|0x02|0x03>", cmd_cs_set,
+				"CS role: 0x01 Initiator, 0x02 Reflector,"
+				" 0x03 Both (default 0x03)",
+				cs_role_generator },
+	{ "sync_ant_sel", "<value>", cmd_cs_set,
+				"CS sync antenna selection; 0xFE/0xFF"
+				" reserved (default 0xFF)" },
+	{ "max_tx_power", "<-127..20>", cmd_cs_set,
+				"Max TX power in dBm, signed (default 20)" },
+	{ "config_id", "<value>", cmd_cs_set,
+				"CS configuration identifier (default 0)" },
+	{ "main_mode_type", "<1|2|3>", cmd_cs_set,
+				"1 Mode 1 (RTT), 2 Mode 2 (PBR), 3 Both"
+				" (default 1)",
+				cs_main_mode_type_generator },
+	{ "sub_mode_type", "<0x01|0x02|0x03|0xFF>", cmd_cs_set,
+				"Sub-mode within main mode; 0xFF = unused"
+				" (default 0xFF)",
+				cs_sub_mode_type_generator },
+	{ "main_mode_min_steps", "<value>", cmd_cs_set,
+				"Min CS main mode steps per subevent"
+				" (default 2)" },
+	{ "main_mode_max_steps", "<value>", cmd_cs_set,
+				"Max CS main mode steps per subevent"
+				" (default 3)" },
+	{ "main_mode_repetition", "<value>", cmd_cs_set,
+				"Times main mode steps are repeated in a"
+				" subevent (default 1)" },
+	{ "mode0_steps", "<value>", cmd_cs_set,
+				"CS Mode 0 steps at the beginning of each"
+				" subevent (default 2)" },
+	{ "rtt_types", "<value>", cmd_cs_set,
+				"RTT measurement types bitmask (default 0)" },
+	{ "sync_phy", "<0x01|0x02>", cmd_cs_set,
+				"PHY for CS sync: 0x01 LE 1M, 0x02 LE 2M"
+				" (default 0x01)",
+				cs_phy_generator },
+	{ "channel_map", "<10 colon-separated hex bytes>", cmd_cs_set,
+				"10-byte channel map bitmap"
+				" (default FC:FF:7F:FC:FF:FF:FF:FF:FF:1F)" },
+	{ "channel_map_repetition", "<value>", cmd_cs_set,
+				"Consecutive repetitions of the channel map"
+				" (default 1)" },
+	{ "channel_selection_type", "<value>", cmd_cs_set,
+				"CS channel selection algorithm (default 0)" },
+	{ "channel_shape", "<value>", cmd_cs_set,
+				"Shape used in channel selection algorithm"
+				" (default 0)" },
+	{ "channel_jump", "<value>", cmd_cs_set,
+				"Channel jump size (default 2)" },
+	{ "companion_signal_enable", "<0|1>", cmd_cs_set,
+				"1 to transmit companion signal, 0 to disable"
+				" (default 0)",
+				cs_bool_generator },
+	{ "min_sub_event_len", "<3 colon-separated hex bytes>", cmd_cs_set,
+				"Min CS subevent length, 3-byte LE"
+				" (default 00:20:00)" },
+	{ "max_sub_event_len", "<3 colon-separated hex bytes>", cmd_cs_set,
+				"Max CS subevent length, 3-byte LE"
+				" (default 03:20:00)" },
+	{ "max_procedure_duration", "<value>", cmd_cs_set,
+				"Maximum duration of one CS measurement"
+				" procedure (default 1600)" },
+	{ "min_period_between_procedures", "<value>", cmd_cs_set,
+				"Minimum time between consecutive procedures"
+				" (default 30)" },
+	{ "max_period_between_procedures", "<value>", cmd_cs_set,
+				"Maximum time between consecutive procedures"
+				" (default 150)" },
+	{ "max_procedure_count", "<value>", cmd_cs_set,
+				"Max number of procedures; 0 = no limit"
+				" (default 0)" },
+	{ "tone_antenna_config_selection", "<value>", cmd_cs_set,
+				"Antenna config for CS tone exchanges"
+				" (default 0x07)" },
+	{ "phy", "<0x01|0x02>", cmd_cs_set,
+				"PHY for CS procedures: 0x01 LE 1M, 0x02 LE 2M"
+				" (default 0x01)",
+				cs_phy_generator },
+	{ "tx_power_delta", "<value>", cmd_cs_set,
+				"Remote vs local TX power delta; 0x80 = not"
+				" applicable (default 0x80)" },
+	{ "preferred_peer_antenna", "<value>", cmd_cs_set,
+				"Preferred antenna for the peer device"
+				" (default 0x03)" },
+	{ "snr_control_initiator", "<value>", cmd_cs_set,
+				"SNR control for initiator; 0xFF = no"
+				" preference (default 0xFF)" },
+	{ "snr_control_reflector", "<value>", cmd_cs_set,
+				"SNR control for reflector; 0xFF = no"
+				" preference (default 0xFF)" },
+	{ NULL } },
+};
+
+void cs_add_submenu(void)
+{
+	bt_shell_add_submenu(&cs_menu);
+}
+
+void cs_remove_submenu(void)
+{
+	g_list_free_full(cs_sessions, g_free);
+	cs_sessions = NULL;
+
+	while (cs_watches) {
+		struct cs_watch *w = cs_watches->data;
+
+		g_dbus_remove_watch(dbus_conn, w->watch_id);
+		cs_watches = g_list_remove(cs_watches, w);
+		g_free(w);
+	}
+
+	g_list_free(cs_proxies);
+	cs_proxies = NULL;
+}
diff --git a/client/cs.h b/client/cs.h
new file mode 100644
index 000000000..8902c8143
--- /dev/null
+++ b/client/cs.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include "gdbus/gdbus.h"
+
+void cs_add_submenu(void);
+void cs_remove_submenu(void);
+
+void cs_proxy_added(GDBusProxy *proxy);
+void cs_proxy_removed(GDBusProxy *proxy);
+void cs_device_disconnected(const char *dev_path);
+void cs_measurement_started(GDBusProxy *proxy);
+void cs_measurement_stopped(GDBusProxy *proxy);
+void cs_set_device_list(GList **devices);
diff --git a/client/main.c b/client/main.c
index 9d9ac8b14..b5cad8afc 100644
--- a/client/main.c
+++ b/client/main.c
@@ -39,6 +39,7 @@
 #include "assistant.h"
 #include "hci.h"
 #include "telephony.h"
+#include "cs.h"
 
 /* String display constants */
 #define COLORED_NEW	COLOR_GREEN "NEW" COLOR_OFF
@@ -124,6 +125,7 @@ static void disconnect_handler(DBusConnection *connection, void *user_data)
 	battery_proxies = NULL;
 
 	default_ctrl = NULL;
+	cs_set_device_list(NULL);
 }
 
 static void print_adapter(GDBusProxy *proxy, const char *description)
@@ -391,8 +393,10 @@ static struct adapter *adapter_new(GDBusProxy *proxy)
 
 	ctrl_list = g_list_append(ctrl_list, adapter);
 
-	if (!default_ctrl)
+	if (!default_ctrl) {
 		default_ctrl = adapter;
+		cs_set_device_list(&adapter->devices);
+	}
 
 	return adapter;
 }
@@ -525,6 +529,8 @@ static void proxy_added(GDBusProxy *proxy, void *user_data)
 		bearer_added(proxy);
 	} else if (!strcmp(interface, "org.bluez.Bearer.LE1")) {
 		bearer_added(proxy);
+	} else if (!strcmp(interface, "org.bluez.ChannelSounding1")) {
+		cs_proxy_added(proxy);
 	}
 }
 
@@ -656,6 +662,8 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
 		bearer_removed(proxy);
 	} else if (!strcmp(interface, "org.bluez.Bearer.LE1")) {
 		bearer_removed(proxy);
+	} else if (!strcmp(interface, "org.bluez.ChannelSounding1")) {
+		cs_proxy_removed(proxy);
 	}
 }
 
@@ -729,6 +737,10 @@ static void property_changed(GDBusProxy *proxy, const char *name,
 				else if (!connected && default_dev == proxy)
 					set_default_device(NULL, NULL);
 
+				if (!connected)
+					cs_device_disconnected(
+						g_dbus_proxy_get_path(proxy));
+
 				/* If the device is connected and the filter
 				 * is auto_connect and it matches the pattern,
 				 * stop discovery.
@@ -821,6 +833,16 @@ static void property_changed(GDBusProxy *proxy, const char *name,
 			print_iter(str, name, iter);
 			g_free(str);
 		}
+	} else if (!strcmp(interface, "org.bluez.ChannelSounding1")) {
+		if (!strcmp(name, "Active")) {
+			dbus_bool_t active;
+
+			dbus_message_iter_get_basic(iter, &active);
+			if (active)
+				cs_measurement_started(proxy);
+			else
+				cs_measurement_stopped(proxy);
+		}
 	}
 }
 
@@ -1090,6 +1112,7 @@ static void cmd_select(int argc, char *argv[])
 		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 
 	default_ctrl = adapter;
+	cs_set_device_list(&adapter->devices);
 	print_adapter(adapter->proxy, NULL);
 
 	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
@@ -4003,6 +4026,7 @@ int main(int argc, char *argv[])
 	assistant_add_submenu();
 	hci_add_submenu();
 	telephony_add_submenu();
+	cs_add_submenu();
 	bt_shell_set_prompt(PROMPT_OFF, NULL);
 
 	bt_shell_handle_non_interactive_help();
@@ -4044,6 +4068,7 @@ int main(int argc, char *argv[])
 	assistant_remove_submenu();
 	hci_remove_submenu();
 	telephony_remove_submenu();
+	cs_remove_submenu();
 
 	g_dbus_client_unref(client);
 
-- 


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

* RE: Add Channel Sounding Dbus support and
  2026-07-12 12:17 ` [PATCH BlueZ v3 1/4] rap: Add Channel Sounding parameter types and APIs Naga Bhavani Akella
@ 2026-07-12 13:24   ` bluez.test.bot
  0 siblings, 0 replies; 7+ messages in thread
From: bluez.test.bot @ 2026-07-12 13:24 UTC (permalink / raw)
  To: linux-bluetooth, naga.akella

[-- Attachment #1: Type: text/plain, Size: 989 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/project/bluetooth/list/?series=1126078

---Test result---

Test Summary:
CheckPatch                    PASS      2.68 seconds
GitLint                       PASS      0.84 seconds
BuildEll                      PASS      21.10 seconds
BluezMake                     PASS      551.30 seconds
MakeCheck                     PASS      23.41 seconds
MakeDistcheck                 PASS      162.29 seconds
CheckValgrind                 PASS      231.67 seconds
CheckSmatch                   PASS      315.86 seconds
bluezmakeextell               PASS      102.37 seconds
IncrementalBuild              PASS      574.32 seconds
ScanBuild                     PASS      993.72 seconds



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

---
Regards,
Linux Bluetooth


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

end of thread, other threads:[~2026-07-12 13:24 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-12 12:17 [PATCH BlueZ v3 0/4] Add Channel Sounding Dbus support and Naga Bhavani Akella
2026-07-12 12:17 ` [PATCH BlueZ v3 1/4] rap: Add Channel Sounding parameter types and APIs Naga Bhavani Akella
2026-07-12 13:24   ` Add Channel Sounding Dbus support and bluez.test.bot
2026-07-12 12:17 ` [PATCH BlueZ v3 2/4] src: Register GATT profiles for Channel Sounding reflector Naga Bhavani Akella
2026-07-12 12:17 ` [PATCH BlueZ v3 3/4] profiles: Add D-Bus Channel Sounding control APIs Naga Bhavani Akella
2026-07-12 12:17 ` [PATCH BlueZ v3 4/4] client: Add Channel Sounding shell submenu Naga Bhavani Akella
  -- strict thread matches above, loose matches on Subject: below --
2026-07-10  9:49 [PATCH BlueZ v2 1/4] rap: Add Channel Sounding parameter types and APIs Naga Bhavani Akella
2026-07-10 11:57 ` Add Channel Sounding Dbus support and bluez.test.bot

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