* [PATCH BlueZ v1] bass: Fix crashing on BT_BASS_MOD_SRC
From: Luiz Augusto von Dentz @ 2026-04-14 16:16 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
If assistant attempt o modify source the code would attempt to iterate
over all valid range of BIS indexes which may lead to the following
trace since the delegator maybe freed in the process:
#0 queue_find (queue=<optimized out>, function=function@entry=0x58b8761109c0 <setup_match_bis>, match_data=match_data@entry=0x3) at src/shared/queue.c:230
#1 0x000058b8761127fb in bass_update_bis_sync (bcast_src=<optimized out>, dg=<optimized out>) at profiles/audio/bass.c:1824
#2 handle_mod_src_req (data=<optimized out>, params=<optimized out>, bcast_src=0x58b894661be0) at profiles/audio/bass.c:1862
#3 cp_handler (bcast_src=0x58b894661be0, op=<optimized out>, params=<optimized out>, user_data=<optimized out>) at profiles/audio/bass.c:1910
#4 0x000058b8761bc978 in bass_handle_mod_src_op (bass=<optimized out>, attrib=<optimized out>, opcode=<optimized out>, id=<optimized out>, iov=<optimized out>, att=<optimized out>)
at src/shared/bass.c:1069
To fix the code will now just interate at existing setups checking if
they match the BIS index then adding/removing the stream so it is no
longer possible to free the delegator before all setups are processed.
---
profiles/audio/bass.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/profiles/audio/bass.c b/profiles/audio/bass.c
index bf0db0555963..e3710ea04c2b 100644
--- a/profiles/audio/bass.c
+++ b/profiles/audio/bass.c
@@ -1865,21 +1865,21 @@ static bool setup_match_bis(const void *data, const void *match_data)
static void bass_update_bis_sync(struct bass_delegator *dg,
struct bt_bcast_src *bcast_src)
{
- for (int bis = 1; bis < ISO_MAX_NUM_BIS; bis++) {
- struct bass_setup *setup = queue_find(dg->setups,
- setup_match_bis, INT_TO_PTR(bis));
- uint8_t state;
+ struct queue_entry *entry;
- if (!setup)
- continue;
+ /* Check if existing setups if BIS needs to be added/removed */
+ for (entry = queue_get_entries(dg->setups); entry;
+ entry = entry->next) {
+ struct bass_setup *setup = entry->data;
+ uint8_t state;
state = bt_bap_stream_get_state(setup->stream);
- if (!setup->stream && bt_bass_check_bis(bcast_src, bis))
+ if (!setup->stream && bt_bass_check_bis(bcast_src, setup->bis))
bass_add_bis(setup);
else if (setup->stream &&
state == BT_BAP_STREAM_STATE_STREAMING &&
- !bt_bass_check_bis(bcast_src, bis))
+ !bt_bass_check_bis(bcast_src, setup->bis))
bass_remove_bis(setup);
}
}
--
2.53.0
^ permalink raw reply related
* RE: Add initial Channel Sounding Reflector
From: bluez.test.bot @ 2026-04-14 16:16 UTC (permalink / raw)
To: linux-bluetooth, naga.akella
In-Reply-To: <20260414150806.3135253-2-naga.akella@oss.qualcomm.com>
[-- Attachment #1: Type: text/plain, Size: 33363 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=1081191
---Test result---
Test Summary:
CheckPatch FAIL 1.76 seconds
GitLint PASS 3.36 seconds
BuildEll PASS 20.00 seconds
BluezMake FAIL 545.94 seconds
MakeCheck FAIL 167.58 seconds
MakeDistcheck PASS 232.97 seconds
CheckValgrind FAIL 164.94 seconds
CheckSmatch FAIL 247.62 seconds
bluezmakeextell FAIL 143.65 seconds
IncrementalBuild FAIL 0.40 seconds
ScanBuild FAIL 288.37 seconds
Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[BlueZ,v5,2/3] main.conf: Add Channel Sounding config parsing support
WARNING:STATIC_CONST_CHAR_ARRAY: static const char * array should probably be static const char * const
#209: FILE: src/main.c:159:
+static const char *bcs_options[] = {
/github/workspace/src/patch/14524450.patch total: 0 errors, 1 warnings, 221 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
/github/workspace/src/patch/14524450.patch has style problems, please review.
NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
##############################
Test: BluezMake - FAIL
Desc: Build BlueZ
Output:
tools/mgmt-tester.c: In function ‘main’:
tools/mgmt-tester.c:12984:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
12984 | 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[])
| ^~~~
src/main.c: In function ‘parse_cs_role’:
src/main.c:1272:2: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement]
1272 | char *endptr = NULL;
| ^~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:9621: src/bluetoothd-main.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4156: all] Error 2
##############################
Test: MakeCheck - FAIL
Desc: Run Bluez Make Check
Output:
src/main.c: In function ‘parse_cs_role’:
src/main.c:1272:2: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement]
1272 | char *endptr = NULL;
| ^~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:9621: src/bluetoothd-main.o] Error 1
make: *** [Makefile:10769: 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:12984:5: note: variable tracking size limit exceeded with ‘-fvar-tracking-assignments’, retrying without
12984 | int main(int argc, char *argv[])
| ^~~~
src/main.c: In function ‘parse_cs_role’:
src/main.c:1272:2: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement]
1272 | char *endptr = NULL;
| ^~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:9621: src/bluetoothd-main.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:10769: 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:768:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:846:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1339:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1370:23: warning: Variable length array is used.
src/shared/gatt-server.c:279:25: warning: Variable length array is used.
src/shared/gatt-server.c:622:25: warning: Variable length array is used.
src/shared/gatt-server.c:720:25: warning: Variable length array is used.
src/shared/bap.c:312: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:768:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:846:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1339:31: warning: Variable length array is used.
src/shared/gatt-helpers.c:1370:23: warning: Variable length array is used.
src/shared/gatt-server.c:279:25: warning: Variable length array is used.
src/shared/gatt-server.c:622:25: warning: Variable length array is used.
src/shared/gatt-server.c:720:25: warning: Variable length array is used.
src/shared/bap.c:312: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:309: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/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/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:1272:9: warning: mixing declarations and code
src/main.c: In function ‘parse_cs_role’:
src/main.c:1272:2: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement]
1272 | char *endptr = NULL;
| ^~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:9621: src/bluetoothd-main.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4156: all] Error 2
##############################
Test: bluezmakeextell - FAIL
Desc: Build Bluez with External ELL
Output:
src/main.c: In function ‘parse_cs_role’:
src/main.c:1272:2: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement]
1272 | char *endptr = NULL;
| ^~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:9621: src/bluetoothd-main.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4156: all] Error 2
##############################
Test: IncrementalBuild - FAIL
Desc: Incremental build with the patches in the series
Output:
fatal: previous rebase directory .git/rebase-apply still exists but mbox given.
##############################
Test: ScanBuild - FAIL
Desc: Run Scan Build
Output:
src/shared/gatt-client.c:455:21: warning: Use of memory after it is freed
gatt_db_unregister(op->client->db, op->db_id);
^~~~~~~~~~
src/shared/gatt-client.c:700:2: warning: Use of memory after it is freed
discovery_op_complete(op, false, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1000:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1106:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1300:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1365:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1640:6: warning: Use of memory after it is freed
if (read_db_hash(op)) {
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1645:2: warning: Use of memory after it is freed
discover_all(op);
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1701: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:2154:6: warning: Use of memory after it is freed
if (read_db_hash(op)) {
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:2162:8: warning: Use of memory after it is freed
discovery_op_ref(op),
^~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3340:2: warning: Use of memory after it is freed
complete_write_long_op(req, success, 0, false);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3362:2: warning: Use of memory after it is freed
request_unref(req);
^~~~~~~~~~~~~~~~~~
13 warnings generated.
src/shared/bap.c:1529:8: warning: Use of memory after it is freed
bap = bt_bap_ref_safe(bap);
^~~~~~~~~~~~~~~~~~~~
src/shared/bap.c:2340: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:455:21: warning: Use of memory after it is freed
gatt_db_unregister(op->client->db, op->db_id);
^~~~~~~~~~
src/shared/gatt-client.c:700:2: warning: Use of memory after it is freed
discovery_op_complete(op, false, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1000:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1106:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1300:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1365:2: warning: Use of memory after it is freed
discovery_op_complete(op, success, att_ecode);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1640:6: warning: Use of memory after it is freed
if (read_db_hash(op)) {
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1645:2: warning: Use of memory after it is freed
discover_all(op);
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:1701: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:2154:6: warning: Use of memory after it is freed
if (read_db_hash(op)) {
^~~~~~~~~~~~~~~~
src/shared/gatt-client.c:2162:8: warning: Use of memory after it is freed
discovery_op_ref(op),
^~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3340:2: warning: Use of memory after it is freed
complete_write_long_op(req, success, 0, false);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/shared/gatt-client.c:3362: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:1529:8: warning: Use of memory after it is freed
bap = bt_bap_ref_safe(bap);
^~~~~~~~~~~~~~~~~~~~
src/shared/bap.c:2340: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-client.c:1822: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-server.c:1208: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.
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:1175: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.
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/gatt-database.c:1175: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/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-client.c:1569:2: warning: Use of memory after it is freed
notify_client_unref(client);
^~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
src/main.c: In function ‘parse_cs_role’:
src/main.c:1272:2: error: ISO C90 forbids mixed declarations and code [-Werror=declaration-after-statement]
1272 | char *endptr = NULL;
| ^~~~
cc1: all warnings being treated as errors
make[1]: *** [Makefile:9621: src/bluetoothd-main.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:4156: all] Error 2
https://github.com/bluez/bluez/pull/2032
---
Regards,
Linux Bluetooth
^ permalink raw reply
* RE: [v5] Bluetooth: hci_event: Fix OOB read and infinite loop in hci_le_create_big_complete_evt
From: bluez.test.bot @ 2026-04-14 16:03 UTC (permalink / raw)
To: linux-bluetooth, luiz.dentz
In-Reply-To: <20260414144641.1168084-1-luiz.dentz@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 7418 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=1081189
---Test result---
Test Summary:
CheckPatch PASS 0.65 seconds
GitLint FAIL 0.27 seconds
SubjectPrefix PASS 0.09 seconds
BuildKernel PASS 27.35 seconds
CheckAllWarning PASS 30.09 seconds
CheckSparse PASS 28.67 seconds
BuildKernel32 PASS 26.72 seconds
TestRunnerSetup PASS 584.01 seconds
TestRunner_l2cap-tester PASS 28.66 seconds
TestRunner_iso-tester PASS 35.40 seconds
TestRunner_bnep-tester PASS 6.67 seconds
TestRunner_mgmt-tester FAIL 117.98 seconds
TestRunner_rfcomm-tester PASS 9.72 seconds
TestRunner_sco-tester FAIL 14.66 seconds
TestRunner_ioctl-tester PASS 10.62 seconds
TestRunner_mesh-tester FAIL 12.19 seconds
TestRunner_smp-tester PASS 8.89 seconds
TestRunner_userchan-tester PASS 6.92 seconds
TestRunner_6lowpan-tester FAIL 8.61 seconds
IncrementalBuild FAIL 1.44 seconds
Details
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[v5] Bluetooth: hci_event: Fix OOB read and infinite loop in hci_le_create_big_complete_evt
WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
1: T1 Title exceeds max length (91>80): "[v5] Bluetooth: hci_event: Fix OOB read and infinite loop in hci_le_create_big_complete_evt"
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
Total: 494, Passed: 489 (99.0%), Failed: 1, Not Run: 4
Failed Test Cases
Read Exp Feature - Success Failed 0.111 seconds
##############################
Test: TestRunner_sco-tester - FAIL
Desc: Run sco-tester with test-runner
Output:
WARNING: possible circular locking dependency detected
7.0.0-rc2-ge2297ca80d65 #1 Not tainted
------------------------------------------------------
kworker/u5:0/115 is trying to acquire lock:
ffff888001946240 (sk_lock-AF_BLUETOOTH-BTPROTO_SCO){+.+.}-{0:0}, at: sco_connect_cfm+0x358/0x8d0
but task is already holding lock:
ffff8880025f6220 (&conn->lock){+.+.}-{3:3}, at: sco_connect_cfm+0x22d/0x8d0
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #1 (&conn->lock){+.+.}-{3:3}:
lock_acquire+0xf7/0x2c0
_raw_spin_lock+0x2a/0x40
sco_sock_connect+0x4d7/0x1280
__sys_connect+0x1a3/0x260
__x64_sys_connect+0x6e/0xb0
do_syscall_64+0xa0/0x570
entry_SYSCALL_64_after_hwframe+0x74/0x7c
-> #0 (sk_lock-AF_BLUETOOTH-BTPROTO_SCO){+.+.}-{0:0}:
check_prev_add+0xe9/0xc70
__lock_acquire+0x1457/0x1df0
lock_acquire+0xf7/0x2c0
lock_sock_nested+0x36/0xd0
sco_connect_cfm+0x358/0x8d0
hci_sync_conn_complete_evt+0x3d3/0x8e0
hci_event_packet+0x74f/0xb10
hci_rx_work+0x398/0xd00
process_scheduled_works+0xb16/0x1ac0
worker_thread+0x4ff/0xba0
kthread+0x368/0x490
ret_from_fork+0x498/0x7e0
ret_from_fork_asm+0x19/0x30
other info that might help us debug this:
...
BUG: sleeping function called from invalid context at net/core/sock.c:3782
in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 115, name: kworker/u5:0
preempt_count: 1, expected: 0
RCU nest depth: 0, expected: 0
INFO: lockdep is turned off.
CPU: 0 UID: 0 PID: 115 Comm: kworker/u5:0 Not tainted 7.0.0-rc2-ge2297ca80d65 #1 PREEMPT(lazy)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-1ubuntu1.1 04/01/2014
Workqueue: hci0 hci_rx_work
Call Trace:
<TASK>
dump_stack_lvl+0x49/0x60
__might_resched+0x2ea/0x500
lock_sock_nested+0x47/0xd0
? sco_connect_cfm+0x358/0x8d0
sco_connect_cfm+0x358/0x8d0
? hci_debugfs_create_conn+0x190/0x210
? __pfx_sco_connect_cfm+0x10/0x10
hci_sync_conn_complete_evt+0x3d3/0x8e0
hci_event_packet+0x74f/0xb10
? __pfx_hci_sync_conn_complete_evt+0x10/0x10
? __pfx_hci_event_packet+0x10/0x10
? mark_held_locks+0x49/0x80
? lockdep_hardirqs_on_prepare+0xd4/0x180
? _raw_spin_unlock_irqrestore+0x2c/0x50
hci_rx_work+0x398/0xd00
process_scheduled_works+0xb16/0x1ac0
? __pfx_process_scheduled_works+0x10/0x10
? lock_acquire+0xf7/0x2c0
? lock_is_held_type+0x9b/0x110
? __pfx_hci_rx_work+0x10/0x10
worker_thread+0x4ff/0xba0
? __pfx_worker_thread+0x10/0x10
kthread+0x368/0x490
? _raw_spin_unlock_irq+0x23/0x40
? __pfx_kthread+0x10/0x10
ret_from_fork+0x498/0x7e0
? __pfx_ret_from_fork+0x10/0x10
? __switch_to+0x9e4/0xe50
? __switch_to_asm+0x32/0x60
? __pfx_kthread+0x10/0x10
...
Total: 30, Passed: 30 (100.0%), Failed: 0, Not Run: 0
##############################
Test: TestRunner_mesh-tester - FAIL
Desc: Run mesh-tester with test-runner
Output:
Total: 10, Passed: 8 (80.0%), Failed: 2, Not Run: 0
Failed Test Cases
Mesh - Send cancel - 1 Timed out 2.613 seconds
Mesh - Send cancel - 2 Timed out 2.000 seconds
##############################
Test: TestRunner_6lowpan-tester - FAIL
Desc: Run 6lowpan-tester with test-runner
Output:
WARNING: possible circular locking dependency detected
7.0.0-rc2-ge2297ca80d65 #1 Not tainted
------------------------------------------------------
kworker/0:1/10 is trying to acquire lock:
ffff8880026e4940 ((wq_completion)hci0#2){+.+.}-{0:0}, at: touch_wq_lockdep_map+0x75/0x180
but task is already holding lock:
ffffffffa5a4d720 (rtnl_mutex){+.+.}-{4:4}, at: lowpan_unregister_netdev+0xd/0x30
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #4 (rtnl_mutex){+.+.}-{4:4}:
lock_acquire+0xf7/0x2c0
__mutex_lock+0x16b/0x1fc0
lowpan_register_netdev+0x11/0x30
chan_ready_cb+0x836/0xd00
l2cap_recv_frame+0x6a06/0x8920
l2cap_recv_acldata+0x790/0xdf0
hci_rx_work+0x500/0xd00
process_scheduled_works+0xb16/0x1ac0
worker_thread+0x4ff/0xba0
kthread+0x368/0x490
ret_from_fork+0x498/0x7e0
ret_from_fork_asm+0x19/0x30
-> #3 (&chan->lock#3/1){+.+.}-{4:4}:
lock_acquire+0xf7/0x2c0
__mutex_lock+0x16b/0x1fc0
l2cap_chan_connect+0x74e/0x1980
lowpan_control_write+0x523/0x660
full_proxy_write+0x10b/0x190
vfs_write+0x1c0/0xf60
ksys_write+0xf1/0x1d0
do_syscall_64+0xa0/0x570
entry_SYSCALL_64_after_hwframe+0x74/0x7c
-> #2 (&conn->lock){+.+.}-{4:4}:
...
Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0
##############################
Test: IncrementalBuild - FAIL
Desc: Incremental build with the patches in the series
Output:
fatal: previous rebase directory .git/rebase-apply still exists but mbox given.
https://github.com/bluez/bluetooth-next/pull/82
---
Regards,
Linux Bluetooth
^ permalink raw reply
* [bluez/bluez] d7cd4d: shared: rap: Introduce Channel Sounding HCI raw in...
From: Bhavani @ 2026-04-14 15:45 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1081201
Home: https://github.com/bluez/bluez
Commit: d7cd4d5e6656ba7bbc60887e9b204b7cb650845b
https://github.com/bluez/bluez/commit/d7cd4d5e6656ba7bbc60887e9b204b7cb650845b
Author: Naga Bhavani Akella <naga.akella@oss.qualcomm.com>
Date: 2026-04-14 (Tue, 14 Apr 2026)
Changed paths:
M src/shared/hci.c
M src/shared/hci.h
M src/shared/rap.c
M src/shared/rap.h
Log Message:
-----------
shared: rap: Introduce Channel Sounding HCI raw interface support
Implement stub callbacks for Channel Sounding HCI events and add the
required protocol definitions for CS configuration, procedure control,
and subevent result parsing
Add data structures to support Channel Sounding Processing
Add helper function to get hci conn info list and integrate it with RAP
Commit: cd3d94660e57931fc87810e491055e8f8de62741
https://github.com/bluez/bluez/commit/cd3d94660e57931fc87810e491055e8f8de62741
Author: Naga Bhavani Akella <naga.akella@oss.qualcomm.com>
Date: 2026-04-14 (Tue, 14 Apr 2026)
Changed paths:
M src/bluetooth.service.in
M src/btd.h
M src/main.c
M src/main.conf
Log Message:
-----------
main.conf: Add Channel Sounding config parsing support
Add support for parsing Channel Sounding (CS) configuration options
from the configuration file.
Add CAP_NET_RAW to CapabilityBoundingSet in bluetooth.service.
bluetoothd requires CAP_NET_RAW to receive and process HCI LE events
when running under a constrained systemd capability bounding set
Commit: 7f151a21b42da27f6feb26bd5d8c2d4adef1f317
https://github.com/bluez/bluez/commit/7f151a21b42da27f6feb26bd5d8c2d4adef1f317
Author: Naga Bhavani Akella <naga.akella@oss.qualcomm.com>
Date: 2026-04-14 (Tue, 14 Apr 2026)
Changed paths:
M Makefile.plugins
M profiles/ranging/rap.c
A profiles/ranging/rap_hci.c
Log Message:
-----------
profiles: ranging: Add HCI LE Event Handling in Reflector role
Open RAW HCI Channel for CS Event Handling
Parse the following HCI LE CS Events in reflector role
and route the events to RAP Profile.
1. HCI_EVT_LE_CS_READ_RMT_SUPP_CAP_COMPLETE
2. HCI_EVT_LE_CS_CONFIG_COMPLETE
3. HCI_EVT_LE_CS_SECURITY_ENABLE_COMPLETE
4. HCI_EVT_LE_CS_PROCEDURE_ENABLE_COMPLETE
5. HCI_EVT_LE_CS_SUBEVENT_RESULT
6. HCI_EVT_LE_CS_SUBEVENT_RESULT_CONTINUE
Send HCI_OP_LE_CS_SET_DEFAULT_SETTINGS to the controller
with default settings selected by the user.
Map connection handle received to device connection
Compare: https://github.com/bluez/bluez/compare/d7cd4d5e6656%5E...7f151a21b42d
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* [bluez/bluez] 9736f3: shared: rap: Introduce Channel Sounding HCI raw in...
From: Bhavani @ 2026-04-14 15:45 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1081191
Home: https://github.com/bluez/bluez
Commit: 9736f3017b53172b929ee0a710eec6b8c23212f2
https://github.com/bluez/bluez/commit/9736f3017b53172b929ee0a710eec6b8c23212f2
Author: Naga Bhavani Akella <naga.akella@oss.qualcomm.com>
Date: 2026-04-14 (Tue, 14 Apr 2026)
Changed paths:
M src/shared/hci.c
M src/shared/hci.h
M src/shared/rap.c
M src/shared/rap.h
Log Message:
-----------
shared: rap: Introduce Channel Sounding HCI raw interface support
Implement stub callbacks for Channel Sounding HCI events and add the
required protocol definitions for CS configuration, procedure control,
and subevent result parsing
Add data structures to support Channel Sounding Processing
Add helper function to get hci conn info list and integrate it with RAP
Commit: 1729f38c58dfdd3d54034aed674f885f17ef759f
https://github.com/bluez/bluez/commit/1729f38c58dfdd3d54034aed674f885f17ef759f
Author: Naga Bhavani Akella <naga.akella@oss.qualcomm.com>
Date: 2026-04-14 (Tue, 14 Apr 2026)
Changed paths:
M src/bluetooth.service.in
M src/btd.h
M src/main.c
M src/main.conf
Log Message:
-----------
main.conf: Add Channel Sounding config parsing support
Add support for parsing Channel Sounding (CS) configuration options
from the configuration file.
Add CAP_NET_RAW to CapabilityBoundingSet in bluetooth.service.
bluetoothd requires CAP_NET_RAW to receive and process HCI LE events
when running under a constrained systemd capability bounding set
Compare: https://github.com/bluez/bluez/compare/9736f3017b53%5E...1729f38c58df
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* [PATCH BlueZ v6 3/3] profiles: ranging: Add HCI LE Event Handling in Reflector role
From: Naga Bhavani Akella @ 2026-04-14 15:33 UTC (permalink / raw)
To: linux-bluetooth
Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
prathibha.madugonde, Naga Bhavani Akella
In-Reply-To: <20260414153335.3169542-1-naga.akella@oss.qualcomm.com>
Open RAW HCI Channel for CS Event Handling
Parse the following HCI LE CS Events in reflector role
and route the events to RAP Profile.
1. HCI_EVT_LE_CS_READ_RMT_SUPP_CAP_COMPLETE
2. HCI_EVT_LE_CS_CONFIG_COMPLETE
3. HCI_EVT_LE_CS_SECURITY_ENABLE_COMPLETE
4. HCI_EVT_LE_CS_PROCEDURE_ENABLE_COMPLETE
5. HCI_EVT_LE_CS_SUBEVENT_RESULT
6. HCI_EVT_LE_CS_SUBEVENT_RESULT_CONTINUE
Send HCI_OP_LE_CS_SET_DEFAULT_SETTINGS to the controller
with default settings selected by the user.
Map connection handle received to device connection
---
Makefile.plugins | 3 +-
profiles/ranging/rap.c | 83 ++-
profiles/ranging/rap_hci.c | 1288 ++++++++++++++++++++++++++++++++++++
3 files changed, 1367 insertions(+), 7 deletions(-)
create mode 100644 profiles/ranging/rap_hci.c
diff --git a/Makefile.plugins b/Makefile.plugins
index c9efadb45..ac667beda 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -89,7 +89,8 @@ builtin_modules += battery
builtin_sources += profiles/battery/battery.c
builtin_modules += rap
-builtin_sources += profiles/ranging/rap.c
+builtin_sources += profiles/ranging/rap.c \
+ profiles/ranging/rap_hci.c
if SIXAXIS
builtin_modules += sixaxis
diff --git a/profiles/ranging/rap.c b/profiles/ranging/rap.c
index f03454c72..63682e318 100644
--- a/profiles/ranging/rap.c
+++ b/profiles/ranging/rap.c
@@ -17,6 +17,7 @@
#include "gdbus/gdbus.h"
#include "bluetooth/bluetooth.h"
+#include "bluetooth/l2cap.h"
#include "bluetooth/uuid.h"
#include "src/plugin.h"
@@ -34,12 +35,17 @@
#include "src/shared/rap.h"
#include "attrib/att.h"
#include "src/log.h"
+#include "src/btd.h"
+#define USE_BT_HCI_RAW_CHANNEL 1
struct rap_data {
struct btd_device *device;
struct btd_service *service;
struct bt_rap *rap;
unsigned int ready_id;
+#if USE_BT_HCI_RAW_CHANNEL
+ struct bt_hci *hci;
+#endif
};
static struct queue *sessions;
@@ -61,10 +67,10 @@ static void rap_debug(const char *str, void *user_data)
static void rap_data_add(struct rap_data *data)
{
- DBG("%p", data);
+ DBG("%p", (void *)data);
if (queue_find(sessions, NULL, data)) {
- error("data %p already added", data);
+ error("data %p already added", (void *)data);
return;
}
@@ -95,13 +101,21 @@ static void rap_data_free(struct rap_data *data)
}
bt_rap_ready_unregister(data->rap, data->ready_id);
+#if USE_BT_HCI_RAW_CHANNEL
+ if (data->hci) {
+ bt_rap_hci_sm_cleanup();
+ bt_hci_unref(data->hci);
+ }
+#endif
+ /* Clean up HCI connection mappings */
+ bt_rap_detach_hci(data->rap);
bt_rap_unref(data->rap);
free(data);
}
static void rap_data_remove(struct rap_data *data)
{
- DBG("%p", data);
+ DBG("%p", (void *)data);
if (!queue_remove(sessions, data))
return;
@@ -118,7 +132,7 @@ static void rap_detached(struct bt_rap *rap, void *user_data)
{
struct rap_data *data;
- DBG("%p", rap);
+ DBG("%p", (void *)rap);
data = queue_find(sessions, match_data, rap);
if (!data) {
@@ -131,7 +145,7 @@ static void rap_detached(struct bt_rap *rap, void *user_data)
static void rap_ready(struct bt_rap *rap, void *user_data)
{
- DBG("%p", rap);
+ DBG("%p", (void *)rap);
}
static void rap_attached(struct bt_rap *rap, void *user_data)
@@ -140,7 +154,7 @@ static void rap_attached(struct bt_rap *rap, void *user_data)
struct bt_att *att;
struct btd_device *device;
- DBG("%p", rap);
+ DBG("%p", (void *)rap);
data = queue_find(sessions, match_data, rap);
if (data) {
@@ -194,6 +208,22 @@ static int rap_probe(struct btd_service *service)
free(data);
return -EINVAL;
}
+#if USE_BT_HCI_RAW_CHANNEL
+ int16_t hci_index = btd_adapter_get_index(adapter);
+
+ data->hci = bt_hci_new_raw_device(hci_index);
+ if (bt_rap_attach_hci(data->rap, data->hci)) {
+ DBG("HCI raw channel initialized, hci%d", hci_index);
+ bt_rap_hci_set_le_bcs_options(
+ btd_opts.defaults.bcs.role,
+ btd_opts.defaults.bcs.cs_sync_ant_sel,
+ btd_opts.defaults.bcs.max_tx_power);
+ } else {
+ error("HCI raw channel not available (may be in use)");
+ }
+#else /* USE_BT_HCI_RAW_CHANNEL */
+ DBG("MGMT Events");
+#endif /* USE_BT_HCI_RAW_CHANNEL */
rap_data_add(data);
@@ -228,6 +258,10 @@ static int rap_accept(struct btd_service *service)
struct btd_device *device = btd_service_get_device(service);
struct bt_gatt_client *client = btd_device_get_gatt_client(device);
struct rap_data *data = btd_service_get_user_data(service);
+ struct bt_att *att;
+ const bdaddr_t *bdaddr;
+ uint8_t bdaddr_type;
+ uint16_t handle;
char addr[18];
ba2str(device_get_address(device), addr);
@@ -243,6 +277,43 @@ static int rap_accept(struct btd_service *service)
return -EINVAL;
}
+ /* Set up connection handle mapping for CS event routing */
+ att = bt_rap_get_att(data->rap);
+ bdaddr = device_get_address(device);
+ bdaddr_type = device_get_le_address_type(device);
+
+ if (att && data->hci) {
+ /* Use bt_hci_get_conn_info to find the connection handle
+ * by iterating through all connections and matching bdaddr
+ */
+ struct bt_hci_conn_info conn_info;
+ bool found = false;
+
+ /* Try handles from 0x0001 to 0x0EFF
+ * (valid LE connection handle range)
+ */
+ for (handle = 0x0001; handle <= 0x0EFF; handle++) {
+ if (bt_hci_get_conn_info(data->hci, handle,
+ &conn_info)) {
+ /* Check if bdaddr matches */
+ if (memcmp(conn_info.bdaddr, bdaddr, 6) == 0) {
+ found = true;
+ DBG("Found conn handle 0x%04X", handle);
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ DBG("Setting up handle mapping: handle=0x%04X", handle);
+ bt_rap_set_conn_handle(data->rap, handle,
+ (const uint8_t *)bdaddr,
+ bdaddr_type);
+ } else {
+ error("Failed to find connection handle for device");
+ }
+ }
+
btd_service_connecting_complete(service, 0);
return 0;
diff --git a/profiles/ranging/rap_hci.c b/profiles/ranging/rap_hci.c
new file mode 100644
index 000000000..b00719ae2
--- /dev/null
+++ b/profiles/ranging/rap_hci.c
@@ -0,0 +1,1288 @@
+// 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
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <string.h>
+#include <endian.h>
+
+#include "lib/bluetooth/bluetooth.h"
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
+#include "src/shared/rap.h"
+#include "src/log.h"
+#include "monitor/bt.h"
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+/* CS State Definitions */
+enum cs_state_t {
+ CS_INIT,
+ CS_STOPPED,
+ CS_STARTED,
+ CS_WAIT_CONFIG_CMPLT,
+ CS_WAIT_SEC_CMPLT,
+ CS_WAIT_PROC_CMPLT,
+ CS_HOLD,
+ CS_UNSPECIFIED
+};
+
+const char *state_names[] = {
+ "CS_INIT",
+ "CS_STOPPED",
+ "CS_STARTED",
+ "CS_WAIT_CONFIG_CMPLT",
+ "CS_WAIT_SEC_CMPLT",
+ "CS_WAIT_PROC_CMPLT",
+ "CS_HOLD",
+ "CS_UNSPECIFIED"
+};
+
+/* Callback Function Type */
+typedef void (*cs_callback_t)(uint16_t length,
+ const void *param, void *user_data);
+
+/* State Machine Context */
+struct cs_state_machine_t {
+ enum cs_state_t current_state;
+ enum cs_state_t old_state;
+ struct bt_hci *hci;
+ struct bt_rap *rap;
+ unsigned int event_id;
+ bool initiator;
+ bool procedure_active;
+};
+
+struct cs_callback_map_t {
+ enum cs_state_t state;
+ cs_callback_t callback;
+};
+
+struct cs_callback_map_t cs_callback_map[] = {
+ { CS_WAIT_CONFIG_CMPLT, bt_rap_hci_cs_config_complete_callback },
+ { CS_WAIT_SEC_CMPLT, bt_rap_hci_cs_sec_enable_complete_callback },
+ { CS_WAIT_PROC_CMPLT, bt_rap_hci_cs_procedure_enable_complete_callback }
+};
+
+#define CS_CALLBACK_MAP_SIZE ARRAY_SIZE(cs_callback_map)
+
+struct bt_rap_hci_cs_options cs_opt;
+struct cs_state_machine_t *sm;
+
+/* Connection Handle Mapping */
+struct rap_conn_mapping {
+ uint16_t handle;
+ uint8_t bdaddr[6];
+ uint8_t bdaddr_type;
+ struct bt_att *att;
+ struct bt_rap *rap;
+};
+
+static struct queue *conn_mappings;
+
+/* Connection Mapping Helper Functions */
+static void mapping_free(void *data)
+{
+ struct rap_conn_mapping *mapping = data;
+
+ if (!mapping)
+ return;
+
+ free(mapping);
+}
+
+static bool match_mapping_handle(const void *a, const void *b)
+{
+ const struct rap_conn_mapping *mapping = a;
+ uint16_t handle = PTR_TO_UINT(b);
+
+ return mapping->handle == handle;
+}
+
+static bool match_mapping_rap(const void *a, const void *b)
+{
+ const struct rap_conn_mapping *mapping = a;
+ const struct bt_rap *rap = b;
+
+ return mapping->rap == rap;
+}
+
+static struct rap_conn_mapping *find_mapping_by_handle(uint16_t handle)
+{
+ if (!conn_mappings)
+ return NULL;
+
+ return queue_find(conn_mappings, match_mapping_handle,
+ UINT_TO_PTR(handle));
+}
+
+static bool add_conn_mapping(uint16_t handle, const uint8_t *bdaddr,
+ uint8_t bdaddr_type, struct bt_att *att,
+ struct bt_rap *rap)
+{
+ struct rap_conn_mapping *mapping;
+
+ if (!conn_mappings) {
+ conn_mappings = queue_new();
+ if (!conn_mappings)
+ return false;
+ }
+
+ /* Check if mapping already exists */
+ mapping = find_mapping_by_handle(handle);
+ if (mapping) {
+ /* Update existing mapping */
+ if (bdaddr)
+ memcpy(mapping->bdaddr, bdaddr, 6);
+ mapping->bdaddr_type = bdaddr_type;
+ mapping->att = att;
+ mapping->rap = rap;
+ return true;
+ }
+
+ /* Create new mapping */
+ mapping = new0(struct rap_conn_mapping, 1);
+ if (!mapping)
+ return false;
+
+ mapping->handle = handle;
+ if (bdaddr)
+ memcpy(mapping->bdaddr, bdaddr, 6);
+ mapping->bdaddr_type = bdaddr_type;
+ mapping->att = att;
+ mapping->rap = rap;
+
+ return queue_push_tail(conn_mappings, mapping);
+}
+
+static void remove_conn_mapping(uint16_t handle)
+{
+ struct rap_conn_mapping *mapping;
+
+ if (!conn_mappings)
+ return;
+
+ mapping = queue_remove_if(conn_mappings, match_mapping_handle,
+ UINT_TO_PTR(handle));
+ if (mapping)
+ mapping_free(mapping);
+}
+
+static void remove_rap_mappings(struct bt_rap *rap)
+{
+ if (!conn_mappings)
+ return;
+
+ queue_remove_all(conn_mappings, match_mapping_rap, rap,
+ mapping_free);
+}
+
+static struct bt_rap *resolve_handle_to_rap(uint16_t handle,
+ struct bt_hci *hci)
+{
+ struct rap_conn_mapping *mapping;
+ struct bt_hci_conn_info conn_info;
+
+ /* First try to find in mapping cache */
+ mapping = find_mapping_by_handle(handle);
+ if (mapping && mapping->rap) {
+ DBG("Found handle 0x%04X in mapping cache", handle);
+ return mapping->rap;
+ }
+
+ /* Fallback: Try to get connection info via ioctl */
+ if (hci && bt_hci_get_conn_info(hci, handle, &conn_info)) {
+ DBG("Got connection info via ioctl for handle 0x%04X:", handle);
+ DBG(" bdaddr=%02x:%02x:%02x:%02x:%02x:%02x link_type=0x%02x",
+ conn_info.bdaddr[5], conn_info.bdaddr[4],
+ conn_info.bdaddr[3], conn_info.bdaddr[2],
+ conn_info.bdaddr[1], conn_info.bdaddr[0],
+ conn_info.type);
+ DBG(" Note: Cannot determine RAP instance from ioctl alone");
+ }
+
+ /* Profile layer should have called bt_rap_set_conn_handle() during
+ * connection establishment. If we reach here, the mapping was not set.
+ */
+ DBG("No mapping found for handle 0x%04X", handle);
+ DBG("Profile layer should call bt_rap_set_conn_handle() on connect");
+
+ return NULL;
+}
+
+/* State Machine Functions */
+void cs_state_machine_init(struct cs_state_machine_t *sm, struct bt_rap *rap,
+ struct bt_hci *hci)
+{
+ if (!sm)
+ return;
+
+ memset(sm, 0, sizeof(struct cs_state_machine_t));
+ sm->current_state = CS_UNSPECIFIED;
+ sm->rap = rap;
+ sm->hci = hci;
+ sm->initiator = false;
+ sm->procedure_active = false;
+}
+
+void bt_rap_hci_sm_cleanup(void)
+{
+ if (!sm)
+ return;
+
+ if (sm->event_id)
+ bt_hci_unregister(sm->hci, sm->event_id);
+
+ sm->current_state = CS_UNSPECIFIED;
+ sm->rap = NULL;
+ sm->hci = NULL;
+ sm->procedure_active = false;
+
+ free(sm);
+}
+
+void bt_rap_hci_set_le_bcs_options(uint8_t role, uint8_t cs_sync_ant_sel,
+ int8_t max_tx_power)
+{
+ cs_opt.role = role;
+ cs_opt.cs_sync_ant_sel = cs_sync_ant_sel;
+ cs_opt.max_tx_power = max_tx_power;
+}
+
+/* State Transition Logic */
+void cs_set_state(struct cs_state_machine_t *sm, enum cs_state_t new_state)
+{
+ if (!sm)
+ return;
+
+ if (sm->current_state == new_state)
+ return;
+
+ /* Validate state values before array access */
+ if (sm->current_state > CS_UNSPECIFIED || new_state > CS_UNSPECIFIED) {
+ DBG("[ERROR] Invalid state transition attempted\n");
+ return;
+ }
+
+ DBG("[STATE] Transition: %s → %s\n",
+ state_names[sm->current_state],
+ state_names[new_state]);
+
+ sm->old_state = sm->current_state;
+ sm->current_state = new_state;
+}
+
+enum cs_state_t cs_get_current_state(struct cs_state_machine_t *sm)
+{
+ return sm ? sm->current_state : CS_UNSPECIFIED;
+}
+
+bool cs_is_procedure_active(const struct cs_state_machine_t *sm)
+{
+ return sm ? sm->procedure_active : false;
+}
+
+/* HCI Event Callbacks */
+static void rap_def_settings_done_cb(const void *data, uint8_t size,
+ void *user_data)
+{
+ struct bt_hci_rsp_le_cs_set_def_settings *rp;
+ struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
+
+ if (!sm || !data ||
+ size < sizeof(struct bt_hci_rsp_le_cs_set_def_settings))
+ return;
+
+ DBG("[EVENT] CS default Setting Complete (size=0x%02X)\n", size);
+
+ rp = (struct bt_hci_rsp_le_cs_set_def_settings *)data;
+
+ if (cs_get_current_state(sm) != CS_INIT) {
+ DBG("Event received in Wrong State!! Expected : CS_INIT");
+ return;
+ }
+
+ if (rp->status == 0) {
+ /* Success - proceed to configuration */
+ cs_set_state(sm, CS_WAIT_CONFIG_CMPLT);
+
+ /* Reflector role */
+ DBG("Waiting for CS Config Completed event...\n");
+ /* TODO: Initiator role - Send CS Config complete cmd */
+ } else {
+ /* Error - transition to stopped */
+ DBG("[ERROR]CS Set default setting failed with status 0x%02X\n",
+ rp->status);
+ cs_set_state(sm, CS_STOPPED);
+ }
+}
+
+void rap_send_hci_def_settings_command(struct cs_state_machine_t *sm,
+ struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete *ev)
+{
+ struct bt_hci_cmd_le_cs_set_def_settings cp;
+ unsigned int status;
+
+ memset(&cp, 0, sizeof(cp));
+
+ if (ev->handle)
+ cp.handle = ev->handle;
+ cp.role_enable = cs_opt.role;
+ cp.cs_sync_antenna_selection = cs_opt.cs_sync_ant_sel;
+ cp.max_tx_power = cs_opt.max_tx_power;
+
+ if (!sm || !sm->hci) {
+ DBG("[ERR] Set Def Settings: sm or hci is null");
+ return;
+ }
+
+ status = bt_hci_send(sm->hci, BT_HCI_CMD_LE_CS_SET_DEF_SETTINGS,
+ &cp, sizeof(cp), rap_def_settings_done_cb,
+ sm, NULL);
+
+ DBG("sending set default settings case, status : %d", status);
+ if (!status)
+ DBG("Failed to send default settings cmd");
+}
+
+static void rap_rd_rmt_supp_cap_cmplt_evt(const uint8_t *data, uint8_t size,
+ void *user_data)
+{
+ struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
+ const struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete *evt;
+ struct bt_rap *rap;
+ struct iovec iov;
+
+ if (!sm || !data ||
+ size < sizeof(struct bt_hci_evt_le_cs_rd_rem_supp_cap_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) {
+ DBG("[ERROR] Failed to pull remote cap complete struct\n");
+ return;
+ }
+
+ DBG("[EVENT] Remote Capabilities Complete\n");
+ DBG("status=0x%02X, handle=0x%04X\n", evt->status, evt->handle);
+
+ /* Check status */
+ if (evt->status != 0) {
+ DBG("[ERROR] Remote capabilities failed with status 0x%02X\n",
+ evt->status);
+ cs_set_state(sm, CS_STOPPED);
+ return;
+ }
+
+ /* Resolve handle to RAP instance */
+ rap = resolve_handle_to_rap(evt->handle, sm->hci);
+ if (!rap) {
+ DBG("[WARN] Could not resolve handle 0x%04X to RAP instance\n",
+ evt->handle);
+ /* Continue with state machine RAP for now */
+ rap = sm->rap;
+ }
+
+ DBG("[EVENT] Remote Capabilities: num_config=%u, ",
+ evt->num_config_supported);
+ DBG("max_consecutive_proc=%u, num_antennas=%u, ",
+ evt->max_consecutive_procedures_supported,
+ evt->num_antennas_supported);
+ DBG("max_antenna_paths=%u, roles=0x%02X, modes=0x%02X\n",
+ evt->max_antenna_paths_supported,
+ evt->roles_supported,
+ evt->modes_supported);
+
+ rap_send_hci_def_settings_command(sm,
+ (struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete *)evt);
+ cs_set_state(sm, CS_INIT);
+}
+
+static void rap_cs_config_cmplt_evt(const uint8_t *data, uint8_t size,
+ void *user_data)
+{
+ struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
+ const struct bt_hci_evt_le_cs_config_complete *evt;
+ struct rap_ev_cs_config_cmplt rap_ev;
+ struct iovec iov;
+
+ if (!sm || !data ||
+ size < sizeof(struct bt_hci_evt_le_cs_config_complete))
+ return;
+
+ /* Initialize iovec with the event data */
+ iov.iov_base = (void *)data;
+ iov.iov_len = size;
+
+ DBG("[EVENT] Configuration Complete (size=0x%02X)\n", size);
+
+ /* State Check */
+ if (cs_get_current_state(sm) != CS_WAIT_CONFIG_CMPLT) {
+ DBG("Event received in Wrong State!! ");
+ DBG("Expected : CS_WAIT_CONFIG_CMPLT");
+ return;
+ }
+
+ /* Pull the entire structure at once */
+ evt = util_iov_pull_mem(&iov, sizeof(*evt));
+ if (!evt) {
+ DBG("[ERROR] Failed to pull config complete struct\n");
+ return;
+ }
+
+ DBG("status=0x%02X, handle=0x%04X\n", evt->status, evt->handle);
+
+ /* Check status */
+ if (evt->status != 0) {
+ DBG("[ERROR] Configuration failed with status 0x%02X\n",
+ evt->status);
+ cs_set_state(sm, CS_STOPPED);
+ return;
+ }
+
+ /* Copy fields to rap_ev structure */
+ rap_ev.status = evt->status;
+ rap_ev.conn_hdl = cpu_to_le16(evt->handle);
+ rap_ev.config_id = evt->config_id;
+ rap_ev.action = evt->action;
+ rap_ev.main_mode_type = evt->main_mode_type;
+ rap_ev.sub_mode_type = evt->sub_mode_type;
+ rap_ev.min_main_mode_steps = evt->min_main_mode_steps;
+ rap_ev.max_main_mode_steps = evt->max_main_mode_steps;
+ rap_ev.main_mode_rep = evt->main_mode_repetition;
+ rap_ev.mode_0_steps = evt->mode_0_steps;
+ rap_ev.role = evt->role;
+ rap_ev.rtt_type = evt->rtt_type;
+ rap_ev.cs_sync_phy = evt->cs_sync_phy;
+ memcpy(rap_ev.channel_map, evt->channel_map, 10);
+ rap_ev.channel_map_rep = evt->channel_map_repetition;
+ rap_ev.channel_sel_type = evt->channel_selection_type;
+ rap_ev.ch3c_shape = evt->ch3c_shape;
+ rap_ev.ch3c_jump = evt->ch3c_jump;
+ rap_ev.reserved = evt->reserved;
+ rap_ev.t_ip1_time = evt->t_ip1_time;
+ rap_ev.t_ip2_time = evt->t_ip2_time;
+ rap_ev.t_fcs_time = evt->t_fcs_time;
+ rap_ev.t_pm_time = evt->t_pm_time;
+
+ /* Store rtt_type in global options */
+ cs_opt.rtt_type = rap_ev.rtt_type;
+
+ DBG("[EVENT] Config Complete: config_id=%u, action=%u, ",
+ rap_ev.config_id, rap_ev.action);
+ DBG("main_mode=%u, sub_mode=%u, role=%u, rtt_type=%u\n",
+ rap_ev.main_mode_type, rap_ev.sub_mode_type,
+ rap_ev.role, rap_ev.rtt_type);
+
+ /* Success - proceed to Security enable complete */
+ cs_set_state(sm, CS_WAIT_SEC_CMPLT);
+
+ /* Reflector role */
+ DBG("Waiting for security enable event...\n");
+ /* TODO: Initiator role - Send CS Security enable cmd */
+
+ /* Send Callback to RAP Profile */
+ for (size_t i = 0; i < CS_CALLBACK_MAP_SIZE; i++) {
+ if (cs_callback_map[i].state == sm->old_state) {
+ cs_callback_map[i].callback(size, &rap_ev, sm->rap);
+ return;
+ }
+ }
+}
+
+static void rap_cs_sec_enable_cmplt_evt(const uint8_t *data, uint8_t size,
+ void *user_data)
+{
+ struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
+ struct rap_ev_cs_sec_enable_cmplt rap_ev;
+ struct iovec iov;
+ uint8_t status;
+ uint16_t handle;
+
+ if (!sm || !data ||
+ size < sizeof(struct bt_hci_evt_le_cs_sec_enable_complete))
+ return;
+
+ /* Initialize iovec with the event data */
+ iov.iov_base = (void *)data;
+ iov.iov_len = size;
+
+ DBG("[EVENT] Security Enable Complete (size=0x%02X)\n", size);
+
+ /* State Check */
+ if (cs_get_current_state(sm) != CS_WAIT_SEC_CMPLT) {
+ DBG("Event received in Wrong State!! ");
+ DBG("Expected : CS_WAIT_SEC_CMPLT");
+ return;
+ }
+
+ /* Parse all fields in order using iovec */
+ if (!util_iov_pull_u8(&iov, &status)) {
+ DBG("[ERROR] Failed to parse Status\n");
+ return;
+ }
+
+ if (!util_iov_pull_le16(&iov, &handle)) {
+ DBG("[ERROR] Failed to parse Connection_Handle\n");
+ return;
+ }
+
+ rap_ev.status = status;
+ rap_ev.conn_hdl = cpu_to_le16(handle);
+
+ DBG("[EVENT] Security Enable: status=0x%02X, handle=0x%04X\n",
+ rap_ev.status, handle);
+
+ if (rap_ev.status == 0) {
+ /* Success - proceed to configuration */
+ cs_set_state(sm, CS_WAIT_PROC_CMPLT);
+
+ /* Reflector role */
+ DBG("Waiting for CS Proc complete event...\n");
+ /* TODO: Initiator - Send CS Proc Set Parameter and enable */
+ } else {
+ /* Error - transition to stopped */
+ DBG("[ERROR] Security enable failed with status 0x%02X\n",
+ rap_ev.status);
+ cs_set_state(sm, CS_STOPPED);
+ }
+
+ /* Send Callback to RAP Profile */
+ for (size_t i = 0; i < CS_CALLBACK_MAP_SIZE; i++) {
+ if (cs_callback_map[i].state == sm->old_state) {
+ cs_callback_map[i].callback(size, &rap_ev, sm->rap);
+ return;
+ }
+ }
+}
+
+static void rap_cs_proc_enable_cmplt_evt(const uint8_t *data, uint8_t size,
+ void *user_data)
+{
+ struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
+ const struct bt_hci_evt_le_cs_proc_enable_complete *evt;
+ struct rap_ev_cs_proc_enable_cmplt rap_ev;
+ struct iovec iov;
+
+ if (!sm || !data ||
+ size < sizeof(struct bt_hci_evt_le_cs_proc_enable_complete))
+ return;
+
+ /* Initialize iovec with the event data */
+ iov.iov_base = (void *)data;
+ iov.iov_len = size;
+
+ DBG("[EVENT] Procedure Enable Complete (size=0x%02X)\n", size);
+
+ /* State Check */
+ if (cs_get_current_state(sm) != CS_WAIT_PROC_CMPLT) {
+ DBG("Event received in Wrong State!! ");
+ DBG("Expected : CS_WAIT_PROC_CMPLT");
+ return;
+ }
+
+ /* Pull the entire structure at once */
+ evt = util_iov_pull_mem(&iov, sizeof(*evt));
+ if (!evt) {
+ DBG("[ERROR] Failed to pull proc enable complete struct\n");
+ return;
+ }
+
+ DBG("status=0x%02X, handle=0x%04X\n", evt->status, evt->handle);
+
+ /* Check status */
+ if (evt->status != 0) {
+ DBG("[ERROR] Procedure enable failed with status 0x%02X\n",
+ evt->status);
+ cs_set_state(sm, CS_STOPPED);
+ sm->procedure_active = false;
+ return;
+ }
+
+ /* Copy fields to rap_ev structure */
+ rap_ev.status = evt->status;
+ rap_ev.conn_hdl = cpu_to_le16(evt->handle);
+ rap_ev.config_id = evt->config_id;
+ rap_ev.state = evt->state;
+ rap_ev.tone_ant_config_sel = evt->tone_antenna_config_selection;
+ rap_ev.sel_tx_pwr = evt->selected_tx_power;
+ memcpy(rap_ev.sub_evt_len, evt->subevent_len, 3);
+ rap_ev.sub_evts_per_evt = evt->subevents_per_event;
+ rap_ev.sub_evt_intrvl = evt->subevent_interval;
+ rap_ev.evt_intrvl = evt->event_interval;
+ rap_ev.proc_intrvl = evt->procedure_interval;
+ rap_ev.proc_counter = evt->procedure_count;
+ rap_ev.max_proc_len = evt->max_procedure_len;
+
+ DBG("[EVENT] Procedure Enable: config_id=%u, state=%u, ",
+ rap_ev.config_id, rap_ev.state);
+ DBG("sub_evts_per_evt=%u, evt_intrvl=%u, proc_intrvl=%u\n",
+ rap_ev.sub_evts_per_evt, rap_ev.evt_intrvl,
+ rap_ev.proc_intrvl);
+
+ /* Success - procedure started */
+ cs_set_state(sm, CS_STARTED);
+ sm->procedure_active = true;
+
+ /* Send Callback to RAP Profile */
+ for (size_t i = 0; i < CS_CALLBACK_MAP_SIZE; i++) {
+ if (cs_callback_map[i].state == sm->old_state) {
+ cs_callback_map[i].callback(size, &rap_ev, sm->rap);
+ return;
+ }
+ }
+}
+
+static void parse_i_q_sample(struct iovec *iov, int16_t *i_sample,
+ int16_t *q_sample)
+{
+ uint8_t bytes[3];
+ uint32_t buffer;
+ uint32_t i12;
+ uint32_t q12;
+
+ /* Pull 3 bytes from iovec */
+ if (!util_iov_pull_u8(iov, &bytes[0]) ||
+ !util_iov_pull_u8(iov, &bytes[1]) ||
+ !util_iov_pull_u8(iov, &bytes[2])) {
+ *i_sample = 0;
+ *q_sample = 0;
+ return;
+ }
+
+ /* Reconstruct 24-bit buffer from 3 bytes */
+ buffer = (uint32_t)bytes[0] | ((uint32_t)bytes[1] << 8) |
+ ((uint32_t)bytes[2] << 16);
+ i12 = buffer & 0x0FFFU; /* bits 0..11 */
+ q12 = (buffer >> 12) & 0x0FFFU; /* bits 12..23 */
+
+ /* Sign-extend 12-bit values to 16-bit */
+ *i_sample = (int16_t)((int32_t)(i12 << 20) >> 20);
+ *q_sample = (int16_t)((int32_t)(q12 << 20) >> 20);
+}
+
+/* Parse CS Mode 0 step data */
+static void parse_mode_zero_data(struct iovec *iov,
+ struct cs_mode_zero_data *mode_data,
+ uint8_t cs_role)
+{
+ uint32_t freq_offset;
+
+ if (iov->iov_len < 3) {
+ DBG("Mode 0: too short (<3)");
+ return;
+ }
+
+ util_iov_pull_u8(iov, &mode_data->packet_quality);
+ util_iov_pull_u8(iov, &mode_data->packet_rssi_dbm);
+ util_iov_pull_u8(iov, &mode_data->packet_ant);
+ DBG("CS Step mode 0");
+
+ if (cs_role == CS_INITIATOR && iov->iov_len >= 4) {
+ util_iov_pull_le32(iov, &freq_offset);
+ mode_data->init_measured_freq_offset = freq_offset;
+ }
+}
+
+/* Parse CS Mode 1 step data */
+static void parse_mode_one_data(struct iovec *iov,
+ struct cs_mode_one_data *mode_data,
+ uint8_t cs_role, uint8_t cs_rtt_type)
+{
+ uint16_t time_val;
+
+ if (iov->iov_len < 4) {
+ DBG("Mode 1: too short (<4)");
+ return;
+ }
+
+ DBG("CS Step mode 1");
+ util_iov_pull_u8(iov, &mode_data->packet_quality);
+ util_iov_pull_u8(iov, &mode_data->packet_rssi_dbm);
+ util_iov_pull_u8(iov, &mode_data->packet_ant);
+ util_iov_pull_u8(iov, &mode_data->packet_nadm);
+
+ if (iov->iov_len >= 2) {
+ util_iov_pull_le16(iov, &time_val);
+ if (cs_role == CS_REFLECTOR)
+ mode_data->tod_toa_refl = time_val;
+ else
+ mode_data->toa_tod_init = time_val;
+ }
+
+ if ((cs_rtt_type == 0x01 || cs_rtt_type == 0x02) &&
+ iov->iov_len >= 6) {
+ int16_t i_val, q_val;
+
+ parse_i_q_sample(iov, &i_val, &q_val);
+ mode_data->packet_pct1.i_sample = i_val;
+ mode_data->packet_pct1.q_sample = q_val;
+
+ parse_i_q_sample(iov, &i_val, &q_val);
+ mode_data->packet_pct2.i_sample = i_val;
+ mode_data->packet_pct2.q_sample = q_val;
+ }
+}
+
+/* Parse CS Mode 2 step data */
+static void parse_mode_two_data(struct iovec *iov,
+ struct cs_mode_two_data *mode_data,
+ uint8_t max_paths)
+{
+ uint8_t k;
+
+ if (iov->iov_len < 1) {
+ DBG("Mode 2: too short (<1)");
+ return;
+ }
+
+ util_iov_pull_u8(iov, &mode_data->ant_perm_index);
+ DBG("CS Step mode 2, max paths : %d", max_paths);
+
+ for (k = 0; k < max_paths; k++) {
+ int16_t i_val, q_val;
+
+ if (iov->iov_len < 4) {
+ DBG("Mode 2: insufficient PCT for path %u (rem=%zu)",
+ k, iov->iov_len);
+ break;
+ }
+ parse_i_q_sample(iov, &i_val, &q_val);
+ mode_data->tone_pct[k].i_sample = i_val;
+ mode_data->tone_pct[k].q_sample = q_val;
+
+ util_iov_pull_u8(iov, &mode_data->tone_quality_indicator[k]);
+ DBG("tone_quality_indicator : %d",
+ mode_data->tone_quality_indicator[k]);
+ DBG("[i, q] : %d, %d",
+ mode_data->tone_pct[k].i_sample,
+ mode_data->tone_pct[k].q_sample);
+ }
+}
+
+/* Parse CS Mode 3 step data */
+static void parse_mode_three_data(struct iovec *iov,
+ struct cs_mode_three_data *mode_data,
+ 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;
+
+ if (iov->iov_len < 4) {
+ DBG("Mode 3: mode1 too short (<4)");
+ return;
+ }
+
+ DBG("CS Step mode 3");
+
+ /* Parse Mode 1 portion */
+ 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 a single CS step */
+static void parse_cs_step(struct iovec *iov, struct cs_step_data *step,
+ uint8_t cs_role, uint8_t cs_rtt_type,
+ uint8_t max_paths)
+{
+ uint8_t mode;
+ uint8_t chnl;
+ uint8_t length;
+
+ /* Check if we have enough data for the 3-byte header */
+ if (iov->iov_len < 3) {
+ DBG("Truncated header for step");
+ return;
+ }
+
+ /* Read mode, channel, and length (3-byte header) */
+ if (!util_iov_pull_u8(iov, &mode) ||
+ !util_iov_pull_u8(iov, &chnl) ||
+ !util_iov_pull_u8(iov, &length)) {
+ DBG("Failed to read header for step");
+ return;
+ }
+
+ DBG("event->step_data_len : %d", length);
+
+ step->step_mode = mode;
+ step->step_chnl = chnl;
+ step->step_data_length = length;
+
+ DBG("Step: mode=%u chnl=%u data_len=%u", mode, chnl, length);
+
+ if (iov->iov_len < length) {
+ DBG("Truncated payload for step (need %u, have %zu)",
+ length, iov->iov_len);
+ return;
+ }
+
+ /* Parse step data based on mode */
+ switch (mode) {
+ case CS_MODE_ZERO:
+ parse_mode_zero_data(iov, &step->step_mode_data.mode_zero_data,
+ cs_role);
+ break;
+ case CS_MODE_ONE:
+ parse_mode_one_data(iov, &step->step_mode_data.mode_one_data,
+ cs_role, cs_rtt_type);
+ break;
+ case CS_MODE_TWO:
+ parse_mode_two_data(iov, &step->step_mode_data.mode_two_data,
+ max_paths);
+ break;
+ case CS_MODE_THREE:
+ parse_mode_three_data(iov,
+ &step->step_mode_data.mode_three_data,
+ cs_role, cs_rtt_type, max_paths);
+ break;
+ default:
+ DBG("Unknown step mode %d", mode);
+ /* Skip the entire step data */
+ util_iov_pull(iov, length);
+ break;
+ }
+}
+
+static void rap_cs_subevt_result_evt(const uint8_t *data, uint8_t size,
+ void *user_data)
+{
+ struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
+ struct rap_ev_cs_subevent_result *rap_ev;
+ struct iovec iov;
+ uint8_t cs_role;
+ uint8_t cs_rtt_type;
+ uint8_t max_paths;
+ uint8_t steps;
+ size_t send_len = 0;
+ uint16_t handle;
+ uint8_t config_id;
+ uint16_t start_acl_conn_evt_counter;
+ uint16_t proc_counter;
+ uint16_t freq_comp;
+ uint8_t ref_pwr_lvl;
+ uint8_t proc_done_status;
+ uint8_t subevt_done_status;
+ uint8_t abort_reason;
+ uint8_t num_ant_paths;
+ uint8_t num_steps_reported;
+ uint8_t i;
+
+ if (!sm || !data ||
+ size < sizeof(struct bt_hci_evt_le_cs_subevent_result))
+ return;
+
+ /* Initialize iovec with the event data */
+ iov.iov_base = (void *)data;
+ iov.iov_len = size;
+
+ /* Check if Procedure is active or not */
+ if (!sm->procedure_active) {
+ DBG("Received Subevent event when Procedure is inactive!");
+ return;
+ }
+
+ /* Parse header fields using iovec */
+ if (!util_iov_pull_le16(&iov, &handle)) {
+ DBG("[ERROR] Failed to parse Connection_Handle\n");
+ return;
+ }
+
+ if (!util_iov_pull_u8(&iov, &config_id) ||
+ !util_iov_pull_le16(&iov, &start_acl_conn_evt_counter) ||
+ !util_iov_pull_le16(&iov, &proc_counter) ||
+ !util_iov_pull_le16(&iov, &freq_comp) ||
+ !util_iov_pull_u8(&iov, &ref_pwr_lvl) ||
+ !util_iov_pull_u8(&iov, &proc_done_status) ||
+ !util_iov_pull_u8(&iov, &subevt_done_status) ||
+ !util_iov_pull_u8(&iov, &abort_reason) ||
+ !util_iov_pull_u8(&iov, &num_ant_paths) ||
+ !util_iov_pull_u8(&iov, &num_steps_reported)) {
+ DBG("[ERROR] Failed to parse subevent fields\n");
+ return;
+ }
+
+ cs_role = cs_opt.role;
+ cs_rtt_type = cs_opt.rtt_type;
+ max_paths = MIN((num_ant_paths + 1), CS_MAX_ANT_PATHS);
+ steps = MIN(num_steps_reported, CS_MAX_STEPS);
+ send_len = offsetof(struct rap_ev_cs_subevent_result, step_data) +
+ steps * sizeof(struct cs_step_data);
+ rap_ev = (struct rap_ev_cs_subevent_result *)malloc(send_len);
+ if (!rap_ev) {
+ DBG("[ERROR] Failed to allocate memory for subevent result\n");
+ return;
+ }
+
+ DBG("[EVENT] Subevent Result (length=%u)\n", size);
+ rap_ev->conn_hdl = le16_to_cpu(handle);
+ rap_ev->config_id = config_id;
+ rap_ev->start_acl_conn_evt_counter = start_acl_conn_evt_counter;
+ rap_ev->proc_counter = proc_counter;
+ rap_ev->freq_comp = freq_comp;
+ rap_ev->ref_pwr_lvl = ref_pwr_lvl;
+ rap_ev->proc_done_status = proc_done_status;
+ rap_ev->subevt_done_status = subevt_done_status;
+ rap_ev->abort_reason = abort_reason;
+ rap_ev->num_ant_paths = num_ant_paths;
+ rap_ev->num_steps_reported = steps;
+
+ if (num_steps_reported > CS_MAX_STEPS) {
+ DBG("Too many steps reported: %u (max %u)",
+ num_steps_reported, CS_MAX_STEPS);
+ goto send_event;
+ }
+
+ /* Early exit for error conditions */
+ if (rap_ev->subevt_done_status == 0xF ||
+ rap_ev->proc_done_status == 0xF) {
+ DBG("CS Procedure/Subevent aborted: ");
+ DBG("sub evt status = %d, proc status = %d, reason = %d",
+ rap_ev->subevt_done_status, rap_ev->proc_done_status,
+ rap_ev->abort_reason);
+ goto send_event;
+ }
+
+ /* Parse interleaved step data from remaining iovec data */
+ for (i = 0; i < steps; i++)
+ parse_cs_step(&iov, &rap_ev->step_data[i], cs_role, cs_rtt_type,
+ max_paths);
+
+send_event:
+ DBG("CS subevent result processed: %zu bytes, ", send_len);
+ bt_rap_hci_cs_subevent_result_callback(send_len, rap_ev, sm->rap);
+ free(rap_ev);
+}
+
+static void rap_cs_subevt_result_cont_evt(const uint8_t *data, uint8_t size,
+ void *user_data)
+{
+ struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
+ struct rap_ev_cs_subevent_result_cont *rap_ev;
+ struct iovec iov;
+ uint8_t cs_role;
+ uint8_t cs_rtt_type;
+ uint8_t max_paths;
+ uint8_t steps;
+ size_t send_len = 0;
+ uint16_t handle;
+ uint8_t config_id;
+ uint8_t proc_done_status;
+ uint8_t subevt_done_status;
+ uint8_t abort_reason;
+ uint8_t num_ant_paths;
+ uint8_t num_steps_reported;
+ uint8_t i;
+
+ if (!sm || !data ||
+ size < sizeof(struct bt_hci_evt_le_cs_subevent_result_continue))
+ return;
+
+ /* Initialize iovec with the event data */
+ iov.iov_base = (void *)data;
+ iov.iov_len = size;
+
+ /* Check if Procedure is active or not */
+ if (!sm->procedure_active) {
+ DBG("Received Subevent when CS Procedure is inactive!");
+ return;
+ }
+
+ /* Parse header fields using iovec */
+ if (!util_iov_pull_le16(&iov, &handle)) {
+ DBG("[ERROR] Failed to parse Connection_Handle\n");
+ return;
+ }
+
+ if (!util_iov_pull_u8(&iov, &config_id) ||
+ !util_iov_pull_u8(&iov, &proc_done_status) ||
+ !util_iov_pull_u8(&iov, &subevt_done_status) ||
+ !util_iov_pull_u8(&iov, &abort_reason) ||
+ !util_iov_pull_u8(&iov, &num_ant_paths) ||
+ !util_iov_pull_u8(&iov, &num_steps_reported)) {
+ DBG("[ERROR] Failed to parse subevent continue fields ");
+ return;
+ }
+
+ cs_role = cs_opt.role;
+ cs_rtt_type = cs_opt.rtt_type;
+ max_paths = MIN((num_ant_paths + 1), CS_MAX_ANT_PATHS);
+ steps = MIN(num_steps_reported, CS_MAX_STEPS);
+ send_len = offsetof(struct rap_ev_cs_subevent_result_cont, step_data) +
+ steps * sizeof(struct cs_step_data);
+ rap_ev = (struct rap_ev_cs_subevent_result_cont *)malloc(send_len);
+ if (!rap_ev) {
+ DBG("[ERROR] Failed to allocate memory for subevent result\n");
+ return;
+ }
+
+ DBG("[EVENT] Subevent Result Cont (length=%u)\n", size);
+ rap_ev->conn_hdl = le16_to_cpu(handle);
+ rap_ev->config_id = config_id;
+ rap_ev->proc_done_status = proc_done_status;
+ rap_ev->subevt_done_status = subevt_done_status;
+ rap_ev->abort_reason = abort_reason;
+ rap_ev->num_ant_paths = num_ant_paths;
+ rap_ev->num_steps_reported = steps;
+
+ if (num_steps_reported > CS_MAX_STEPS) {
+ DBG("Too many steps reported: %u (max %u)",
+ num_steps_reported, CS_MAX_STEPS);
+ goto send_event;
+ }
+
+ /* Early exit for error conditions */
+ if (rap_ev->subevt_done_status == 0xF ||
+ rap_ev->proc_done_status == 0xF) {
+ DBG("CS Procedure/Subevent aborted: ");
+ DBG("sub evt status = %d, proc status = %d, reason = %d",
+ rap_ev->subevt_done_status, rap_ev->proc_done_status,
+ rap_ev->abort_reason);
+ goto send_event;
+ }
+
+ /* Parse interleaved step data from remaining iovec data */
+ for (i = 0; i < steps; i++)
+ parse_cs_step(&iov, &rap_ev->step_data[i], cs_role, cs_rtt_type,
+ max_paths);
+
+send_event:
+ DBG("CS subevent result cont processed: %zu bytes, ", send_len);
+ bt_rap_hci_cs_subevent_result_cont_callback(send_len, rap_ev, sm->rap);
+ free(rap_ev);
+}
+
+/* Subevent handler function type */
+typedef void (*subevent_handler_t)(const uint8_t *data, uint8_t size,
+ void *user_data);
+
+/* Subevent table entry */
+struct subevent_entry {
+ uint8_t opcode;
+ uint8_t min_len;
+ uint8_t max_len;
+ subevent_handler_t handler;
+ const char *name;
+};
+
+/* Subevent dispatch table */
+static const struct subevent_entry subevent_table[] = {
+ {
+ .opcode = BT_HCI_EVT_LE_CS_RD_REM_SUPP_CAP_COMPLETE,
+ .min_len = sizeof(
+ struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete),
+ .max_len = 0xFF,
+ .handler = rap_rd_rmt_supp_cap_cmplt_evt,
+ .name = "CS Read Remote Supported Capabilities Complete"
+ },
+ {
+ .opcode = BT_HCI_EVT_LE_CS_CONFIG_COMPLETE,
+ .min_len = sizeof(struct bt_hci_evt_le_cs_config_complete),
+ .max_len = 0xFF,
+ .handler = rap_cs_config_cmplt_evt,
+ .name = "CS Config Complete"
+ },
+ {
+ .opcode = BT_HCI_EVT_LE_CS_SEC_ENABLE_COMPLETE,
+ .min_len = sizeof(struct bt_hci_evt_le_cs_sec_enable_complete),
+ .max_len = 0xFF,
+ .handler = rap_cs_sec_enable_cmplt_evt,
+ .name = "CS Security Enable Complete"
+ },
+ {
+ .opcode = BT_HCI_EVT_LE_CS_PROC_ENABLE_COMPLETE,
+ .min_len = sizeof(struct bt_hci_evt_le_cs_proc_enable_complete),
+ .max_len = 0xFF,
+ .handler = rap_cs_proc_enable_cmplt_evt,
+ .name = "CS Procedure Enable Complete"
+ },
+ {
+ .opcode = BT_HCI_EVT_LE_CS_SUBEVENT_RESULT,
+ .min_len = sizeof(struct bt_hci_evt_le_cs_subevent_result),
+ .max_len = 0xFF,
+ .handler = rap_cs_subevt_result_evt,
+ .name = "CS Subevent Result"
+ },
+ {
+ .opcode = BT_HCI_EVT_LE_CS_SUBEVENT_RESULT_CONTINUE,
+ .min_len = sizeof(
+ struct bt_hci_evt_le_cs_subevent_result_continue),
+ .max_len = 0xFF,
+ .handler = rap_cs_subevt_result_cont_evt,
+ .name = "CS Subevent Result Continue"
+ }
+};
+
+#define SUBEVENT_TABLE_SIZE ARRAY_SIZE(subevent_table)
+
+/* HCI Event Registration */
+static void rap_handle_hci_events(const void *data, uint8_t size,
+ void *user_data)
+{
+ struct iovec iov;
+ uint8_t subevent;
+ const struct subevent_entry *entry = NULL;
+ size_t i;
+
+ /* Initialize iovec with the event data */
+ iov.iov_base = (void *)data;
+ iov.iov_len = size;
+
+ /* Pull the subevent code */
+ if (!util_iov_pull_u8(&iov, &subevent)) {
+ DBG("Failed to parse subevent code");
+ return;
+ }
+
+ /* Find the subevent in the table */
+ for (i = 0; i < SUBEVENT_TABLE_SIZE; i++) {
+ if (subevent_table[i].opcode == subevent) {
+ entry = &subevent_table[i];
+ break;
+ }
+ }
+
+ /* Check if subevent is supported */
+ if (!entry) {
+ DBG("Unknown subevent: 0x%02X", subevent);
+ return;
+ }
+
+ /* Validate payload length */
+ if (iov.iov_len < entry->min_len) {
+ DBG("%s: payload too short (%zu < %u)",
+ entry->name, iov.iov_len, entry->min_len);
+ return;
+ }
+
+ if (entry->max_len != 0xFF && iov.iov_len > entry->max_len) {
+ DBG("%s: payload too long (%zu > %u)",
+ entry->name, iov.iov_len, entry->max_len);
+ return;
+ }
+
+ /* Call the handler */
+ DBG("Handling %s (opcode=0x%02X, len=%zu)",
+ entry->name, subevent, iov.iov_len);
+
+ entry->handler(iov.iov_base, iov.iov_len, user_data);
+}
+
+void bt_rap_hci_register_events(struct bt_rap *rap, struct bt_hci *hci)
+{
+ if (!rap || !hci)
+ return;
+
+ sm = new0(struct cs_state_machine_t, 1);
+ if (!sm) {
+ DBG("[ERROR] Failed to allocate state machine\n");
+ return;
+ }
+
+ cs_state_machine_init(sm, rap, hci);
+ sm->event_id = bt_hci_register(hci, BT_HCI_EVT_LE_META_EVENT,
+ rap_handle_hci_events, sm, NULL);
+
+ DBG("bt_hci_register done, event_id : %d", sm->event_id);
+
+ if (!sm->event_id) {
+ DBG("Error: Failed to register hci le meta events ");
+ DBG("event_id=0x%02X\n", sm->event_id);
+ free(sm);
+ return;
+ }
+}
+
+bool bt_rap_attach_hci(struct bt_rap *rap, struct bt_hci *hci)
+{
+ if (!rap)
+ return false;
+
+ if (!hci) {
+ DBG("Failed to create HCI RAW channel ");
+ bt_hci_unref(hci);
+ return false;
+ }
+
+ bt_rap_hci_register_events(rap, hci);
+
+ return true;
+}
+
+bool bt_rap_set_conn_handle(struct bt_rap *rap, uint16_t handle,
+ const uint8_t *bdaddr, uint8_t bdaddr_type)
+{
+ struct bt_att *att;
+
+ if (!rap)
+ return false;
+
+ att = bt_rap_get_att(rap);
+ if (!att)
+ return false;
+
+ DBG("Setting connection mapping: handle=0x%04X, ", handle);
+ if (bdaddr) {
+ DBG("bdaddr=%02x:%02x:%02x:%02x:%02x:%02x type=%u",
+ bdaddr[5], bdaddr[4], bdaddr[3],
+ bdaddr[2], bdaddr[1], bdaddr[0], bdaddr_type);
+ }
+
+ return add_conn_mapping(handle, bdaddr, bdaddr_type, att, rap);
+}
+
+void bt_rap_clear_conn_handle(struct bt_rap *rap, uint16_t handle)
+{
+ if (!rap)
+ return;
+
+ DBG("Clearing connection mapping: handle=0x%04X", handle);
+ remove_conn_mapping(handle);
+}
+
+void bt_rap_detach_hci(struct bt_rap *rap)
+{
+ if (!rap)
+ return;
+
+ DBG("Detaching RAP from HCI, cleaning up mappings");
+
+ /* Remove all mappings associated with this RAP instance */
+ remove_rap_mappings(rap);
+}
--
^ permalink raw reply related
* [PATCH BlueZ v6 2/3] main.conf: Add Channel Sounding config parsing support
From: Naga Bhavani Akella @ 2026-04-14 15:33 UTC (permalink / raw)
To: linux-bluetooth
Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
prathibha.madugonde, Naga Bhavani Akella
In-Reply-To: <20260414153335.3169542-1-naga.akella@oss.qualcomm.com>
Add support for parsing Channel Sounding (CS) configuration options
from the configuration file.
Add CAP_NET_RAW to CapabilityBoundingSet in bluetooth.service.
bluetoothd requires CAP_NET_RAW to receive and process HCI LE events
when running under a constrained systemd capability bounding set
---
src/bluetooth.service.in | 2 +-
src/btd.h | 7 +++
src/main.c | 129 +++++++++++++++++++++++++++++++++++++++
src/main.conf | 24 ++++++++
4 files changed, 161 insertions(+), 1 deletion(-)
diff --git a/src/bluetooth.service.in b/src/bluetooth.service.in
index 8ebe89bec..8dcbde236 100644
--- a/src/bluetooth.service.in
+++ b/src/bluetooth.service.in
@@ -10,7 +10,7 @@ ExecStart=@PKGLIBEXECDIR@/bluetoothd
NotifyAccess=main
#WatchdogSec=10
#Restart=on-failure
-CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
+CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN CAP_NET_BIND_SERVICE
LimitNPROC=1
# Filesystem lockdown
diff --git a/src/btd.h b/src/btd.h
index c84a600d1..db2e81239 100644
--- a/src/btd.h
+++ b/src/btd.h
@@ -94,11 +94,18 @@ struct btd_le_defaults {
uint8_t enable_advmon_interleave_scan;
};
+struct btd_le_bcs {
+ uint8_t role;
+ uint8_t cs_sync_ant_sel;
+ int8_t max_tx_power;
+};
+
struct btd_defaults {
uint16_t num_entries;
struct btd_br_defaults br;
struct btd_le_defaults le;
+ struct btd_le_bcs bcs;
};
struct btd_csis {
diff --git a/src/main.c b/src/main.c
index 818f7c06e..d3a2528e3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -156,6 +156,13 @@ static const char *gatt_options[] = {
NULL
};
+static const char *bcs_options[] = {
+ "Role",
+ "CsSyncAntennaSel",
+ "MaxTxPower",
+ NULL
+};
+
static const char *csip_options[] = {
"SIRK",
"Encryption",
@@ -193,6 +200,7 @@ static const struct group_table {
{ "CSIS", csip_options },
{ "AVDTP", avdtp_options },
{ "AVRCP", avrcp_options },
+ { "ChannelSounding", bcs_options },
{ "AdvMon", advmon_options },
{ }
};
@@ -492,6 +500,46 @@ static bool parse_config_int(GKeyFile *config, const char *group,
return true;
}
+static bool parse_config_signed_int(GKeyFile *config, const char *group,
+ const char *key, int8_t *val,
+ size_t min, size_t max)
+{
+ char *str = NULL;
+ char *endptr = NULL;
+ long tmp;
+ bool result = false;
+
+ str = g_key_file_get_string(config, group, key, NULL);
+ if (!str)
+ return false;
+
+ tmp = strtol(str, &endptr, 0);
+ if (!endptr || *endptr != '\0') {
+ warn("%s.%s = %s is not integer", group, key, str);
+ goto cleanup;
+ }
+
+ if (tmp < (long)min) {
+ warn("%s.%s = %ld is out of range (< %zu)", group, key, tmp,
+ min);
+ goto cleanup;
+ }
+
+ if (tmp > (long)max) {
+ warn("%s.%s = %ld is out of range (> %zu)", group, key, tmp,
+ max);
+ goto cleanup;
+ }
+
+ if (val)
+ *val = (int8_t)tmp;
+ result = true;
+
+cleanup:
+ g_free(str);
+ return result;
+}
+
struct config_param {
const char * const val_name;
void * const val;
@@ -1184,6 +1232,82 @@ static void parse_csis(GKeyFile *config)
0, UINT8_MAX);
}
+static bool parse_cs_role(GKeyFile *config, const char *group,
+ const char *key, uint8_t *val)
+{
+ GError *err = NULL;
+ char *str = NULL;
+ int numeric_val;
+
+ /* Try to read as string first */
+ str = g_key_file_get_string(config, group, key, &err);
+ if (err) {
+ if (err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND)
+ DBG("%s", err->message);
+ g_error_free(err);
+ return false;
+ }
+
+ DBG("%s.%s = %s", group, key, str);
+
+ /* Check if it's a string value */
+ if (!strcmp(str, "Initiator") || !strcmp(str, "initiator")) {
+ if (val)
+ *val = 1;
+ g_free(str);
+ return true;
+ } else if (!strcmp(str, "Reflector") || !strcmp(str, "reflector")) {
+ if (val)
+ *val = 2;
+ g_free(str);
+ return true;
+ } else if (!strcmp(str, "Both") || !strcmp(str, "both")) {
+ if (val)
+ *val = 3;
+ g_free(str);
+ return true;
+ }
+
+ /* Try to parse as numeric value */
+ char *endptr = NULL;
+
+ numeric_val = strtol(str, &endptr, 0);
+
+ if (!endptr || *endptr != '\0') {
+ error("%s.%s = %s is not a valid value. "
+ "Expected: 1/Initiator, 2/Reflector, or 3/Both",
+ group, key, str);
+ g_free(str);
+ return false;
+ }
+
+ if (numeric_val < 1 || numeric_val > 3) {
+ warn("%s.%s = %d is out of range. "
+ "Valid values: 1 (Initiator), 2 (Reflector), 3 (Both)",
+ group, key, numeric_val);
+ g_free(str);
+ return false;
+ }
+
+ if (val)
+ *val = numeric_val;
+
+ g_free(str);
+ return true;
+}
+
+static void parse_le_cs_config(GKeyFile *config)
+{
+ parse_cs_role(config, "ChannelSounding", "Role",
+ &btd_opts.defaults.bcs.role);
+ parse_config_u8(config, "ChannelSounding", "CsSyncAntennaSel",
+ &btd_opts.defaults.bcs.cs_sync_ant_sel,
+ 0x01, 0xFF);
+ parse_config_signed_int(config, "ChannelSounding",
+ "MaxTxPower", &btd_opts.defaults.bcs.max_tx_power,
+ INT8_MIN, INT8_MAX);
+}
+
static void parse_avdtp_session_mode(GKeyFile *config)
{
char *str = NULL;
@@ -1262,6 +1386,7 @@ static void parse_config(GKeyFile *config)
parse_csis(config);
parse_avdtp(config);
parse_avrcp(config);
+ parse_le_cs_config(config);
parse_advmon(config);
}
@@ -1313,6 +1438,10 @@ static void init_defaults(void)
btd_opts.advmon.rssi_sampling_period = 0xFF;
btd_opts.csis.encrypt = true;
+
+ btd_opts.defaults.bcs.role = 0x03;
+ btd_opts.defaults.bcs.cs_sync_ant_sel = 0xFF;
+ btd_opts.defaults.bcs.max_tx_power = 0x14;
}
static void log_handler(const gchar *log_domain, GLogLevelFlags log_level,
diff --git a/src/main.conf b/src/main.conf
index d31dd1b8f..fc0138bbf 100644
--- a/src/main.conf
+++ b/src/main.conf
@@ -299,6 +299,30 @@
# Default = auto
# Security = auto
+[ChannelSounding]
+# Current role of the device
+# Possible values:
+# 1 or "Initiator" - CS Initiator role,
+# Generally, CS Initiator acts as Client (Gatt role) and Central (Gap role)
+# 2 or "Reflector" - CS Reflector role,
+# Generally, CS Reflector acts as Server (Gatt role) and Peripheral (Gap role)
+# 3 or "Both" - Both Initiator and Reflector roles
+# Default: 3 (Both)
+#Role = 3
+
+# Antenna Identifier to be used
+# Possible values:
+# 0x01-0x04 (antenna identifier to be used),
+# 0xFE - Antennas to be used in repetetive order,
+# 0xFF - Host doen't have recommendation
+# Default: 0xFF (Host doesn't have recommendation)
+#CsSyncAntennaSel = 0xFF
+
+# Maximum Transmit power
+# Possible values: 0x7F-0x14 (-127dBm to 20dBm)
+# Default: 0x14 (Max Power possible)
+#MaxTxPower = 0x14
+
[CSIS]
# SIRK - Set Identification Resolution Key which is common for all the
# sets. They SIRK key is used to identify its sets. This can be any
--
^ permalink raw reply related
* [PATCH BlueZ v6 1/3] shared: rap: Introduce Channel Sounding HCI raw interface support
From: Naga Bhavani Akella @ 2026-04-14 15:33 UTC (permalink / raw)
To: linux-bluetooth
Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
prathibha.madugonde, Naga Bhavani Akella
In-Reply-To: <20260414153335.3169542-1-naga.akella@oss.qualcomm.com>
Implement stub callbacks for Channel Sounding HCI events and add the
required protocol definitions for CS configuration, procedure control,
and subevent result parsing
Add data structures to support Channel Sounding Processing
Add helper function to get hci conn info list and integrate it with RAP
---
src/shared/hci.c | 67 +++++++++++++-----
src/shared/hci.h | 12 ++++
src/shared/rap.c | 50 +++++++++++++-
src/shared/rap.h | 174 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 285 insertions(+), 18 deletions(-)
diff --git a/src/shared/hci.c b/src/shared/hci.c
index 575254c09..a3343d63d 100644
--- a/src/shared/hci.c
+++ b/src/shared/hci.c
@@ -20,9 +20,11 @@
#include <sys/un.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
+#include "bluetooth/hci.h"
#include "monitor/bt.h"
#include "src/shared/mainloop.h"
#include "src/shared/io.h"
@@ -30,22 +32,6 @@
#include "src/shared/queue.h"
#include "src/shared/hci.h"
-#define BTPROTO_HCI 1
-struct sockaddr_hci {
- sa_family_t hci_family;
- unsigned short hci_dev;
- unsigned short hci_channel;
-};
-#define HCI_CHANNEL_RAW 0
-#define HCI_CHANNEL_USER 1
-
-#define SOL_HCI 0
-#define HCI_FILTER 2
-struct hci_filter {
- uint32_t type_mask;
- uint32_t event_mask[2];
- uint16_t opcode;
-};
struct bt_hci {
int ref_count;
@@ -673,3 +659,52 @@ bool bt_hci_unregister(struct bt_hci *hci, unsigned int id)
return true;
}
+
+bool bt_hci_get_conn_info(struct bt_hci *hci, uint16_t handle,
+ struct bt_hci_conn_info *info)
+{
+ struct hci_conn_list_req *cl;
+ struct hci_conn_info *ci;
+ int fd, i;
+ bool found = false;
+
+ if (!hci || !info)
+ return false;
+
+ fd = io_get_fd(hci->io);
+ if (fd < 0)
+ return false;
+
+ /* Allocate buffer for connection list request */
+ cl = malloc(10 * sizeof(*ci) + sizeof(*cl));
+ if (!cl)
+ return false;
+
+ memset(cl, 0, 10 * sizeof(*ci) + sizeof(*cl));
+ cl->dev_id = 0; /* Will be filled by ioctl */
+ cl->conn_num = 10;
+
+ /* Get connection list via ioctl */
+ if (ioctl(fd, HCIGETCONNLIST, (void *) cl) < 0) {
+ free(cl);
+ return false;
+ }
+
+ /* Search for the connection with matching handle */
+ ci = cl->conn_info;
+ for (i = 0; i < cl->conn_num; i++, ci++) {
+ if (ci->handle == handle) {
+ info->handle = ci->handle;
+ memcpy(info->bdaddr, &ci->bdaddr, 6);
+ info->type = ci->type;
+ info->out = ci->out;
+ info->state = ci->state;
+ info->link_mode = ci->link_mode;
+ found = true;
+ break;
+ }
+ }
+
+ free(cl);
+ return found;
+}
diff --git a/src/shared/hci.h b/src/shared/hci.h
index 76ee72f54..742e24897 100644
--- a/src/shared/hci.h
+++ b/src/shared/hci.h
@@ -13,6 +13,15 @@
typedef void (*bt_hci_destroy_func_t)(void *user_data);
+struct bt_hci_conn_info {
+ uint16_t handle;
+ uint8_t bdaddr[6];
+ uint8_t type;
+ uint8_t out;
+ uint16_t state;
+ uint32_t link_mode;
+};
+
struct bt_hci;
struct bt_hci *bt_hci_new(int fd);
@@ -41,3 +50,6 @@ unsigned int bt_hci_register(struct bt_hci *hci, uint8_t event,
bt_hci_callback_func_t callback,
void *user_data, bt_hci_destroy_func_t destroy);
bool bt_hci_unregister(struct bt_hci *hci, unsigned int id);
+
+bool bt_hci_get_conn_info(struct bt_hci *hci, uint16_t handle,
+ struct bt_hci_conn_info *info);
diff --git a/src/shared/rap.c b/src/shared/rap.c
index 39ef3f278..5745cda08 100644
--- a/src/shared/rap.c
+++ b/src/shared/rap.c
@@ -26,8 +26,8 @@
#include "src/shared/gatt-client.h"
#include "src/shared/rap.h"
-#define DBG(_rap, fmt, arg...) \
- rap_debug(_rap, "%s:%s() " fmt, __FILE__, __func__, ## arg)
+#define DBG(_rap, fmt, ...) \
+ rap_debug(_rap, "%s:%s() " fmt, __FILE__, __func__, ##__VA_ARGS__)
#define RAS_UUID16 0x185B
@@ -504,6 +504,52 @@ bool bt_rap_unregister(unsigned int id)
return true;
}
+void bt_rap_hci_cs_subevent_result_cont_callback(uint16_t length,
+ const void *param,
+ void *user_data)
+{
+ struct bt_rap *rap = user_data;
+
+ DBG(rap, "Received CS subevent CONT: len=%d", length);
+}
+
+void bt_rap_hci_cs_subevent_result_callback(uint16_t length,
+ const void *param,
+ void *user_data)
+{
+ struct bt_rap *rap = user_data;
+
+ DBG(rap, "Received CS subevent: len=%d", length);
+}
+
+void bt_rap_hci_cs_procedure_enable_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data)
+{
+ struct bt_rap *rap = user_data;
+
+ DBG(rap, "Received CS procedure enable complete subevent: len=%d",
+ length);
+}
+
+void bt_rap_hci_cs_sec_enable_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data)
+{
+ struct bt_rap *rap = user_data;
+
+ DBG(rap, "Received CS security enable subevent: len=%d", length);
+}
+
+void bt_rap_hci_cs_config_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data)
+{
+ struct bt_rap *rap = user_data;
+
+ DBG(rap, "Received CS config complete subevent: len=%d", length);
+}
+
struct bt_rap *bt_rap_new(struct gatt_db *ldb, struct gatt_db *rdb)
{
struct bt_rap *rap;
diff --git a/src/shared/rap.h b/src/shared/rap.h
index a1d1ff2ae..981daf588 100644
--- a/src/shared/rap.h
+++ b/src/shared/rap.h
@@ -9,9 +9,154 @@
#include <inttypes.h>
#include "src/shared/io.h"
+#include "bluetooth/mgmt.h"
+#include "src/shared/hci.h"
struct bt_rap;
+/* Channel Sounding Events */
+struct bt_rap_hci_cs_options {
+ uint8_t role;
+ uint8_t cs_sync_ant_sel;
+ int8_t max_tx_power;
+ int rtt_type;
+};
+
+#define CS_MODE_ZERO 0x00
+#define CS_MODE_ONE 0x01
+#define CS_MODE_TWO 0x02
+#define CS_MODE_THREE 0x03
+
+#define CS_REFLECTOR 0x01
+#define CS_INITIATOR 0x00
+
+#define CS_MAX_ANT_PATHS 0x05
+#define CS_MAX_STEPS 0xA0
+#define CS_MAX_STEP_DATA_LEN 0xFF
+
+struct rap_ev_cs_config_cmplt {
+ uint8_t status;
+ uint16_t conn_hdl;
+ uint8_t config_id;
+ uint8_t action;
+ uint8_t main_mode_type;
+ uint8_t sub_mode_type;
+ uint8_t min_main_mode_steps;
+ uint8_t max_main_mode_steps;
+ uint8_t main_mode_rep;
+ uint8_t mode_0_steps;
+ uint8_t role;
+ uint8_t rtt_type;
+ uint8_t cs_sync_phy;
+ uint8_t channel_map[10];
+ uint8_t channel_map_rep;
+ uint8_t channel_sel_type;
+ uint8_t ch3c_shape;
+ uint8_t ch3c_jump;
+ uint8_t reserved;
+ uint8_t t_ip1_time;
+ uint8_t t_ip2_time;
+ uint8_t t_fcs_time;
+ uint8_t t_pm_time;
+} __packed;
+
+struct rap_ev_cs_sec_enable_cmplt {
+ uint8_t status;
+ uint16_t conn_hdl;
+} __packed;
+
+struct rap_ev_cs_proc_enable_cmplt {
+ uint8_t status;
+ uint16_t conn_hdl;
+ uint8_t config_id;
+ uint8_t state;
+ uint8_t tone_ant_config_sel;
+ int8_t sel_tx_pwr;
+ uint8_t sub_evt_len[3];
+ uint8_t sub_evts_per_evt;
+ uint16_t sub_evt_intrvl;
+ uint16_t evt_intrvl;
+ uint16_t proc_intrvl;
+ uint16_t proc_counter;
+ uint16_t max_proc_len;
+} __packed;
+
+#define CS_MAX_STEPS 0xA0
+
+struct pct_iq_sample {
+ int16_t i_sample;
+ int16_t q_sample;
+} __packed;
+
+struct cs_mode_zero_data {
+ uint8_t packet_quality;
+ uint8_t packet_rssi_dbm;
+ uint8_t packet_ant;
+ uint32_t init_measured_freq_offset;
+} __packed;
+
+struct cs_mode_one_data {
+ uint8_t packet_quality;
+ uint8_t packet_rssi_dbm;
+ uint8_t packet_ant;
+ uint8_t packet_nadm;
+ int16_t toa_tod_init;
+ int16_t tod_toa_refl;
+ struct pct_iq_sample packet_pct1;
+ struct pct_iq_sample packet_pct2;
+} __packed;
+
+struct cs_mode_two_data {
+ uint8_t ant_perm_index;
+ struct pct_iq_sample tone_pct[4];
+ uint8_t tone_quality_indicator[4];
+} __packed;
+
+struct cs_mode_three_data {
+ struct cs_mode_one_data mode_one_data;
+ struct cs_mode_two_data mode_two_data;
+} __packed;
+
+union cs_mode_data {
+ struct cs_mode_zero_data mode_zero_data;
+ struct cs_mode_one_data mode_one_data;
+ struct cs_mode_two_data mode_two_data;
+ struct cs_mode_three_data mode_three_data;
+};
+
+struct cs_step_data {
+ uint8_t step_mode;
+ uint8_t step_chnl;
+ uint8_t step_data_length;
+ union cs_mode_data step_mode_data;
+} __packed;
+
+struct rap_ev_cs_subevent_result {
+ uint16_t conn_hdl;
+ uint8_t config_id;
+ uint16_t start_acl_conn_evt_counter;
+ uint16_t proc_counter;
+ uint16_t freq_comp;
+ uint8_t ref_pwr_lvl;
+ uint8_t proc_done_status;
+ uint8_t subevt_done_status;
+ uint8_t abort_reason;
+ uint8_t num_ant_paths;
+ uint8_t num_steps_reported;
+ struct cs_step_data step_data[];
+} __packed;
+
+struct rap_ev_cs_subevent_result_cont {
+ uint16_t conn_hdl;
+ uint8_t config_id;
+ uint8_t proc_done_status;
+ uint8_t subevt_done_status;
+ uint8_t abort_reason;
+ uint8_t num_ant_paths;
+ uint8_t num_steps_reported;
+ struct cs_step_data step_data[];
+} __packed;
+
typedef void (*bt_rap_debug_func_t)(const char *str, void *user_data);
typedef void (*bt_rap_ready_func_t)(struct bt_rap *rap, void *user_data);
typedef void (*bt_rap_destroy_func_t)(void *user_data);
@@ -43,3 +188,32 @@ bool bt_rap_ready_unregister(struct bt_rap *rap, unsigned int id);
bool bt_rap_unregister(unsigned int id);
struct bt_rap *bt_rap_new(struct gatt_db *ldb, struct gatt_db *rdb);
+
+/* HCI Raw Channel Approach */
+void bt_rap_hci_cs_config_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data);
+void bt_rap_hci_cs_sec_enable_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data);
+void bt_rap_hci_cs_procedure_enable_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data);
+void bt_rap_hci_cs_subevent_result_callback(uint16_t length,
+ const void *param,
+ void *user_data);
+void bt_rap_hci_cs_subevent_result_cont_callback(uint16_t length,
+ const void *param,
+ void *user_data);
+
+void bt_rap_hci_set_le_bcs_options(uint8_t role, uint8_t cs_sync_ant_sel,
+ int8_t max_tx_power);
+
+bool bt_rap_attach_hci(struct bt_rap *rap, struct bt_hci *hci);
+void bt_rap_detach_hci(struct bt_rap *rap);
+void bt_rap_hci_sm_cleanup(void);
+
+/* Connection handle mapping functions */
+bool bt_rap_set_conn_handle(struct bt_rap *rap, uint16_t handle,
+ const uint8_t *bdaddr, uint8_t bdaddr_type);
+void bt_rap_clear_conn_handle(struct bt_rap *rap, uint16_t handle);
--
^ permalink raw reply related
* [PATCH BlueZ v6 0/3] Add initial Channel Sounding support
From: Naga Bhavani Akella @ 2026-04-14 15:33 UTC (permalink / raw)
To: linux-bluetooth
Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
prathibha.madugonde, Naga Bhavani Akella
This patch series introduces initial support for Bluetooth Channel
Sounding (CS) using the raw HCI interface.
This series lays the groundwork for CS support by adding commonly required
protocol definitions, configuration parsing, and event handling for
the reflector role.
The changes include:
1) Introduction of raw HCI support structures and callbacks for Channel
Sounding procedures and events. This provides the foundational data
definitions and HCI subevent handling needed by higher-level profiles
2) Addition of Channel Sounding configuration parsing from the BlueZ
configuration file.This patch also updates the systemd
service capability bounding set to include CAP_NET_RAW, which is
required for bluetoothd to receive and process LE Channel Sounding
events when running under a constrained systemd environment
3) Implementation of HCI LE Channel Sounding event handling in the
Ranging profile for the reflector role.
This includes opening a raw HCI channel,
parsing relevant CS LE events, routing them to the RAP profile
Patch overview:
1/3 shared: rap: introduce Channel Sounding HCI raw interface support
2/3 main.conf: add Channel Sounding config parsing support
3/3 profiles: ranging: add HCI LE Channel Sounding event handling
Changes in v6:
Missed sending patchset 3 in v5
Changes in v5:
Changed the commit message for patchset 2
Naga Bhavani Akella (3):
shared: rap: Introduce Channel Sounding HCI raw interface support
main.conf: Add Channel Sounding config parsing support
profiles: ranging: Add HCI LE Event Handling in Reflector role
Makefile.plugins | 3 +-
profiles/ranging/rap.c | 83 ++-
profiles/ranging/rap_hci.c | 1288 ++++++++++++++++++++++++++++++++++++
src/bluetooth.service.in | 2 +-
src/btd.h | 7 +
src/main.c | 129 ++++
src/main.conf | 24 +
src/shared/hci.c | 67 +-
src/shared/hci.h | 12 +
src/shared/rap.c | 50 +-
src/shared/rap.h | 174 +++++
11 files changed, 1813 insertions(+), 26 deletions(-)
create mode 100644 profiles/ranging/rap_hci.c
--
^ permalink raw reply
* [PATCH BlueZ v5 2/3] main.conf: Add Channel Sounding config parsing support
From: Naga Bhavani Akella @ 2026-04-14 15:08 UTC (permalink / raw)
To: linux-bluetooth
Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
prathibha.madugonde, Naga Bhavani Akella
In-Reply-To: <20260414150806.3135253-1-naga.akella@oss.qualcomm.com>
Add support for parsing Channel Sounding (CS) configuration options
from the configuration file.
Add CAP_NET_RAW to CapabilityBoundingSet in bluetooth.service.
bluetoothd requires CAP_NET_RAW to receive and process HCI LE events
when running under a constrained systemd capability bounding set
---
src/bluetooth.service.in | 2 +-
src/btd.h | 7 +++
src/main.c | 129 +++++++++++++++++++++++++++++++++++++++
src/main.conf | 24 ++++++++
4 files changed, 161 insertions(+), 1 deletion(-)
diff --git a/src/bluetooth.service.in b/src/bluetooth.service.in
index 8ebe89bec..8dcbde236 100644
--- a/src/bluetooth.service.in
+++ b/src/bluetooth.service.in
@@ -10,7 +10,7 @@ ExecStart=@PKGLIBEXECDIR@/bluetoothd
NotifyAccess=main
#WatchdogSec=10
#Restart=on-failure
-CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
+CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN CAP_NET_BIND_SERVICE
LimitNPROC=1
# Filesystem lockdown
diff --git a/src/btd.h b/src/btd.h
index c84a600d1..db2e81239 100644
--- a/src/btd.h
+++ b/src/btd.h
@@ -94,11 +94,18 @@ struct btd_le_defaults {
uint8_t enable_advmon_interleave_scan;
};
+struct btd_le_bcs {
+ uint8_t role;
+ uint8_t cs_sync_ant_sel;
+ int8_t max_tx_power;
+};
+
struct btd_defaults {
uint16_t num_entries;
struct btd_br_defaults br;
struct btd_le_defaults le;
+ struct btd_le_bcs bcs;
};
struct btd_csis {
diff --git a/src/main.c b/src/main.c
index 818f7c06e..d3a2528e3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -156,6 +156,13 @@ static const char *gatt_options[] = {
NULL
};
+static const char *bcs_options[] = {
+ "Role",
+ "CsSyncAntennaSel",
+ "MaxTxPower",
+ NULL
+};
+
static const char *csip_options[] = {
"SIRK",
"Encryption",
@@ -193,6 +200,7 @@ static const struct group_table {
{ "CSIS", csip_options },
{ "AVDTP", avdtp_options },
{ "AVRCP", avrcp_options },
+ { "ChannelSounding", bcs_options },
{ "AdvMon", advmon_options },
{ }
};
@@ -492,6 +500,46 @@ static bool parse_config_int(GKeyFile *config, const char *group,
return true;
}
+static bool parse_config_signed_int(GKeyFile *config, const char *group,
+ const char *key, int8_t *val,
+ size_t min, size_t max)
+{
+ char *str = NULL;
+ char *endptr = NULL;
+ long tmp;
+ bool result = false;
+
+ str = g_key_file_get_string(config, group, key, NULL);
+ if (!str)
+ return false;
+
+ tmp = strtol(str, &endptr, 0);
+ if (!endptr || *endptr != '\0') {
+ warn("%s.%s = %s is not integer", group, key, str);
+ goto cleanup;
+ }
+
+ if (tmp < (long)min) {
+ warn("%s.%s = %ld is out of range (< %zu)", group, key, tmp,
+ min);
+ goto cleanup;
+ }
+
+ if (tmp > (long)max) {
+ warn("%s.%s = %ld is out of range (> %zu)", group, key, tmp,
+ max);
+ goto cleanup;
+ }
+
+ if (val)
+ *val = (int8_t)tmp;
+ result = true;
+
+cleanup:
+ g_free(str);
+ return result;
+}
+
struct config_param {
const char * const val_name;
void * const val;
@@ -1184,6 +1232,82 @@ static void parse_csis(GKeyFile *config)
0, UINT8_MAX);
}
+static bool parse_cs_role(GKeyFile *config, const char *group,
+ const char *key, uint8_t *val)
+{
+ GError *err = NULL;
+ char *str = NULL;
+ int numeric_val;
+
+ /* Try to read as string first */
+ str = g_key_file_get_string(config, group, key, &err);
+ if (err) {
+ if (err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND)
+ DBG("%s", err->message);
+ g_error_free(err);
+ return false;
+ }
+
+ DBG("%s.%s = %s", group, key, str);
+
+ /* Check if it's a string value */
+ if (!strcmp(str, "Initiator") || !strcmp(str, "initiator")) {
+ if (val)
+ *val = 1;
+ g_free(str);
+ return true;
+ } else if (!strcmp(str, "Reflector") || !strcmp(str, "reflector")) {
+ if (val)
+ *val = 2;
+ g_free(str);
+ return true;
+ } else if (!strcmp(str, "Both") || !strcmp(str, "both")) {
+ if (val)
+ *val = 3;
+ g_free(str);
+ return true;
+ }
+
+ /* Try to parse as numeric value */
+ char *endptr = NULL;
+
+ numeric_val = strtol(str, &endptr, 0);
+
+ if (!endptr || *endptr != '\0') {
+ error("%s.%s = %s is not a valid value. "
+ "Expected: 1/Initiator, 2/Reflector, or 3/Both",
+ group, key, str);
+ g_free(str);
+ return false;
+ }
+
+ if (numeric_val < 1 || numeric_val > 3) {
+ warn("%s.%s = %d is out of range. "
+ "Valid values: 1 (Initiator), 2 (Reflector), 3 (Both)",
+ group, key, numeric_val);
+ g_free(str);
+ return false;
+ }
+
+ if (val)
+ *val = numeric_val;
+
+ g_free(str);
+ return true;
+}
+
+static void parse_le_cs_config(GKeyFile *config)
+{
+ parse_cs_role(config, "ChannelSounding", "Role",
+ &btd_opts.defaults.bcs.role);
+ parse_config_u8(config, "ChannelSounding", "CsSyncAntennaSel",
+ &btd_opts.defaults.bcs.cs_sync_ant_sel,
+ 0x01, 0xFF);
+ parse_config_signed_int(config, "ChannelSounding",
+ "MaxTxPower", &btd_opts.defaults.bcs.max_tx_power,
+ INT8_MIN, INT8_MAX);
+}
+
static void parse_avdtp_session_mode(GKeyFile *config)
{
char *str = NULL;
@@ -1262,6 +1386,7 @@ static void parse_config(GKeyFile *config)
parse_csis(config);
parse_avdtp(config);
parse_avrcp(config);
+ parse_le_cs_config(config);
parse_advmon(config);
}
@@ -1313,6 +1438,10 @@ static void init_defaults(void)
btd_opts.advmon.rssi_sampling_period = 0xFF;
btd_opts.csis.encrypt = true;
+
+ btd_opts.defaults.bcs.role = 0x03;
+ btd_opts.defaults.bcs.cs_sync_ant_sel = 0xFF;
+ btd_opts.defaults.bcs.max_tx_power = 0x14;
}
static void log_handler(const gchar *log_domain, GLogLevelFlags log_level,
diff --git a/src/main.conf b/src/main.conf
index d31dd1b8f..fc0138bbf 100644
--- a/src/main.conf
+++ b/src/main.conf
@@ -299,6 +299,30 @@
# Default = auto
# Security = auto
+[ChannelSounding]
+# Current role of the device
+# Possible values:
+# 1 or "Initiator" - CS Initiator role,
+# Generally, CS Initiator acts as Client (Gatt role) and Central (Gap role)
+# 2 or "Reflector" - CS Reflector role,
+# Generally, CS Reflector acts as Server (Gatt role) and Peripheral (Gap role)
+# 3 or "Both" - Both Initiator and Reflector roles
+# Default: 3 (Both)
+#Role = 3
+
+# Antenna Identifier to be used
+# Possible values:
+# 0x01-0x04 (antenna identifier to be used),
+# 0xFE - Antennas to be used in repetetive order,
+# 0xFF - Host doen't have recommendation
+# Default: 0xFF (Host doesn't have recommendation)
+#CsSyncAntennaSel = 0xFF
+
+# Maximum Transmit power
+# Possible values: 0x7F-0x14 (-127dBm to 20dBm)
+# Default: 0x14 (Max Power possible)
+#MaxTxPower = 0x14
+
[CSIS]
# SIRK - Set Identification Resolution Key which is common for all the
# sets. They SIRK key is used to identify its sets. This can be any
--
^ permalink raw reply related
* [PATCH BlueZ v5 1/3] shared: rap: Introduce Channel Sounding HCI raw interface support
From: Naga Bhavani Akella @ 2026-04-14 15:08 UTC (permalink / raw)
To: linux-bluetooth
Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
prathibha.madugonde, Naga Bhavani Akella
In-Reply-To: <20260414150806.3135253-1-naga.akella@oss.qualcomm.com>
Implement stub callbacks for Channel Sounding HCI events and add the
required protocol definitions for CS configuration, procedure control,
and subevent result parsing
Add data structures to support Channel Sounding Processing
Add helper function to get hci conn info list and integrate it with RAP
---
src/shared/hci.c | 67 +++++++++++++-----
src/shared/hci.h | 12 ++++
src/shared/rap.c | 50 +++++++++++++-
src/shared/rap.h | 174 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 285 insertions(+), 18 deletions(-)
diff --git a/src/shared/hci.c b/src/shared/hci.c
index 575254c09..a3343d63d 100644
--- a/src/shared/hci.c
+++ b/src/shared/hci.c
@@ -20,9 +20,11 @@
#include <sys/un.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
+#include "bluetooth/hci.h"
#include "monitor/bt.h"
#include "src/shared/mainloop.h"
#include "src/shared/io.h"
@@ -30,22 +32,6 @@
#include "src/shared/queue.h"
#include "src/shared/hci.h"
-#define BTPROTO_HCI 1
-struct sockaddr_hci {
- sa_family_t hci_family;
- unsigned short hci_dev;
- unsigned short hci_channel;
-};
-#define HCI_CHANNEL_RAW 0
-#define HCI_CHANNEL_USER 1
-
-#define SOL_HCI 0
-#define HCI_FILTER 2
-struct hci_filter {
- uint32_t type_mask;
- uint32_t event_mask[2];
- uint16_t opcode;
-};
struct bt_hci {
int ref_count;
@@ -673,3 +659,52 @@ bool bt_hci_unregister(struct bt_hci *hci, unsigned int id)
return true;
}
+
+bool bt_hci_get_conn_info(struct bt_hci *hci, uint16_t handle,
+ struct bt_hci_conn_info *info)
+{
+ struct hci_conn_list_req *cl;
+ struct hci_conn_info *ci;
+ int fd, i;
+ bool found = false;
+
+ if (!hci || !info)
+ return false;
+
+ fd = io_get_fd(hci->io);
+ if (fd < 0)
+ return false;
+
+ /* Allocate buffer for connection list request */
+ cl = malloc(10 * sizeof(*ci) + sizeof(*cl));
+ if (!cl)
+ return false;
+
+ memset(cl, 0, 10 * sizeof(*ci) + sizeof(*cl));
+ cl->dev_id = 0; /* Will be filled by ioctl */
+ cl->conn_num = 10;
+
+ /* Get connection list via ioctl */
+ if (ioctl(fd, HCIGETCONNLIST, (void *) cl) < 0) {
+ free(cl);
+ return false;
+ }
+
+ /* Search for the connection with matching handle */
+ ci = cl->conn_info;
+ for (i = 0; i < cl->conn_num; i++, ci++) {
+ if (ci->handle == handle) {
+ info->handle = ci->handle;
+ memcpy(info->bdaddr, &ci->bdaddr, 6);
+ info->type = ci->type;
+ info->out = ci->out;
+ info->state = ci->state;
+ info->link_mode = ci->link_mode;
+ found = true;
+ break;
+ }
+ }
+
+ free(cl);
+ return found;
+}
diff --git a/src/shared/hci.h b/src/shared/hci.h
index 76ee72f54..742e24897 100644
--- a/src/shared/hci.h
+++ b/src/shared/hci.h
@@ -13,6 +13,15 @@
typedef void (*bt_hci_destroy_func_t)(void *user_data);
+struct bt_hci_conn_info {
+ uint16_t handle;
+ uint8_t bdaddr[6];
+ uint8_t type;
+ uint8_t out;
+ uint16_t state;
+ uint32_t link_mode;
+};
+
struct bt_hci;
struct bt_hci *bt_hci_new(int fd);
@@ -41,3 +50,6 @@ unsigned int bt_hci_register(struct bt_hci *hci, uint8_t event,
bt_hci_callback_func_t callback,
void *user_data, bt_hci_destroy_func_t destroy);
bool bt_hci_unregister(struct bt_hci *hci, unsigned int id);
+
+bool bt_hci_get_conn_info(struct bt_hci *hci, uint16_t handle,
+ struct bt_hci_conn_info *info);
diff --git a/src/shared/rap.c b/src/shared/rap.c
index 39ef3f278..5745cda08 100644
--- a/src/shared/rap.c
+++ b/src/shared/rap.c
@@ -26,8 +26,8 @@
#include "src/shared/gatt-client.h"
#include "src/shared/rap.h"
-#define DBG(_rap, fmt, arg...) \
- rap_debug(_rap, "%s:%s() " fmt, __FILE__, __func__, ## arg)
+#define DBG(_rap, fmt, ...) \
+ rap_debug(_rap, "%s:%s() " fmt, __FILE__, __func__, ##__VA_ARGS__)
#define RAS_UUID16 0x185B
@@ -504,6 +504,52 @@ bool bt_rap_unregister(unsigned int id)
return true;
}
+void bt_rap_hci_cs_subevent_result_cont_callback(uint16_t length,
+ const void *param,
+ void *user_data)
+{
+ struct bt_rap *rap = user_data;
+
+ DBG(rap, "Received CS subevent CONT: len=%d", length);
+}
+
+void bt_rap_hci_cs_subevent_result_callback(uint16_t length,
+ const void *param,
+ void *user_data)
+{
+ struct bt_rap *rap = user_data;
+
+ DBG(rap, "Received CS subevent: len=%d", length);
+}
+
+void bt_rap_hci_cs_procedure_enable_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data)
+{
+ struct bt_rap *rap = user_data;
+
+ DBG(rap, "Received CS procedure enable complete subevent: len=%d",
+ length);
+}
+
+void bt_rap_hci_cs_sec_enable_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data)
+{
+ struct bt_rap *rap = user_data;
+
+ DBG(rap, "Received CS security enable subevent: len=%d", length);
+}
+
+void bt_rap_hci_cs_config_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data)
+{
+ struct bt_rap *rap = user_data;
+
+ DBG(rap, "Received CS config complete subevent: len=%d", length);
+}
+
struct bt_rap *bt_rap_new(struct gatt_db *ldb, struct gatt_db *rdb)
{
struct bt_rap *rap;
diff --git a/src/shared/rap.h b/src/shared/rap.h
index a1d1ff2ae..981daf588 100644
--- a/src/shared/rap.h
+++ b/src/shared/rap.h
@@ -9,9 +9,154 @@
#include <inttypes.h>
#include "src/shared/io.h"
+#include "bluetooth/mgmt.h"
+#include "src/shared/hci.h"
struct bt_rap;
+/* Channel Sounding Events */
+struct bt_rap_hci_cs_options {
+ uint8_t role;
+ uint8_t cs_sync_ant_sel;
+ int8_t max_tx_power;
+ int rtt_type;
+};
+
+#define CS_MODE_ZERO 0x00
+#define CS_MODE_ONE 0x01
+#define CS_MODE_TWO 0x02
+#define CS_MODE_THREE 0x03
+
+#define CS_REFLECTOR 0x01
+#define CS_INITIATOR 0x00
+
+#define CS_MAX_ANT_PATHS 0x05
+#define CS_MAX_STEPS 0xA0
+#define CS_MAX_STEP_DATA_LEN 0xFF
+
+struct rap_ev_cs_config_cmplt {
+ uint8_t status;
+ uint16_t conn_hdl;
+ uint8_t config_id;
+ uint8_t action;
+ uint8_t main_mode_type;
+ uint8_t sub_mode_type;
+ uint8_t min_main_mode_steps;
+ uint8_t max_main_mode_steps;
+ uint8_t main_mode_rep;
+ uint8_t mode_0_steps;
+ uint8_t role;
+ uint8_t rtt_type;
+ uint8_t cs_sync_phy;
+ uint8_t channel_map[10];
+ uint8_t channel_map_rep;
+ uint8_t channel_sel_type;
+ uint8_t ch3c_shape;
+ uint8_t ch3c_jump;
+ uint8_t reserved;
+ uint8_t t_ip1_time;
+ uint8_t t_ip2_time;
+ uint8_t t_fcs_time;
+ uint8_t t_pm_time;
+} __packed;
+
+struct rap_ev_cs_sec_enable_cmplt {
+ uint8_t status;
+ uint16_t conn_hdl;
+} __packed;
+
+struct rap_ev_cs_proc_enable_cmplt {
+ uint8_t status;
+ uint16_t conn_hdl;
+ uint8_t config_id;
+ uint8_t state;
+ uint8_t tone_ant_config_sel;
+ int8_t sel_tx_pwr;
+ uint8_t sub_evt_len[3];
+ uint8_t sub_evts_per_evt;
+ uint16_t sub_evt_intrvl;
+ uint16_t evt_intrvl;
+ uint16_t proc_intrvl;
+ uint16_t proc_counter;
+ uint16_t max_proc_len;
+} __packed;
+
+#define CS_MAX_STEPS 0xA0
+
+struct pct_iq_sample {
+ int16_t i_sample;
+ int16_t q_sample;
+} __packed;
+
+struct cs_mode_zero_data {
+ uint8_t packet_quality;
+ uint8_t packet_rssi_dbm;
+ uint8_t packet_ant;
+ uint32_t init_measured_freq_offset;
+} __packed;
+
+struct cs_mode_one_data {
+ uint8_t packet_quality;
+ uint8_t packet_rssi_dbm;
+ uint8_t packet_ant;
+ uint8_t packet_nadm;
+ int16_t toa_tod_init;
+ int16_t tod_toa_refl;
+ struct pct_iq_sample packet_pct1;
+ struct pct_iq_sample packet_pct2;
+} __packed;
+
+struct cs_mode_two_data {
+ uint8_t ant_perm_index;
+ struct pct_iq_sample tone_pct[4];
+ uint8_t tone_quality_indicator[4];
+} __packed;
+
+struct cs_mode_three_data {
+ struct cs_mode_one_data mode_one_data;
+ struct cs_mode_two_data mode_two_data;
+} __packed;
+
+union cs_mode_data {
+ struct cs_mode_zero_data mode_zero_data;
+ struct cs_mode_one_data mode_one_data;
+ struct cs_mode_two_data mode_two_data;
+ struct cs_mode_three_data mode_three_data;
+};
+
+struct cs_step_data {
+ uint8_t step_mode;
+ uint8_t step_chnl;
+ uint8_t step_data_length;
+ union cs_mode_data step_mode_data;
+} __packed;
+
+struct rap_ev_cs_subevent_result {
+ uint16_t conn_hdl;
+ uint8_t config_id;
+ uint16_t start_acl_conn_evt_counter;
+ uint16_t proc_counter;
+ uint16_t freq_comp;
+ uint8_t ref_pwr_lvl;
+ uint8_t proc_done_status;
+ uint8_t subevt_done_status;
+ uint8_t abort_reason;
+ uint8_t num_ant_paths;
+ uint8_t num_steps_reported;
+ struct cs_step_data step_data[];
+} __packed;
+
+struct rap_ev_cs_subevent_result_cont {
+ uint16_t conn_hdl;
+ uint8_t config_id;
+ uint8_t proc_done_status;
+ uint8_t subevt_done_status;
+ uint8_t abort_reason;
+ uint8_t num_ant_paths;
+ uint8_t num_steps_reported;
+ struct cs_step_data step_data[];
+} __packed;
+
typedef void (*bt_rap_debug_func_t)(const char *str, void *user_data);
typedef void (*bt_rap_ready_func_t)(struct bt_rap *rap, void *user_data);
typedef void (*bt_rap_destroy_func_t)(void *user_data);
@@ -43,3 +188,32 @@ bool bt_rap_ready_unregister(struct bt_rap *rap, unsigned int id);
bool bt_rap_unregister(unsigned int id);
struct bt_rap *bt_rap_new(struct gatt_db *ldb, struct gatt_db *rdb);
+
+/* HCI Raw Channel Approach */
+void bt_rap_hci_cs_config_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data);
+void bt_rap_hci_cs_sec_enable_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data);
+void bt_rap_hci_cs_procedure_enable_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data);
+void bt_rap_hci_cs_subevent_result_callback(uint16_t length,
+ const void *param,
+ void *user_data);
+void bt_rap_hci_cs_subevent_result_cont_callback(uint16_t length,
+ const void *param,
+ void *user_data);
+
+void bt_rap_hci_set_le_bcs_options(uint8_t role, uint8_t cs_sync_ant_sel,
+ int8_t max_tx_power);
+
+bool bt_rap_attach_hci(struct bt_rap *rap, struct bt_hci *hci);
+void bt_rap_detach_hci(struct bt_rap *rap);
+void bt_rap_hci_sm_cleanup(void);
+
+/* Connection handle mapping functions */
+bool bt_rap_set_conn_handle(struct bt_rap *rap, uint16_t handle,
+ const uint8_t *bdaddr, uint8_t bdaddr_type);
+void bt_rap_clear_conn_handle(struct bt_rap *rap, uint16_t handle);
--
^ permalink raw reply related
* [PATCH BlueZ v5 0/3] Add initial Channel Sounding Reflector
From: Naga Bhavani Akella @ 2026-04-14 15:08 UTC (permalink / raw)
To: linux-bluetooth
Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
prathibha.madugonde, Naga Bhavani Akella
This patch series introduces initial support for Bluetooth Channel Sounding
(CS) using the raw HCI interface.
This series lays the groundwork for CS support by adding commonly
required protocol definitions, configuration parsing, and event handling
for the reflector role.
The changes include:
1) Introduction of raw HCI support structures and callbacks for Channel
Sounding procedures and events. This provides the foundational data
definitions and HCI subevent handling needed by higher-level profiles.
2) Addition of Channel Sounding configuration parsing from the BlueZ
configuration file.This patch also updates the systemd
service capability bounding set to include CAP_NET_RAW, which is
required for bluetoothd to receive and process LE Channel Sounding
events when running under a constrained systemd environment.
3) Implementation of HCI LE Channel Sounding event handling in the Ranging
profile for the reflector role. This includes opening a raw HCI channel,
parsing relevant CS LE events, routing them to the RAP profile
Patch overview:
1/3 shared: rap: introduce Channel Sounding HCI raw interface support
2/3 main.conf: add Channel Sounding config parsing support
3/3 profiles: ranging: add HCI LE Channel Sounding event handling (reflector)
Naga Bhavani Akella (3):
shared: rap: Introduce Channel Sounding HCI raw interface support
main.conf: Add Channel Sounding config parsing support
profiles: ranging: Add HCI LE Event Handling in Reflector role
Makefile.plugins | 3 +-
profiles/ranging/rap.c | 83 ++-
profiles/ranging/rap_hci.c | 1288 ++++++++++++++++++++++++++++++++++++
src/bluetooth.service.in | 2 +-
src/btd.h | 7 +
src/main.c | 129 ++++
src/main.conf | 24 +
src/shared/hci.c | 67 +-
src/shared/hci.h | 12 +
src/shared/rap.c | 50 +-
src/shared/rap.h | 174 +++++
11 files changed, 1813 insertions(+), 26 deletions(-)
create mode 100644 profiles/ranging/rap_hci.c
--
^ permalink raw reply
* [PATCH v5] Bluetooth: hci_event: Fix OOB read and infinite loop in hci_le_create_big_complete_evt
From: Luiz Augusto von Dentz @ 2026-04-14 14:46 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
hci_le_create_big_complete_evt() iterates over BT_BOUND connections for
a BIG handle using a while loop, accessing ev->bis_handle[i++] on each
iteration. However, there is no check that i stays within ev->num_bis
before the array access.
When a controller sends a LE_Create_BIG_Complete event with fewer
bis_handle entries than there are BT_BOUND connections for that BIG,
or with num_bis=0, the loop reads beyond the valid bis_handle[] flex
array into adjacent heap memory. Since the out-of-bounds values
typically exceed HCI_CONN_HANDLE_MAX (0x0EFF), hci_conn_set_handle()
rejects them and the connection remains in BT_BOUND state. The same
connection is then found again by hci_conn_hash_lookup_big_state(),
creating an infinite loop with hci_dev_lock held.
Fix this by terminating the BIG if in case not all BIS could be setup
properly.
Fixes: a0bfde167b50 ("Bluetooth: ISO: Add support for connecting multiple BISes")
Cc: stable@vger.kernel.org
Signed-off-by: ZhiTao Ou <hkbinbinbin@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
net/bluetooth/hci_event.c | 29 ++++++++++++++++++++++++++---
1 file changed, 26 insertions(+), 3 deletions(-)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index b2ee6b6a0f56..1b3b9131affa 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -7118,9 +7118,29 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
continue;
}
- if (hci_conn_set_handle(conn,
- __le16_to_cpu(ev->bis_handle[i++])))
+ if (ev->num_bis <= i) {
+ bt_dev_err(hdev,
+ "Not enough BIS handles for BIG 0x%2.2x",
+ ev->handle);
+ ev->status = HCI_ERROR_UNSPECIFIED;
+ hci_connect_cfm(conn, ev->status);
+ hci_conn_del(conn);
continue;
+ }
+
+ if (hci_conn_set_handle(conn,
+ __le16_to_cpu(ev->bis_handle[i++]))) {
+ bt_dev_err(hdev,
+ "Failed to set BIS handle for BIG 0x%2.2x",
+ ev->handle);
+ /* Force error so BIG gets terminated as not all BIS
+ * could be connected.
+ */
+ ev->status = HCI_ERROR_UNSPECIFIED;
+ hci_connect_cfm(conn, ev->status);
+ hci_conn_del(conn);
+ continue;
+ }
conn->state = BT_CONNECTED;
set_bit(HCI_CONN_BIG_CREATED, &conn->flags);
@@ -7129,7 +7149,10 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
hci_iso_setup_path(conn);
}
- if (!ev->status && !i)
+ /* If there is an unexpected error or if no BISes have been connected
+ * for the BIG, terminate it.
+ */
+ if (ev->status == HCI_ERROR_UNSPECIFIED || (!ev->status && !i))
/* If no BISes have been connected for the BIG,
* terminate. This is in case all bound connections
* have been closed before the BIG creation
--
2.53.0
^ permalink raw reply related
* Re: [PATCH v3] Bluetooth: l2cap: defer conn param update to avoid conn->lock/hdev->lock inversion
From: Luiz Augusto von Dentz @ 2026-04-14 14:46 UTC (permalink / raw)
To: Mikhail Gavrilov; +Cc: marcel, pmenzel, linux-bluetooth, linux-kernel
In-Reply-To: <20260413230813.21393-1-mikhail.v.gavrilov@gmail.com>
Hi Mikhail,
On Mon, Apr 13, 2026 at 7:08 PM Mikhail Gavrilov
<mikhail.v.gavrilov@gmail.com> wrote:
>
> When a BLE peripheral sends an L2CAP Connection Parameter Update Request
> the processing path is:
>
> process_pending_rx() [takes conn->lock]
> l2cap_le_sig_channel()
> l2cap_conn_param_update_req()
> hci_le_conn_update() [takes hdev->lock]
>
> Meanwhile other code paths take the locks in the opposite order:
>
> l2cap_chan_connect() [takes hdev->lock]
> ...
> mutex_lock(&conn->lock)
>
> l2cap_conn_ready() [hdev->lock via hci_cb_list_lock]
> ...
> mutex_lock(&conn->lock)
>
> This is a classic AB/BA deadlock which lockdep reports as a circular
> locking dependency when connecting a BLE MIDI keyboard (Carry-On FC-49).
>
> Fix this by making hci_le_conn_update() defer the HCI command through
> hci_cmd_sync_queue() so it no longer needs to take hdev->lock in the
> caller context.
>
> The connection parameter storage (hci_conn_params update) and userspace
> notification (mgmt_new_conn_param) are moved into
> hci_le_conn_update_complete_evt() where they are handled when the
> controller confirms the update, using hci_sent_cmd_data() to retrieve
> the originally requested min/max interval values.
>
> Fixes: f044eb0524a0 ("Bluetooth: Store latency and supervision timeout in connection params")
> Signed-off-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
> Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
> ---
>
> Changes in v3 (Luiz Augusto von Dentz):
> - Move hci_cmd_sync_queue into hci_le_conn_update itself instead of open-coding
> the deferral in l2cap_core.c
> - Move conn_params update and mgmt_new_conn_param into
> hci_le_conn_update_complete_evt, using hci_sent_cmd_data to retrieve
> the originally requested parameters
>
> Changes in v2 (Paul Menzel, Sashiko/Gemini AI review):
> - Allocate before sending ACCEPTED response to avoid state mismatch on OOM
> - Verify connection handle and address in sync callback against reuse race
> - Expand commit message with implementation details
>
> include/net/bluetooth/hci_core.h | 2 +-
> net/bluetooth/hci_conn.c | 66 ++++++++++++++++++++++----------
> net/bluetooth/hci_event.c | 33 ++++++++++++++++
> net/bluetooth/l2cap_core.c | 12 +-----
> 4 files changed, 81 insertions(+), 32 deletions(-)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index a7bffb908c1e..aa600fbf9a53 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -2495,7 +2495,7 @@ void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle,
> bdaddr_t *bdaddr, u8 addr_type);
>
> int hci_abort_conn(struct hci_conn *conn, u8 reason);
> -u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
> +void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
> u16 to_multiplier);
> void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand,
> __u8 ltk[16], __u8 key_size);
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index 11d3ad8d2551..207221560a02 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -480,40 +480,64 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
> return hci_setup_sync_conn(conn, handle);
> }
>
> -u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
> - u16 to_multiplier)
> +struct le_conn_update_data {
> + struct hci_conn *conn;
> + u16 min;
> + u16 max;
> + u16 latency;
> + u16 to_multiplier;
> +};
> +
> +static int le_conn_update_sync(struct hci_dev *hdev, void *data)
> {
> - struct hci_dev *hdev = conn->hdev;
> - struct hci_conn_params *params;
> + struct le_conn_update_data *d = data;
> + struct hci_conn *conn;
> struct hci_cp_le_conn_update cp;
>
> hci_dev_lock(hdev);
> -
> - params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
> - if (params) {
> - params->conn_min_interval = min;
> - params->conn_max_interval = max;
> - params->conn_latency = latency;
> - params->supervision_timeout = to_multiplier;
> - }
> -
> + /* Verify connection is still alive. */
> + conn = hci_conn_valid(hdev, d->conn) ? d->conn : NULL;
> hci_dev_unlock(hdev);
> + if (!conn)
> + return -ECANCELED;
>
> memset(&cp, 0, sizeof(cp));
> cp.handle = cpu_to_le16(conn->handle);
> - cp.conn_interval_min = cpu_to_le16(min);
> - cp.conn_interval_max = cpu_to_le16(max);
> - cp.conn_latency = cpu_to_le16(latency);
> - cp.supervision_timeout = cpu_to_le16(to_multiplier);
> + cp.conn_interval_min = cpu_to_le16(d->min);
> + cp.conn_interval_max = cpu_to_le16(d->max);
> + cp.conn_latency = cpu_to_le16(d->latency);
> + cp.supervision_timeout = cpu_to_le16(d->to_multiplier);
> cp.min_ce_len = cpu_to_le16(0x0000);
> cp.max_ce_len = cpu_to_le16(0x0000);
>
> - hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp);
> + return __hci_cmd_sync_status(hdev, HCI_OP_LE_CONN_UPDATE,
> + sizeof(cp), &cp, HCI_CMD_TIMEOUT);
> +}
> +
> +static void le_conn_update_complete(struct hci_dev *hdev, void *data,
> + int err)
> +{
> + kfree(data);
> +}
>
> - if (params)
> - return 0x01;
> +void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
> + u16 to_multiplier)
> +{
> + struct le_conn_update_data *d;
>
> - return 0x00;
> + d = kmalloc(sizeof(*d), GFP_KERNEL);
> + if (!d)
> + return;
> +
> + d->conn = conn;
> + d->min = min;
> + d->max = max;
> + d->latency = latency;
> + d->to_multiplier = to_multiplier;
> +
> + if (hci_cmd_sync_queue(conn->hdev, le_conn_update_sync, d,
> + le_conn_update_complete) < 0)
> + kfree(d);
> }
>
> void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand,
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index 3ebc5e6d45d9..9df8fc762a84 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -6065,6 +6065,8 @@ static void hci_le_conn_update_complete_evt(struct hci_dev *hdev, void *data,
> struct sk_buff *skb)
> {
> struct hci_ev_le_conn_update_complete *ev = data;
> + struct hci_cp_le_conn_update *sent;
> + struct hci_conn_params *params;
> struct hci_conn *conn;
>
> bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
> @@ -6079,6 +6081,37 @@ static void hci_le_conn_update_complete_evt(struct hci_dev *hdev, void *data,
> conn->le_conn_interval = le16_to_cpu(ev->interval);
> conn->le_conn_latency = le16_to_cpu(ev->latency);
> conn->le_supv_timeout = le16_to_cpu(ev->supervision_timeout);
> +
> + /* Update stored connection parameters and notify userspace
> + * using the parameters from the original HCI command.
> + */
> + sent = hci_sent_cmd_data(hdev, HCI_OP_LE_CONN_UPDATE);
> + if (sent) {
> + u8 store_hint;
> +
> + params = hci_conn_params_lookup(hdev, &conn->dst,
> + conn->dst_type);
> + if (params) {
> + params->conn_min_interval =
> + le16_to_cpu(sent->conn_interval_min);
> + params->conn_max_interval =
> + le16_to_cpu(sent->conn_interval_max);
> + params->conn_latency =
> + le16_to_cpu(sent->conn_latency);
> + params->supervision_timeout =
> + le16_to_cpu(sent->supervision_timeout);
> + store_hint = 0x01;
> + } else {
> + store_hint = 0x00;
> + }
> +
> + mgmt_new_conn_param(hdev, &conn->dst, conn->dst_type,
> + store_hint,
> + le16_to_cpu(sent->conn_interval_min),
> + le16_to_cpu(sent->conn_interval_max),
> + le16_to_cpu(sent->conn_latency),
> + le16_to_cpu(sent->supervision_timeout));
> + }
> }
>
> hci_dev_unlock(hdev);
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index 95c65fece39b..aac2db1d6fbb 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -4706,16 +4706,8 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
> l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
> sizeof(rsp), &rsp);
>
> - if (!err) {
> - u8 store_hint;
> -
> - store_hint = hci_le_conn_update(hcon, min, max, latency,
> - to_multiplier);
> - mgmt_new_conn_param(hcon->hdev, &hcon->dst, hcon->dst_type,
> - store_hint, min, max, latency,
> - to_multiplier);
> -
> - }
> + if (!err)
> + hci_le_conn_update(hcon, min, max, latency, to_multiplier);
>
> return 0;
> }
> --
> 2.53.0
>
https://sashiko.dev/#/patchset/20260413230813.21393-1-mikhail.v.gavrilov%40gmail.com
Most comments seem valid. Regarding the last 2 we might need to wait
for HCI_EV_LE_CONN_UPDATE_COMPLETE by passing it to
__hci_cmd_sync_status_sk.
For the first comment I guess we will need to use hci_conn_get to
prevent the hci_conn from being freed. It can still be removed so the
usage of hci_conn_valid remains valid, but we will need to call
hci_conn_put even if hci_conn is already removed.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH v2] Bluetooth: Add Broadcom channel priority commands
From: Luiz Augusto von Dentz @ 2026-04-14 14:00 UTC (permalink / raw)
To: fnkl.kernel
Cc: Sven Peter, Janne Grunau, Neal Gompa, Marcel Holtmann,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, linux-kernel, asahi, linux-arm-kernel,
linux-bluetooth, netdev
In-Reply-To: <20260407-brcm-prio-v2-1-3f745edf49af@gmail.com>
Hi Sasha,
On Tue, Apr 7, 2026 at 1:46 PM Sasha Finkelstein via B4 Relay
<devnull+fnkl.kernel.gmail.com@kernel.org> wrote:
>
> From: Sasha Finkelstein <fnkl.kernel@gmail.com>
>
> Certain Broadcom bluetooth chips (bcm4377/bcm4378/bcm438) need ACL
> streams carrying audio to be set as "high priority" using a vendor
> specific command to prevent 10-ish second-long dropouts whenever
> something does a device scan. This patch sends the command when the
> socket priority is set to TC_PRIO_INTERACTIVE, as BlueZ does for audio.
>
> Signed-off-by: Sasha Finkelstein <fnkl.kernel@gmail.com>
> ---
> Changes in v2:
> - new ioctl got nack-ed, so let's use sk_priority as the trigger
> - Link to v1: https://lore.kernel.org/r/20260407-brcm-prio-v1-1-f38b17376640@gmail.com
> ---
> MAINTAINERS | 2 ++
> drivers/bluetooth/hci_bcm4377.c | 2 ++
> include/net/bluetooth/bluetooth.h | 4 ++++
> include/net/bluetooth/hci_core.h | 11 +++++++++++
> net/bluetooth/Kconfig | 7 +++++++
> net/bluetooth/Makefile | 1 +
> net/bluetooth/brcm.c | 29 +++++++++++++++++++++++++++++
> net/bluetooth/brcm.h | 17 +++++++++++++++++
> net/bluetooth/hci_conn.c | 28 ++++++++++++++++++++++++++++
> net/bluetooth/l2cap_sock.c | 13 +++++++++++++
> 10 files changed, 114 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index c3fe46d7c4bc..81be021367ec 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2562,6 +2562,8 @@ F: include/dt-bindings/pinctrl/apple.h
> F: include/linux/mfd/macsmc.h
> F: include/linux/soc/apple/*
> F: include/uapi/drm/asahi_drm.h
> +F: net/bluetooth/brcm.c
> +F: net/bluetooth/brcm.h
>
> ARM/ARTPEC MACHINE SUPPORT
> M: Jesper Nilsson <jesper.nilsson@axis.com>
> diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c
> index 925d0a635945..5f79920c0306 100644
> --- a/drivers/bluetooth/hci_bcm4377.c
> +++ b/drivers/bluetooth/hci_bcm4377.c
> @@ -2397,6 +2397,8 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> if (bcm4377->hw->broken_le_ext_adv_report_phy)
> hci_set_quirk(hdev, HCI_QUIRK_FIXUP_LE_EXT_ADV_REPORT_PHY);
>
> + hci_set_brcm_capable(hdev);
> +
> pci_set_drvdata(pdev, bcm4377);
> hci_set_drvdata(hdev, bcm4377);
> SET_HCIDEV_DEV(hdev, &pdev->dev);
> diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
> index 69eed69f7f26..07a250673950 100644
> --- a/include/net/bluetooth/bluetooth.h
> +++ b/include/net/bluetooth/bluetooth.h
> @@ -457,6 +457,7 @@ struct l2cap_ctrl {
> };
>
> struct hci_dev;
> +struct hci_conn;
>
> typedef void (*hci_req_complete_t)(struct hci_dev *hdev, u8 status, u16 opcode);
> typedef void (*hci_req_complete_skb_t)(struct hci_dev *hdev, u8 status,
> @@ -469,6 +470,9 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status,
> int hci_ethtool_ts_info(unsigned int index, int sk_proto,
> struct kernel_ethtool_ts_info *ts_info);
>
> +int hci_conn_setsockopt(struct hci_conn *conn, struct sock *sk, int level,
> + int optname, sockptr_t optval, unsigned int optlen);
> +
> #define HCI_REQ_START BIT(0)
> #define HCI_REQ_SKB BIT(1)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index a7bffb908c1e..947e7c2b08dd 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -642,6 +642,10 @@ struct hci_dev {
> bool aosp_quality_report;
> #endif
>
> +#if IS_ENABLED(CONFIG_BT_BRCMEXT)
> + bool brcm_capable;
> +#endif
> +
> int (*open)(struct hci_dev *hdev);
> int (*close)(struct hci_dev *hdev);
> int (*flush)(struct hci_dev *hdev);
> @@ -1791,6 +1795,13 @@ static inline void hci_set_aosp_capable(struct hci_dev *hdev)
> #endif
> }
>
> +static inline void hci_set_brcm_capable(struct hci_dev *hdev)
> +{
> +#if IS_ENABLED(CONFIG_BT_BRCMEXT)
> + hdev->brcm_capable = true;
> +#endif
> +}
> +
> static inline void hci_devcd_setup(struct hci_dev *hdev)
> {
> #ifdef CONFIG_DEV_COREDUMP
> diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig
> index 6b2b65a66700..0f2a5fbcafc5 100644
> --- a/net/bluetooth/Kconfig
> +++ b/net/bluetooth/Kconfig
> @@ -110,6 +110,13 @@ config BT_AOSPEXT
> This options enables support for the Android Open Source
> Project defined HCI vendor extensions.
>
> +config BT_BRCMEXT
> + bool "Enable Broadcom extensions"
> + depends on BT
> + help
> + This option enables support for the Broadcom defined HCI
> + vendor extensions.
> +
> config BT_DEBUGFS
> bool "Export Bluetooth internals in debugfs"
> depends on BT && DEBUG_FS
> diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
> index a7eede7616d8..b4c9013a46ce 100644
> --- a/net/bluetooth/Makefile
> +++ b/net/bluetooth/Makefile
> @@ -24,5 +24,6 @@ bluetooth-$(CONFIG_BT_LE) += iso.o
> bluetooth-$(CONFIG_BT_LEDS) += leds.o
> bluetooth-$(CONFIG_BT_MSFTEXT) += msft.o
> bluetooth-$(CONFIG_BT_AOSPEXT) += aosp.o
> +bluetooth-$(CONFIG_BT_BRCMEXT) += brcm.o
> bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o
> bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o
> diff --git a/net/bluetooth/brcm.c b/net/bluetooth/brcm.c
> new file mode 100644
> index 000000000000..9aa0a265ab3d
> --- /dev/null
> +++ b/net/bluetooth/brcm.c
> @@ -0,0 +1,29 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2026 The Asahi Linux Contributors
> + */
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +
> +#include "brcm.h"
> +
> +int brcm_set_high_priority(struct hci_dev *hdev, u16 handle, bool enable)
> +{
> + struct sk_buff *skb;
> + u8 cmd[3];
> +
> + if (!hdev->brcm_capable)
> + return 0;
> +
> + cmd[0] = handle;
> + cmd[1] = handle >> 8;
Adding a packed struct and then using something like cpu_to_le16 is
probably preferable over above.
> + cmd[2] = !!enable;
> +
> + skb = hci_cmd_sync(hdev, 0xfc57, sizeof(cmd), cmd, HCI_CMD_TIMEOUT);
> + if (IS_ERR(skb))
> + return PTR_ERR(skb);
> +
> + kfree_skb(skb);
> + return 0;
> +}
> diff --git a/net/bluetooth/brcm.h b/net/bluetooth/brcm.h
> new file mode 100644
> index 000000000000..fdaee63bd1d2
> --- /dev/null
> +++ b/net/bluetooth/brcm.h
> @@ -0,0 +1,17 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2026 The Asahi Linux Contributors
> + */
> +
> +#if IS_ENABLED(CONFIG_BT_BRCMEXT)
> +
> +int brcm_set_high_priority(struct hci_dev *hdev, u16 handle, bool enable);
> +
> +#else
> +
> +static inline int brcm_set_high_priority(struct hci_dev *hdev, u16 handle, bool enable)
> +{
> + return 0;
> +}
> +
> +#endif
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index 11d3ad8d2551..096163840f62 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -35,6 +35,7 @@
> #include <net/bluetooth/iso.h>
> #include <net/bluetooth/mgmt.h>
>
> +#include "brcm.h"
> #include "smp.h"
> #include "eir.h"
>
> @@ -3070,6 +3071,33 @@ int hci_conn_set_phy(struct hci_conn *conn, u32 phys)
> }
> }
>
> +int hci_conn_setsockopt(struct hci_conn *conn, struct sock *sk, int level,
> + int optname, sockptr_t optval, unsigned int optlen)
> +{
> + int val;
> + bool old_high, new_high, changed;
> +
> + if (level != SOL_SOCKET)
> + return 0;
> +
> + if (optname != SO_PRIORITY)
> + return 0;
> +
> + if (optlen < sizeof(int))
> + return -EINVAL;
> +
> + if (copy_from_sockptr(&val, optval, sizeof(val)))
> + return -EFAULT;
> +
> + old_high = sk->sk_priority >= TC_PRIO_INTERACTIVE;
> + new_high = val >= TC_PRIO_INTERACTIVE;
> + changed = old_high != new_high;
> + if (!changed)
> + return 0;
> +
> + return brcm_set_high_priority(conn->hdev, conn->handle, new_high);
The skb carries the priority (skb->priority), not sure why you need to
capture the sk_priority instead, doing so ignores the load balance
that hci_core performs to avoid starving connections.
> +}
> +
> static int abort_conn_sync(struct hci_dev *hdev, void *data)
> {
> struct hci_conn *conn = data;
> diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
> index 71e8c1b45bce..d5eef87accc4 100644
> --- a/net/bluetooth/l2cap_sock.c
> +++ b/net/bluetooth/l2cap_sock.c
> @@ -891,6 +891,16 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
>
> BT_DBG("sk %p", sk);
>
> + if (level == SOL_SOCKET) {
> + conn = chan->conn;
> + if (conn)
> + err = hci_conn_setsockopt(conn->hcon, sock->sk, level,
> + optname, optval, optlen);
> + if (err)
> + return err;
> + return sock_setsockopt(sock, level, optname, optval, optlen);
> + }
> +
> if (level == SOL_L2CAP)
> return l2cap_sock_setsockopt_old(sock, optname, optval, optlen);
>
> @@ -1931,6 +1941,9 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
>
> INIT_LIST_HEAD(&l2cap_pi(sk)->rx_busy);
>
> + if (sock)
> + set_bit(SOCK_CUSTOM_SOCKOPT, &sock->flags);
This is more complicated than it needs to be. I'd just add a new
callback, `hdev->set_priority(handle, skb->priority)`, so the driver
is called whenever it needs to elevate a connection's priority, that
said there could be cases where a connection needs its priority set
momentarily to transmit A2DP, followed by OBEX packets that are best
effort. Therefore, `hci_conn` will probably need to track the priority
so it can detect when it needs changing on a per skb basis.
> chan = l2cap_chan_create();
> if (!chan) {
> sk_free(sk);
>
> ---
> base-commit: bfe62a454542cfad3379f6ef5680b125f41e20f4
> change-id: 20260407-brcm-prio-b630e6cc3834
>
> Best regards,
> --
> Sasha Finkelstein <fnkl.kernel@gmail.com>
>
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* RE: [Bluez,1/2] monitor: define manufacturer company IDs
From: bluez.test.bot @ 2026-04-14 12:24 UTC (permalink / raw)
To: linux-bluetooth, apusaka
In-Reply-To: <20260414111307.3725821-1-apusaka@google.com>
[-- Attachment #1: Type: text/plain, Size: 2687 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=1081093
---Test result---
Test Summary:
CheckPatch FAIL 1.22 seconds
GitLint PASS 0.54 seconds
BuildEll PASS 17.61 seconds
BluezMake PASS 603.42 seconds
MakeCheck PASS 18.55 seconds
MakeDistcheck PASS 220.26 seconds
CheckValgrind PASS 273.63 seconds
CheckSmatch WARNING 305.22 seconds
bluezmakeextell PASS 166.13 seconds
IncrementalBuild FAIL 0.25 seconds
ScanBuild PASS 902.35 seconds
Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[Bluez,2/2] monitor: Set msft_opcode on read_local_version_rsp
ERROR:OPEN_BRACE: open brace '{' following function definitions go on the next line
#108: FILE: monitor/packet.c:4362:
+static int get_msft_opcode(uint16_t manufacturer) {
/github/workspace/src/patch/14524190.patch total: 1 errors, 0 warnings, 86 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
/github/workspace/src/patch/14524190.patch has style problems, please review.
NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
##############################
Test: CheckSmatch - WARNING
Desc: Run smatch tool with source
Output:
monitor/packet.c:2000:26: warning: Variable length array is used.monitor/packet.c: note: in included file:monitor/bt.h:3866:52: warning: array of flexible structuresmonitor/bt.h:3854:40: warning: array of flexible structuresmonitor/packet.c:2000:26: warning: Variable length array is used.monitor/packet.c: note: in included file:monitor/bt.h:3866:52: warning: array of flexible structuresmonitor/bt.h:3854:40: warning: array of flexible structures
##############################
Test: IncrementalBuild - FAIL
Desc: Incremental build with the patches in the series
Output:
fatal: previous rebase directory .git/rebase-apply still exists but mbox given.
https://github.com/bluez/bluez/pull/2031
---
Regards,
Linux Bluetooth
^ permalink raw reply
* Re: [PATCH v7 0/8] Add support for handling PCIe M.2 Key E connectors in devicetree
From: Andy Shevchenko @ 2026-04-14 12:03 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Manivannan Sadhasivam, Manivannan Sadhasivam, Rob Herring,
Greg Kroah-Hartman, Jiri Slaby, Nathan Chancellor, Nicolas Schier,
Hans de Goede, Ilpo Järvinen, Mark Pearson, Derek J. Clark,
Krzysztof Kozlowski, Conor Dooley, Marcel Holtmann,
Luiz Augusto von Dentz, Bartosz Golaszewski, Bartosz Golaszewski,
linux-serial, linux-kernel, linux-kbuild, platform-driver-x86,
linux-pci, devicetree, linux-arm-msm, linux-bluetooth, linux-pm,
Stephan Gerhold, Dmitry Baryshkov, linux-acpi, Hans de Goede,
Bartosz Golaszewski
In-Reply-To: <CAGXv+5EGe59nJctLweEdZjb3MNmMvjuCHngGSfptzN985OiLdg@mail.gmail.com>
On Tue, Apr 14, 2026 at 06:29:02PM +0800, Chen-Yu Tsai wrote:
> On Tue, Apr 14, 2026 at 4:28 PM Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> > On Tue, Apr 14, 2026 at 01:03:19PM +0800, Chen-Yu Tsai wrote:
> > > On Tue, Apr 14, 2026 at 12:08 AM Manivannan Sadhasivam <mani@kernel.org> wrote:
> > > > On Mon, Apr 13, 2026 at 07:33:12PM +0530, Manivannan Sadhasivam wrote:
> > > > > On Mon, Apr 13, 2026 at 03:54:59PM +0800, Chen-Yu Tsai wrote:
> > > > > > On Thu, Mar 26, 2026 at 01:36:28PM +0530, Manivannan Sadhasivam wrote:
...
> > > > > > - Given that this connector actually represents two devices, how do I
> > > > > > say I want the BT part to be a wakeup source, but not the WiFi part?
> > > > > > Does wakeup-source even work at this point?
> > > > >
> > > > > You can't use the DT property since the devices are not described in DT
> > > > > statically. But you can still use the per-device 'wakeup' sysfs knob to enable
> > > > > wakeup.
> > >
> > > I see. I think not being able to specify generic properties for the devices
> > > on the connector is going to be a bit problematic.
> >
> > This is nature of the open-connectors, especially on the busses that are
> > hotpluggable, like PCIe. We never know what is connected there _ahead_.
>
> I believe what you mean by "hotpluggable" is "user replaceable".
From the OS perspective it's the same. From platform perspective
there is a difference, granted.
> > In other words you can't describe in DT something that may not exist.
>
> But this is actually doable with the PCIe slot representation. The
> properties are put in the device node for the slot. If no card is
> actually inserted in the slot, then no device is created, and the
> device node is left as not associated with anything.
But you need to list all devices in the world if you want to support this
somehow. Yes, probably many of them (or majority) will be enumerated as is,
but some may need an assistance via (dynamic) properties or similar mechanisms.
> It's just that for this new M.2 E-key connector, there aren't separate
> nodes for each interface. And the system doesn't associate the device
> node with the device, because it's no longer a child node of the
> controller or hierarchy, but connected over the OF graph.
>
> Moving over to the E-key connector representation seems like one step
> forward and one step backward in descriptive ability. We gain proper
> power sequencing, but lose generic properties.
The "key" is property of the connector. Hence if you have an idea what can be
common for ALL "key":s, that's probably can be abstracted. Note, I'm not
familiar with the connector framework in the Linux kernel, perhaps it's already
that kind of abstraction.
> The latter part is solvable, but we likely need child nodes under the
> connector for the different interfaces. Properties that make sense for
> one type might not make sense for another.
>
> P.S. We could also just add child device nodes under the controller to
> put the generic properties, but that's splitting the description into
> multiple parts. Let's not go there if at all possible.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [bluez/bluez] 5de8de: monitor: define manufacturer company IDs
From: apusaka @ 2026-04-14 11:42 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1081093
Home: https://github.com/bluez/bluez
Commit: 5de8def71a42e3118d8f9b5e91a6765996975f88
https://github.com/bluez/bluez/commit/5de8def71a42e3118d8f9b5e91a6765996975f88
Author: Archie Pusaka <apusaka@chromium.org>
Date: 2026-04-14 (Tue, 14 Apr 2026)
Changed paths:
M monitor/packet.c
Log Message:
-----------
monitor: define manufacturer company IDs
Define company IDs to make it more readable.
Also remove an unnecessary if that could cause uninitialized variable
warning.
Commit: 1e4863460198fba5e75a8aec2232013dbe58ca77
https://github.com/bluez/bluez/commit/1e4863460198fba5e75a8aec2232013dbe58ca77
Author: Archie Pusaka <apusaka@chromium.org>
Date: 2026-04-14 (Tue, 14 Apr 2026)
Changed paths:
M monitor/packet.c
Log Message:
-----------
monitor: Set msft_opcode on read_local_version_rsp
Aside from INDEX_INFO, we can also receive manufacturer company ID
when receiving read_local_version_rsp, so we should also try setting
the msft_opcode there.
Compare: https://github.com/bluez/bluez/compare/5de8def71a42%5E...1e4863460198
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* [PATCH Bluez 2/2] monitor: Set msft_opcode on read_local_version_rsp
From: Archie Pusaka @ 2026-04-14 11:11 UTC (permalink / raw)
To: linux-bluetooth, Luiz Augusto von Dentz; +Cc: CrosBT Upstreaming, Archie Pusaka
In-Reply-To: <20260414111307.3725821-1-apusaka@google.com>
From: Archie Pusaka <apusaka@chromium.org>
Aside from INDEX_INFO, we can also receive manufacturer company ID
when receiving read_local_version_rsp, so we should also try setting
the msft_opcode there.
---
monitor/packet.c | 68 +++++++++++++++++-------------------------------
1 file changed, 24 insertions(+), 44 deletions(-)
diff --git a/monitor/packet.c b/monitor/packet.c
index 30cab1a2f..ff0b1cac2 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -4359,6 +4359,24 @@ static int addr2str(const uint8_t *addr, char *str)
addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
}
+static int get_msft_opcode(uint16_t manufacturer) {
+ switch (manufacturer) {
+ case COMPANY_ID_INTEL:
+ return 0xFC1E;
+ case COMPANY_ID_QUALCOMM:
+ return 0xFD70;
+ case COMPANY_ID_MEDIATEK:
+ return 0xFD30;
+ case COMPANY_ID_REALTEK:
+ return 0xFCF0;
+ case COMPANY_ID_LINUX:
+ return 0xFC1E;
+ default:
+ return BT_HCI_CMD_NOP;
+ }
+
+}
+
void packet_monitor(struct timeval *tv, struct ucred *cred,
uint16_t index, uint16_t opcode,
const void *data, uint16_t size)
@@ -4451,50 +4469,8 @@ void packet_monitor(struct timeval *tv, struct ucred *cred,
if (index < MAX_INDEX) {
memcpy(index_list[index].bdaddr, ii->bdaddr, 6);
index_list[index].manufacturer = manufacturer;
-
- switch (manufacturer) {
- case COMPANY_ID_INTEL:
- /*
- * Intel controllers that support the
- * Microsoft vendor extension are using
- * 0xFC1E for VsMsftOpCode.
- */
- index_list[index].msft_opcode = 0xFC1E;
- break;
- case COMPANY_ID_QUALCOMM:
- /*
- * Qualcomm controllers that support the
- * Microsoft vendor extensions are using
- * 0xFD70 for VsMsftOpCode.
- */
- index_list[index].msft_opcode = 0xFD70;
- break;
- case COMPANY_ID_MEDIATEK:
- /*
- * Mediatek controllers that support the
- * Microsoft vendor extensions are using
- * 0xFD30 for VsMsftOpCode.
- */
- index_list[index].msft_opcode = 0xFD30;
- break;
- case COMPANY_ID_REALTEK:
- /*
- * Realtek controllers that support the
- * Microsoft vendor extensions are using
- * 0xFCF0 for VsMsftOpCode.
- */
- index_list[index].msft_opcode = 0xFCF0;
- break;
- case COMPANY_ID_LINUX:
- /*
- * Emulator controllers use Linux Foundation as
- * manufacturer and support the
- * Microsoft vendor extensions using
- * 0xFC1E for VsMsftOpCode.
- */
- index_list[index].msft_opcode = 0xFC1E;
- break;
- }
+ index_list[index].msft_opcode =
+ get_msft_opcode(manufacturer);
}
addr2str(ii->bdaddr, str);
@@ -6530,6 +6506,10 @@ static void read_local_version_rsp(uint16_t index, const void *data,
}
index_list[index_current].manufacturer = manufacturer;
+ if (index_list[index_current].msft_opcode == BT_HCI_CMD_NOP) {
+ index_list[index_current].msft_opcode =
+ get_msft_opcode(manufacturer);
+ }
}
print_manufacturer(rsp->manufacturer);
--
2.54.0.rc1.513.gad8abe7a5a-goog
^ permalink raw reply related
* [PATCH Bluez 1/2] monitor: define manufacturer company IDs
From: Archie Pusaka @ 2026-04-14 11:11 UTC (permalink / raw)
To: linux-bluetooth, Luiz Augusto von Dentz; +Cc: CrosBT Upstreaming, Archie Pusaka
From: Archie Pusaka <apusaka@chromium.org>
Define company IDs to make it more readable.
Also remove an unnecessary if that could cause uninitialized variable
warning.
---
monitor/packet.c | 51 +++++++++++++++++++++++++++---------------------
1 file changed, 29 insertions(+), 22 deletions(-)
diff --git a/monitor/packet.c b/monitor/packet.c
index ff28dfbd4..30cab1a2f 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -100,14 +100,21 @@
#define COLOR_PHY_PACKET COLOR_BLUE
-#define UNKNOWN_MANUFACTURER 0xffff
+#define COMPANY_ID_INTEL 0x0002
+#define COMPANY_ID_BROADCOM 0x000F
+#define COMPANY_ID_QUALCOMM 0x001D
+#define COMPANY_ID_MEDIATEK 0x0046
+#define COMPANY_ID_APPLE 0x004C
+#define COMPANY_ID_REALTEK 0x005D
+#define COMPANY_ID_LINUX 0x05F1
+#define COMPANY_ID_UNKNOWN 0xFFFF
static time_t time_offset = ((time_t) -1);
static int priority_level = BTSNOOP_PRIORITY_DEBUG;
static unsigned long filter_mask = 0;
static bool index_filter = false;
static uint16_t index_current = 0;
-static uint16_t fallback_manufacturer = UNKNOWN_MANUFACTURER;
+static uint16_t fallback_manufacturer = COMPANY_ID_UNKNOWN;
#define CTRL_RAW 0x0000
#define CTRL_USER 0x0001
@@ -3487,7 +3494,7 @@ static void print_manufacturer_data(const void *data, uint8_t data_len)
packet_print_company("Company", company);
switch (company) {
- case 76:
+ case COMPANY_ID_APPLE:
case 19456:
print_manufacturer_apple(data + 2, data_len - 2);
break;
@@ -4446,7 +4453,7 @@ void packet_monitor(struct timeval *tv, struct ucred *cred,
index_list[index].manufacturer = manufacturer;
switch (manufacturer) {
- case 2:
+ case COMPANY_ID_INTEL:
/*
* Intel controllers that support the
* Microsoft vendor extension are using
@@ -4454,7 +4461,7 @@ void packet_monitor(struct timeval *tv, struct ucred *cred,
*/
index_list[index].msft_opcode = 0xFC1E;
break;
- case 29:
+ case COMPANY_ID_QUALCOMM:
/*
* Qualcomm controllers that support the
* Microsoft vendor extensions are using
@@ -4462,7 +4469,7 @@ void packet_monitor(struct timeval *tv, struct ucred *cred,
*/
index_list[index].msft_opcode = 0xFD70;
break;
- case 70:
+ case COMPANY_ID_MEDIATEK:
/*
* Mediatek controllers that support the
* Microsoft vendor extensions are using
@@ -4470,7 +4477,7 @@ void packet_monitor(struct timeval *tv, struct ucred *cred,
*/
index_list[index].msft_opcode = 0xFD30;
break;
- case 93:
+ case COMPANY_ID_REALTEK:
/*
* Realtek controllers that support the
* Microsoft vendor extensions are using
@@ -4478,7 +4485,7 @@ void packet_monitor(struct timeval *tv, struct ucred *cred,
*/
index_list[index].msft_opcode = 0xFCF0;
break;
- case 1521:
+ case COMPANY_ID_LINUX:
/*
* Emulator controllers use Linux Foundation as
* manufacturer and support the
@@ -6528,7 +6535,7 @@ static void read_local_version_rsp(uint16_t index, const void *data,
print_manufacturer(rsp->manufacturer);
switch (manufacturer) {
- case 15:
+ case COMPANY_ID_BROADCOM:
print_manufacturer_broadcom(rsp->lmp_subver, rsp->hci_rev);
break;
}
@@ -10900,11 +10907,11 @@ static const char *current_vendor_str(uint16_t ocf)
return "Microsoft";
switch (manufacturer) {
- case 2:
+ case COMPANY_ID_INTEL:
return "Intel";
- case 15:
+ case COMPANY_ID_BROADCOM:
return "Broadcom";
- case 93:
+ case COMPANY_ID_REALTEK:
return "Realtek";
}
@@ -10928,9 +10935,9 @@ static const struct vendor_ocf *current_vendor_ocf(uint16_t ocf)
return msft_vendor_ocf();
switch (manufacturer) {
- case 2:
+ case COMPANY_ID_INTEL:
return intel_vendor_ocf(ocf);
- case 15:
+ case COMPANY_ID_BROADCOM:
return broadcom_vendor_ocf(ocf);
}
@@ -10952,9 +10959,9 @@ static const struct vendor_evt *current_vendor_evt(const void *data,
manufacturer = fallback_manufacturer;
switch (manufacturer) {
- case 2:
+ case COMPANY_ID_INTEL:
return intel_vendor_evt(data, consumed_size);
- case 15:
+ case COMPANY_ID_BROADCOM:
return broadcom_vendor_evt(evt);
}
@@ -10971,11 +10978,11 @@ static const char *current_vendor_evt_str(void)
manufacturer = fallback_manufacturer;
switch (manufacturer) {
- case 2:
+ case COMPANY_ID_INTEL:
return "Intel";
- case 15:
+ case COMPANY_ID_BROADCOM:
return "Broadcom";
- case 93:
+ case COMPANY_ID_REALTEK:
return "Realtek";
}
@@ -11116,7 +11123,7 @@ static void remote_version_complete_evt(struct timeval *tv, uint16_t index,
print_manufacturer(evt->manufacturer);
switch (le16_to_cpu(evt->manufacturer)) {
- case 15:
+ case COMPANY_ID_BROADCOM:
print_manufacturer_broadcom(evt->lmp_subver, 0xffff);
break;
}
@@ -13808,7 +13815,7 @@ void packet_vendor_diag(struct timeval *tv, uint16_t index,
"Vendor Diagnostic", NULL, extra_str);
switch (manufacturer) {
- case 15:
+ case COMPANY_ID_BROADCOM:
broadcom_lm_diag(data, size);
break;
default:
@@ -16161,7 +16168,7 @@ static void mgmt_print_system_config_tlv(void *data, void *user_data)
value = get_u8(entry->value);
else if (entry->length == 2)
value = get_le16(entry->value);
- else if (entry->length == 4)
+ else
value = get_le32(entry->value);
print_field("%s: %u", desc, value);
} else {
--
2.54.0.rc1.513.gad8abe7a5a-goog
^ permalink raw reply related
* [bluetooth-next:master] BUILD SUCCESS 912a499a7955a2773a20f33e495a5ce24d7279f0
From: kernel test robot @ 2026-04-14 10:51 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master
branch HEAD: 912a499a7955a2773a20f33e495a5ce24d7279f0 Bluetooth: btintel_pcie: Support Product level reset
elapsed time: 873m
configs tested: 89
configs skipped: 1
The following configs have been built successfully.
More configs may be tested in the coming days.
tested configs:
alpha allnoconfig gcc-15.2.0
alpha allyesconfig gcc-15.2.0
arc allmodconfig gcc-15.2.0
arc allnoconfig gcc-15.2.0
arc allyesconfig gcc-15.2.0
arm allnoconfig clang-23
arm allnoconfig gcc-15.2.0
arm allyesconfig gcc-15.2.0
arm randconfig-002-20260414 gcc-15.2.0
arm64 allmodconfig clang-19
arm64 allnoconfig gcc-15.2.0
csky allmodconfig gcc-15.2.0
csky allnoconfig gcc-15.2.0
hexagon allmodconfig clang-17
hexagon allnoconfig clang-23
hexagon allnoconfig gcc-15.2.0
hexagon randconfig-001-20260414 clang-23
hexagon randconfig-002-20260414 clang-16
i386 allmodconfig gcc-14
i386 allnoconfig gcc-14
i386 allnoconfig gcc-15.2.0
i386 allyesconfig gcc-14
i386 randconfig-014-20260414 gcc-14
loongarch allmodconfig clang-19
loongarch allnoconfig clang-23
loongarch allnoconfig gcc-15.2.0
loongarch randconfig-001-20260414 clang-18
loongarch randconfig-002-20260414 clang-23
m68k allmodconfig gcc-15.2.0
m68k allnoconfig gcc-15.2.0
m68k allyesconfig gcc-15.2.0
microblaze allnoconfig gcc-15.2.0
microblaze allyesconfig gcc-15.2.0
mips allmodconfig gcc-15.2.0
mips allnoconfig gcc-15.2.0
mips allyesconfig gcc-15.2.0
nios2 allmodconfig gcc-11.5.0
nios2 allnoconfig clang-23
nios2 allnoconfig gcc-11.5.0
nios2 randconfig-001-20260414 gcc-11.5.0
nios2 randconfig-002-20260414 gcc-11.5.0
openrisc allmodconfig gcc-15.2.0
openrisc allnoconfig clang-23
openrisc allnoconfig gcc-15.2.0
openrisc defconfig gcc-15.2.0
parisc allmodconfig gcc-15.2.0
parisc allnoconfig clang-23
parisc allnoconfig gcc-15.2.0
parisc allyesconfig gcc-15.2.0
parisc defconfig gcc-15.2.0
powerpc allmodconfig gcc-15.2.0
powerpc allnoconfig clang-23
powerpc allnoconfig gcc-15.2.0
riscv allmodconfig clang-23
riscv allnoconfig clang-23
riscv allnoconfig gcc-15.2.0
riscv allyesconfig clang-16
riscv randconfig-001-20260414 clang-23
riscv randconfig-002-20260414 gcc-8.5.0
s390 allmodconfig clang-18
s390 allnoconfig clang-23
s390 allyesconfig gcc-15.2.0
s390 randconfig-001-20260414 clang-23
s390 randconfig-002-20260414 clang-23
sh allmodconfig gcc-15.2.0
sh allnoconfig clang-23
sh allnoconfig gcc-15.2.0
sh allyesconfig gcc-15.2.0
sh randconfig-001-20260414 gcc-15.2.0
sh randconfig-002-20260414 gcc-15.2.0
sparc allnoconfig clang-23
sparc allnoconfig gcc-15.2.0
sparc64 allmodconfig clang-23
um allmodconfig clang-19
um allnoconfig clang-23
um allyesconfig gcc-14
x86_64 allmodconfig clang-20
x86_64 allnoconfig clang-20
x86_64 allnoconfig clang-23
x86_64 allyesconfig clang-20
x86_64 randconfig-001-20260414 gcc-14
x86_64 randconfig-003-20260414 gcc-14
x86_64 randconfig-004-20260414 clang-20
x86_64 randconfig-005-20260414 clang-20
x86_64 rhel-9.4-rust clang-20
xtensa allnoconfig clang-23
xtensa allnoconfig gcc-15.2.0
xtensa allyesconfig gcc-15.2.0
xtensa cadence_csp_defconfig gcc-15.2.0
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH v7 0/8] Add support for handling PCIe M.2 Key E connectors in devicetree
From: Chen-Yu Tsai @ 2026-04-14 10:29 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Manivannan Sadhasivam, Manivannan Sadhasivam, Rob Herring,
Greg Kroah-Hartman, Jiri Slaby, Nathan Chancellor, Nicolas Schier,
Hans de Goede, Ilpo Järvinen, Mark Pearson, Derek J. Clark,
Krzysztof Kozlowski, Conor Dooley, Marcel Holtmann,
Luiz Augusto von Dentz, Bartosz Golaszewski, Bartosz Golaszewski,
linux-serial, linux-kernel, linux-kbuild, platform-driver-x86,
linux-pci, devicetree, linux-arm-msm, linux-bluetooth, linux-pm,
Stephan Gerhold, Dmitry Baryshkov, linux-acpi, Hans de Goede,
Bartosz Golaszewski
In-Reply-To: <ad36pIu-0dutL7Nk@ashevche-desk.local>
On Tue, Apr 14, 2026 at 4:28 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Tue, Apr 14, 2026 at 01:03:19PM +0800, Chen-Yu Tsai wrote:
> > On Tue, Apr 14, 2026 at 12:08 AM Manivannan Sadhasivam <mani@kernel.org> wrote:
> > > On Mon, Apr 13, 2026 at 07:33:12PM +0530, Manivannan Sadhasivam wrote:
> > > > On Mon, Apr 13, 2026 at 03:54:59PM +0800, Chen-Yu Tsai wrote:
> > > > > On Thu, Mar 26, 2026 at 01:36:28PM +0530, Manivannan Sadhasivam wrote:
>
> ...
>
> > > > > - Given that this connector actually represents two devices, how do I
> > > > > say I want the BT part to be a wakeup source, but not the WiFi part?
> > > > > Does wakeup-source even work at this point?
> > > >
> > > > You can't use the DT property since the devices are not described in DT
> > > > statically. But you can still use the per-device 'wakeup' sysfs knob to enable
> > > > wakeup.
> >
> > I see. I think not being able to specify generic properties for the devices
> > on the connector is going to be a bit problematic.
>
> This is nature of the open-connectors, especially on the busses that are
> hotpluggable, like PCIe. We never know what is connected there _ahead_.
I believe what you mean by "hotpluggable" is "user replaceable".
> In other words you can't describe in DT something that may not exist.
But this is actually doable with the PCIe slot representation. The
properties are put in the device node for the slot. If no card is
actually inserted in the slot, then no device is created, and the
device node is left as not associated with anything.
It's just that for this new M.2 E-key connector, there aren't separate
nodes for each interface. And the system doesn't associate the device
node with the device, because it's no longer a child node of the
controller or hierarchy, but connected over the OF graph.
Moving over to the E-key connector representation seems like one step
forward and one step backward in descriptive ability. We gain proper
power sequencing, but lose generic properties.
The latter part is solvable, but we likely need child nodes under the
connector for the different interfaces. Properties that make sense for
one type might not make sense for another.
Thanks
ChenYu
P.S. We could also just add child device nodes under the controller to
put the generic properties, but that's splitting the description into
multiple parts. Let's not go there if at all possible.
^ permalink raw reply
* Re: [PATCH v2] Bluetooth: Add Broadcom channel priority commands
From: Neal Gompa @ 2026-04-14 8:59 UTC (permalink / raw)
To: fnkl.kernel
Cc: Sven Peter, Janne Grunau, Marcel Holtmann, Luiz Augusto von Dentz,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, linux-kernel, asahi, linux-arm-kernel,
linux-bluetooth, netdev
In-Reply-To: <20260407-brcm-prio-v2-1-3f745edf49af@gmail.com>
On Tue, Apr 7, 2026 at 1:46 PM Sasha Finkelstein via B4 Relay
<devnull+fnkl.kernel.gmail.com@kernel.org> wrote:
>
> From: Sasha Finkelstein <fnkl.kernel@gmail.com>
>
> Certain Broadcom bluetooth chips (bcm4377/bcm4378/bcm438) need ACL
> streams carrying audio to be set as "high priority" using a vendor
> specific command to prevent 10-ish second-long dropouts whenever
> something does a device scan. This patch sends the command when the
> socket priority is set to TC_PRIO_INTERACTIVE, as BlueZ does for audio.
>
> Signed-off-by: Sasha Finkelstein <fnkl.kernel@gmail.com>
> ---
> Changes in v2:
> - new ioctl got nack-ed, so let's use sk_priority as the trigger
> - Link to v1: https://lore.kernel.org/r/20260407-brcm-prio-v1-1-f38b17376640@gmail.com
> ---
Thank you so much for this!
Reviewed-by: Neal Gompa <neal@gompa.dev>
--
真実はいつも一つ!/ Always, there's only one truth!
^ permalink raw reply
* Re: [PATCH v7 0/8] Add support for handling PCIe M.2 Key E connectors in devicetree
From: Andy Shevchenko @ 2026-04-14 8:28 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Manivannan Sadhasivam, Manivannan Sadhasivam, Rob Herring,
Greg Kroah-Hartman, Jiri Slaby, Nathan Chancellor, Nicolas Schier,
Hans de Goede, Ilpo Järvinen, Mark Pearson, Derek J. Clark,
Krzysztof Kozlowski, Conor Dooley, Marcel Holtmann,
Luiz Augusto von Dentz, Bartosz Golaszewski, Bartosz Golaszewski,
linux-serial, linux-kernel, linux-kbuild, platform-driver-x86,
linux-pci, devicetree, linux-arm-msm, linux-bluetooth, linux-pm,
Stephan Gerhold, Dmitry Baryshkov, linux-acpi, Hans de Goede,
Bartosz Golaszewski
In-Reply-To: <CAGXv+5E=tujhtZjwi6Qm7hk3Ks74UzTQHWq82NiTEw1+vYod5g@mail.gmail.com>
On Tue, Apr 14, 2026 at 01:03:19PM +0800, Chen-Yu Tsai wrote:
> On Tue, Apr 14, 2026 at 12:08 AM Manivannan Sadhasivam <mani@kernel.org> wrote:
> > On Mon, Apr 13, 2026 at 07:33:12PM +0530, Manivannan Sadhasivam wrote:
> > > On Mon, Apr 13, 2026 at 03:54:59PM +0800, Chen-Yu Tsai wrote:
> > > > On Thu, Mar 26, 2026 at 01:36:28PM +0530, Manivannan Sadhasivam wrote:
...
> > > > - Given that this connector actually represents two devices, how do I
> > > > say I want the BT part to be a wakeup source, but not the WiFi part?
> > > > Does wakeup-source even work at this point?
> > >
> > > You can't use the DT property since the devices are not described in DT
> > > statically. But you can still use the per-device 'wakeup' sysfs knob to enable
> > > wakeup.
>
> I see. I think not being able to specify generic properties for the devices
> on the connector is going to be a bit problematic.
This is nature of the open-connectors, especially on the busses that are
hotpluggable, like PCIe. We never know what is connected there _ahead_.
In other words you can't describe in DT something that may not exist.
> requires specifying a bounce buffer / SWIOTLB for the PCIe WiFi card. The
> PCIe controller does not have an IOMMU behind it.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [Bug 221339] AX200 -19 errors on boot after firmware 20260313-1.1
From: bugzilla-daemon @ 2026-04-14 7:27 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <bug-221339-62941@https.bugzilla.kernel.org/>
https://bugzilla.kernel.org/show_bug.cgi?id=221339
--- Comment #7 from The Linux kernel's regression tracker (Thorsten Leemhuis) (regressions@leemhuis.info) ---
(In reply to Paul Menzel from comment #6)
> @Thorsten, only if you didn’t know, but for the Bluetooth subsystem the
> Bugzilla issues are sent to the list [1],
That for some subsystems nevertheless makes no difference (even if they have B:
pointing to a bugzilla im MAINTAINERS, which BT iirc has not), so email I'd say
mail is the best choice.
--
You may reply to this email to add a comment.
You are receiving this mail because:
You are the assignee for the bug.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox