* [PATCH v5] Bluetooth: hci_qca: Convert timeout from jiffies to ms
From: Shuai Zhang @ 2026-04-29 12:38 UTC (permalink / raw)
To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz
Cc: linux-arm-msm, linux-bluetooth, linux-kernel, cheng.jiang,
quic_chezhou, wei.deng, jinwang.li, mengshi.wu, shuai.zhang,
stable, Paul Menzel, Bartosz Golaszewski
Since the timer uses jiffies as its unit rather than ms, the timeout value
must be converted from ms to jiffies when configuring the timer. Otherwise,
the intended 8s timeout is incorrectly set to approximately 33s.
Wake timer depends on commit c347ca17d62a
Cc: stable@vger.kernel.org
Fixes: d841502c79e3 ("Bluetooth: hci_qca: Collect controller memory dump during SSR")
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Shuai Zhang <shuai.zhang@oss.qualcomm.com>
---
Changes v5:
- add depends on commit
- Link to v4
https://lore.kernel.org/all/20260327082941.1396521-1-shuai.zhang@oss.qualcomm.com/
Changes v4:
- add review-by signoff
- Link to v3
https://lore.kernel.org/all/20251107033924.3707495-1-quic_shuaz@quicinc.com/
Changes v3:
- add Fixes tag
- Link to v2
https://lore.kernel.org/all/20251106140103.1406081-1-quic_shuaz@quicinc.com/
Changes v2:
- Split timeout conversion into a separate patch.
- Clarified commit messages and added test case description.
- Link to v1
https://lore.kernel.org/all/20251104112601.2670019-1-quic_shuaz@quicinc.com/
---
drivers/bluetooth/hci_qca.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index cd1834246..89073adec 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -1607,7 +1607,7 @@ static void qca_wait_for_dump_collection(struct hci_dev *hdev)
struct qca_data *qca = hu->priv;
wait_on_bit_timeout(&qca->flags, QCA_MEMDUMP_COLLECTION,
- TASK_UNINTERRUPTIBLE, MEMDUMP_TIMEOUT_MS);
+ TASK_UNINTERRUPTIBLE, msecs_to_jiffies(MEMDUMP_TIMEOUT_MS));
clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
}
--
2.34.1
^ permalink raw reply related
* RE: [v1] gatt-client: Fix use-after-free caused by reentrant client teardown
From: bluez.test.bot @ 2026-04-29 12:41 UTC (permalink / raw)
To: linux-bluetooth, jinwang.li
In-Reply-To: <20260429114806.2337081-1-jinwang.li@oss.qualcomm.com>
[-- Attachment #1: Type: text/plain, Size: 825 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=1087435
---Test result---
Test Summary:
CheckPatch PASS 0.39 seconds
GitLint PASS 0.32 seconds
BuildEll PASS 20.12 seconds
BluezMake PASS 587.78 seconds
CheckSmatch PASS 319.98 seconds
bluezmakeextell PASS 163.68 seconds
IncrementalBuild PASS 595.61 seconds
ScanBuild PASS 903.06 seconds
https://github.com/bluez/bluez/pull/2084
---
Regards,
Linux Bluetooth
^ permalink raw reply
* Re: [PATCH 7/9] Bluetooth: hci_sync: Add NVMEM-backed BD address retrieval
From: Andrew Lunn @ 2026-04-29 13:15 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Loic Poulain, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, Konrad Dybcio, Jens Axboe,
Johannes Berg, Jeff Johnson, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, linux-mmc, devicetree, linux-kernel, linux-arm-msm,
linux-block, linux-wireless, ath10k, linux-bluetooth, netdev,
daniel
In-Reply-To: <CAMRc=Me9G9vd06a39vi_UrXCTkUtJQRogm2MqgnwLS_r3Thyzg@mail.gmail.com>
On Wed, Apr 29, 2026 at 10:53:13AM +0200, Bartosz Golaszewski wrote:
> On Tue, Apr 28, 2026 at 4:23 PM Loic Poulain
> <loic.poulain@oss.qualcomm.com> wrote:
> >
> > Some devices store the Bluetooth BD address in non-volatile
> > memory, which can be accessed through the NVMEM framework.
> > Similar to Ethernet or WiFi MAC addresses, add support for
> > reading the BD address from a 'local-bd-address' NVMEM cell.
> >
> > As with the device-tree provided BD address, add a quirk to
> > indicate whether a device or platform should attempt to read
> > the address from NVMEM when no valid in-chip address is present.
> > Also add a quirk to indicate if the address is stored in
> > big-endian byte order.
> >
> > Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> > ---
>
> Is there any reason why we can't extend the existing
> of_get_mac_address() with another property name and use it here? It
> already has support for mac addresses from nvmem.
Does it even need to be a different property name? Is a bluetooth MAC
address somehow different to an Ethernet MAC address? Isn't it just a
EUI-48, independent of it being Ethernet, Bluetooth, wifi, fddi, token
ring, homing pigeon?
Andrew
^ permalink raw reply
* [PATCH] Bluetooth: hci_event: fix memset typo
From: Jann Horn @ 2026-04-29 13:40 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz
Cc: Iulia Tanasescu, linux-bluetooth, linux-kernel, Jann Horn
hci_le_big_sync_established_evt() currently does:
conn->num_bis = 0;
memset(conn->bis, 0, sizeof(conn->num_bis));
sizeof(conn->num_bis) is wrong - it would make sense to either use
conn->num_bis (before setting that to 0) or sizeof(conn->bis).
Fix it by using sizeof(conn->bis), the least intrusive change.
Luckily, nothing actually depends on this memset() working properly:
Nothing seems to ever read from conn->bis beyond conn->num_bis, and when
conn->num_bis is increased, the corresponding elements of conn->bis are
initialized. So I think this line could also just be removed.
This is a purely theoretical fix and should have no impact on actual
behavior.
Fixes: 42ecf1947135 ("Bluetooth: ISO: Do not emit LE BIG Create Sync if previous is pending")
Signed-off-by: Jann Horn <jannh@google.com>
---
compile-tested only
---
net/bluetooth/hci_event.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index b2ee6b6a0f56..ad3945e4fe2a 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -7168,7 +7168,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
clear_bit(HCI_CONN_CREATE_BIG_SYNC, &conn->flags);
conn->num_bis = 0;
- memset(conn->bis, 0, sizeof(conn->num_bis));
+ memset(conn->bis, 0, sizeof(conn->bis));
for (i = 0; i < ev->num_bis; i++) {
u16 handle = le16_to_cpu(ev->bis[i]);
---
base-commit: dca922e019dd758b4c1b4bec8f1d509efddeaab4
change-id: 20260429-bluetooth-memset-fix-01d70ce0acf7
--
Jann Horn <jannh@google.com>
^ permalink raw reply related
* Re: [PATCH BlueZ v5 0/2] client: Add public broadcast advertising support
From: patchwork-bot+bluetooth @ 2026-04-29 13:50 UTC (permalink / raw)
To: raghu447; +Cc: linux-bluetooth
In-Reply-To: <20260429074605.11774-1-raghavendra.rao@collabora.com>
Hello:
This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Wed, 29 Apr 2026 13:16:03 +0530 you wrote:
> This series adds bluetoothctl support for staging Public Broadcast
> Announcement advertising data used during LE Audio public broadcast
> qualification.
>
> Patch 1 adds a public-broadcast command to the advertise submenu. The
> command stages Public Broadcast Announcement ServiceData using UUID
> 0x1856 and supports SQ and HQ presets.
>
> [...]
Here is the summary with links:
- [BlueZ,v5,1/2] client: add public-broadcast advertising command
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=5dc2d7e3334e
- [BlueZ,v5,2/2] client: make advertise.name use public broadcast name
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=278f3439c45f
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [bluez/bluez] 3171f7: monitor: Add decoding support for Public Broadcast...
From: raghava447 @ 2026-04-29 13:51 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/master
Home: https://github.com/bluez/bluez
Commit: 3171f7fd3685874a429556d23ef49f8504fa8c3c
https://github.com/bluez/bluez/commit/3171f7fd3685874a429556d23ef49f8504fa8c3c
Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Date: 2026-04-28 (Tue, 28 Apr 2026)
Changed paths:
M monitor/packet.c
Log Message:
-----------
monitor: Add decoding support for Public Broadcast Announcements
This adds support for decoding Public Broadcast Announcements (PBP).
Commit: 5dc2d7e3334e4564f192f1b8c76217e114013066
https://github.com/bluez/bluez/commit/5dc2d7e3334e4564f192f1b8c76217e114013066
Author: raghavendra <raghavendra.rao@collabora.com>
Date: 2026-04-29 (Wed, 29 Apr 2026)
Changed paths:
M client/advertising.c
M client/advertising.h
M client/main.c
Log Message:
-----------
client: add public-broadcast advertising command
Commit: 278f3439c45ffcb1309f9fe961be1b120bdde459
https://github.com/bluez/bluez/commit/278f3439c45ffcb1309f9fe961be1b120bdde459
Author: raghavendra <raghavendra.rao@collabora.com>
Date: 2026-04-29 (Wed, 29 Apr 2026)
Changed paths:
M client/advertising.c
Log Message:
-----------
client: make advertise.name use public broadcast name
Compare: https://github.com/bluez/bluez/compare/b3729e26cc42...278f3439c45f
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* RE: [v2] Bluetooth: btusb: Allow firmware re-download when version matches
From: bluez.test.bot @ 2026-04-29 14:56 UTC (permalink / raw)
To: linux-bluetooth, shuai.zhang
In-Reply-To: <20260429121207.1306526-1-shuai.zhang@oss.qualcomm.com>
[-- Attachment #1: Type: text/plain, Size: 1527 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=1087449
---Test result---
Test Summary:
CheckPatch PASS 0.59 seconds
GitLint FAIL 0.25 seconds
SubjectPrefix PASS 0.08 seconds
BuildKernel PASS 24.84 seconds
CheckAllWarning PASS 28.00 seconds
CheckSparse PASS 26.10 seconds
BuildKernel32 PASS 24.71 seconds
TestRunnerSetup PASS 524.21 seconds
IncrementalBuild PASS 23.70 seconds
Details
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[v2] Bluetooth: btusb: Allow firmware re-download when version matches
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
31: B1 Line exceeds max length (84>80): " https://lore.kernel.org/all/20260108074353.1027877-1-shuai.zhang@oss.qualcomm.com/"
https://github.com/bluez/bluetooth-next/pull/130
---
Regards,
Linux Bluetooth
^ permalink raw reply
* RE: [v5] Bluetooth: hci_qca: Convert timeout from jiffies to ms
From: bluez.test.bot @ 2026-04-29 14:58 UTC (permalink / raw)
To: linux-bluetooth, shuai.zhang
In-Reply-To: <20260429123802.1310681-1-shuai.zhang@oss.qualcomm.com>
[-- Attachment #1: Type: text/plain, Size: 2355 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=1087462
---Test result---
Test Summary:
CheckPatch FAIL 0.59 seconds
GitLint FAIL 0.24 seconds
SubjectPrefix PASS 0.08 seconds
BuildKernel PASS 26.43 seconds
CheckAllWarning PASS 29.32 seconds
CheckSparse PASS 28.06 seconds
BuildKernel32 PASS 26.08 seconds
TestRunnerSetup PASS 577.43 seconds
IncrementalBuild PASS 25.38 seconds
Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[v5] Bluetooth: hci_qca: Convert timeout from jiffies to ms
ERROR: Please use git commit description style 'commit <12+ chars of sha1> ("<title line>")' - ie: 'commit c347ca17d62a ("Bluetooth: hci_qca: Fix missing wakeup during SSR memdump handling")'
#125:
Wake timer depends on commit c347ca17d62a
total: 1 errors, 0 warnings, 8 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/14546625.patch has style problems, please review.
NOTE: Ignored message types: UNKNOWN_COMMIT_ID
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[v5] Bluetooth: hci_qca: Convert timeout from jiffies to ms
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
17: B1 Line exceeds max length (84>80): " https://lore.kernel.org/all/20260327082941.1396521-1-shuai.zhang@oss.qualcomm.com/"
https://github.com/bluez/bluetooth-next/pull/131
---
Regards,
Linux Bluetooth
^ permalink raw reply
* Re: [PATCH v2] Bluetooth: btusb: Allow firmware re-download when version matches
From: Luiz Augusto von Dentz @ 2026-04-29 15:17 UTC (permalink / raw)
To: Shuai Zhang
Cc: Marcel Holtmann, linux-bluetooth, linux-kernel, linux-arm-msm,
cheng.jiang, quic_chezhou, wei.deng, jinwang.li, mengshi.wu
In-Reply-To: <20260429121207.1306526-1-shuai.zhang@oss.qualcomm.com>
Hi Shuai,
On Wed, Apr 29, 2026 at 8:12 AM Shuai Zhang
<shuai.zhang@oss.qualcomm.com> wrote:
>
> The Bluetooth host decides whether to download firmware by reading the
> controller firmware download completion flag and firmware version
> information.
>
> If a USB error occurs during the firmware download process (for example
> due to a USB disconnect), the download is aborted immediately. An
> incomplete firmware transfer does not cause the controller to set the
> download completion flag, but the firmware version information may be
> updated at an early stage of the download process.
Hold on, if the download has been aborted then the version should be
reverted, or rather just update once the firmware loading is complete,
so this indicates there is a bug somewhere that needs fixing, not
worked around.
> In this case, after USB reconnection, the host attempts to re-download
> the firmware because the download completion flag is not set. However,
> since the controller reports the same firmware version as the target
> firmware, the download is skipped. This ultimately results in the
> firmware not being properly updated on the controller.
>
> This change removes the restriction that skips firmware download when
> the versions are equal. It covers scenarios where the USB connection
> can be disconnected at any time and ensures that firmware download can
> be retriggered after USB reconnection, allowing the Bluetooth firmware
> to be correctly and completely updated.
>
> Signed-off-by: Shuai Zhang <shuai.zhang@oss.qualcomm.com>
> ---
> Changes v2:
> - Update code comments and commit message to reflect the correct logic.
> - Align the commit title with upstream conventions.
> - Link v1
> https://lore.kernel.org/all/20260108074353.1027877-1-shuai.zhang@oss.qualcomm.com/
> ---
> drivers/bluetooth/btusb.c | 8 +++++++-
> 1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index 572091e60..70abbabea 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -3550,7 +3550,13 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev,
> "firmware rome 0x%x build 0x%x",
> rver_rom, rver_patch, ver_rom, ver_patch);
>
> - if (rver_rom != ver_rom || rver_patch <= ver_patch) {
> + /* Allow rampatch when the patch version equals the firmware version.
> + * A firmware download may be aborted by a transient USB error (e.g.
> + * disconnect) after the controller updates version info but before
> + * completion.
> + * Allowing equal versions enables re-flashing during recovery.
> + */
> + if (rver_rom != ver_rom || rver_patch < ver_patch) {
As I said above, this sounds more like a workaround. That said, I
wonder why it would print an error if the version matches, it sounds
to be that if the version matches it should just skip and consider it
has been loaded already in case the actual problem is fixed by setting
the new version only when loading has been completed.
> bt_dev_err(hdev, "rampatch file version did not match with firmware");
> err = -EINVAL;
> goto done;
> --
> 2.34.1
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH v5] Bluetooth: hci_qca: Convert timeout from jiffies to ms
From: Luiz Augusto von Dentz @ 2026-04-29 15:21 UTC (permalink / raw)
To: Shuai Zhang
Cc: Bartosz Golaszewski, Marcel Holtmann, linux-arm-msm,
linux-bluetooth, linux-kernel, cheng.jiang, quic_chezhou,
wei.deng, jinwang.li, mengshi.wu, stable, Paul Menzel,
Bartosz Golaszewski
In-Reply-To: <20260429123802.1310681-1-shuai.zhang@oss.qualcomm.com>
Hi Shuai,
On Wed, Apr 29, 2026 at 8:38 AM Shuai Zhang
<shuai.zhang@oss.qualcomm.com> wrote:
>
> Since the timer uses jiffies as its unit rather than ms, the timeout value
> must be converted from ms to jiffies when configuring the timer. Otherwise,
> the intended 8s timeout is incorrectly set to approximately 33s.
>
> Wake timer depends on commit c347ca17d62a
>
> Cc: stable@vger.kernel.org
> Fixes: d841502c79e3 ("Bluetooth: hci_qca: Collect controller memory dump during SSR")
> Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
> Acked-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> Signed-off-by: Shuai Zhang <shuai.zhang@oss.qualcomm.com>
> ---
> Changes v5:
> - add depends on commit
> - Link to v4
> https://lore.kernel.org/all/20260327082941.1396521-1-shuai.zhang@oss.qualcomm.com/
>
> Changes v4:
> - add review-by signoff
> - Link to v3
> https://lore.kernel.org/all/20251107033924.3707495-1-quic_shuaz@quicinc.com/
>
> Changes v3:
> - add Fixes tag
> - Link to v2
> https://lore.kernel.org/all/20251106140103.1406081-1-quic_shuaz@quicinc.com/
>
> Changes v2:
> - Split timeout conversion into a separate patch.
> - Clarified commit messages and added test case description.
> - Link to v1
> https://lore.kernel.org/all/20251104112601.2670019-1-quic_shuaz@quicinc.com/
> ---
> drivers/bluetooth/hci_qca.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> index cd1834246..89073adec 100644
> --- a/drivers/bluetooth/hci_qca.c
> +++ b/drivers/bluetooth/hci_qca.c
> @@ -1607,7 +1607,7 @@ static void qca_wait_for_dump_collection(struct hci_dev *hdev)
> struct qca_data *qca = hu->priv;
>
> wait_on_bit_timeout(&qca->flags, QCA_MEMDUMP_COLLECTION,
> - TASK_UNINTERRUPTIBLE, MEMDUMP_TIMEOUT_MS);
> + TASK_UNINTERRUPTIBLE, msecs_to_jiffies(MEMDUMP_TIMEOUT_MS));
Well defining it as ms seems useless then, just do #define
MEMDUMP_TIMEOUT msecs_to_jiffies(<value in ms>).
>
> clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
> }
> --
> 2.34.1
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* [PATCH] Bluetooth: btrtl: fix RTL8761B/BU broken LE extended scan
From: Alexej Sidorenko @ 2026-04-29 15:13 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, luiz.dentz, linux-kernel, Alexej Sidorenko
RTL8761B and RTL8761BU devices report HCI version 5.1 but do not
support the LE Extended Scan commands. This causes repeated failures
with Opcode 0x2042 (LE Set Extended Scan Parameters) returning -EBUSY
when BlueZ attempts extended scanning while a connection is active.
Set HCI_QUIRK_BROKEN_EXT_SCAN for CHIP_ID_8761B to make BlueZ fall
back to legacy LE scan commands which the firmware supports correctly.
Tested with RTL8761BU (USB ID 0bda:a728) where the issue manifested
as continuous 'Opcode 0x2042 failed: -16' errors in dmesg whenever
a BLE connection was active.
Signed-off-by: Alexej Sidorenko <alexej@sidorenko.cz>
---
drivers/bluetooth/btrtl.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
index 62f9d4df3..49ecb18fe 100644
--- a/drivers/bluetooth/btrtl.c
+++ b/drivers/bluetooth/btrtl.c
@@ -1342,6 +1342,19 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
if (!btrtl_dev->ic_info)
return;
+ switch (btrtl_dev->project_id) {
+ case CHIP_ID_8761B:
+ /* RTL8761B/BU reports HCI version 5.1 but does not support
+ * the LE Extended Scan commands (Opcode 0x2042), causing
+ * repeated -EBUSY failures when BlueZ attempts extended
+ * scanning while a connection is active.
+ */
+ hci_set_quirk(hdev, HCI_QUIRK_BROKEN_EXT_SCAN);
+ break;
+ default:
+ break;
+ }
+
switch (btrtl_dev->ic_info->lmp_subver) {
case RTL_ROM_LMP_8703B:
/* 8723CS reports two pages for local ext features,
--
2.45.2
^ permalink raw reply related
* [PATCH BlueZ v6 0/3] Add RAS Packet format and Notification support
From: Prathibha Madugonde @ 2026-04-29 15:29 UTC (permalink / raw)
To: linux-bluetooth; +Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg
From: Prathibha Madugonde <prathibha.madugonde@oss.qualcomm.com>
Changes in v6:
src/shared:
Removed 5 separate CCC write callbacks
Added unified ras_ranging_data_ccc_write_cb for Real-time and On-demand
Removed unused macros
refactored CS mode processing into separate functions
Improved iov_prepend_bytes - use realloc/memmove instead of malloc/memcpy
unit/test-rap:
Added RAS/SR/SPE/BI-11-C test case for mutual exclusivity validation
Changes in v5:
Fixed Max length err in title
Changes in v4:
Fixed declaration after statement in src/shared/rap.c
Changes in v3:
Fix for cs_mode_one_data struct members rearrage as per spec
Reading of cs_mode_one_data in rap_hci.c
Address cs_mode data struct padding in src/shared/rap.c
Changes in v2:
Fixed missing declaration in src/shared/rap.c
Patch overview:
1/3 src/shared: Add RAS packet format and sending notifications to client
2/3 uint/test-rap : Add PTS tests for CS reflector
3/3 profiles/ranging: Read cs_mode_one_data members as per spec
profiles/ranging/rap_hci.c | 25 +-
src/shared/rap.c | 1188 +++++++++++++++++++++++++++++++++++-
src/shared/rap.h | 4 +-
unit/test-rap.c | 327 +++++++++-
4 files changed, 1515 insertions(+), 29 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH BlueZ v6 1/3] src/shared: Add RAS packet format and notification support
From: Prathibha Madugonde @ 2026-04-29 15:29 UTC (permalink / raw)
To: linux-bluetooth; +Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg
In-Reply-To: <20260429152942.2940978-1-prathm@qti.qualcomm.com>
From: Prathibha Madugonde <prathibha.madugonde@oss.qualcomm.com>
Implement complete RAS data pipeline:
- Handle HCI CS subevent result/continuation events
- Serialize ranging/subevent headers per spec
- GATT notifications for real-time ranging data
---
src/shared/rap.c | 1188 +++++++++++++++++++++++++++++++++++++++++++++-
src/shared/rap.h | 4 +-
2 files changed, 1178 insertions(+), 14 deletions(-)
diff --git a/src/shared/rap.c b/src/shared/rap.c
index ac6de04e0..7ffa9cfc0 100644
--- a/src/shared/rap.c
+++ b/src/shared/rap.c
@@ -14,6 +14,7 @@
#include <errno.h>
#include "bluetooth/bluetooth.h"
+#include "bluetooth/hci.h"
#include "bluetooth/uuid.h"
#include "src/shared/queue.h"
@@ -33,6 +34,154 @@
/* Total number of attribute handles reserved for the RAS service */
#define RAS_TOTAL_NUM_HANDLES 18
+/* 2(rc+cfg) + 1(tx_pwr) + 1(4 bits antenna_mask, 2 bits reserved,
+ * 2 bits pct_format)
+ */
+#define RAS_RANGING_HEADER_SIZE 4
+#define TOTAL_RAS_RANGING_HEADER_SIZE 5
+#define ATT_OVERHEAD 3 /* 1(opcode) + 2(char handle) */
+#define RAS_STEP_ABORTED_BIT 0x80/* set step aborted */
+#define RAS_SUBEVENT_HEADER_SIZE 8
+
+enum pct_format {
+ IQ = 0,
+ PHASE = 1,
+};
+
+enum ranging_done_status {
+ RANGING_DONE_ALL_RESULTS_COMPLETE = 0x0,
+ RANGING_DONE_PARTIAL_RESULTS = 0x1,
+ RANGING_DONE_ABORTED = 0xF,
+};
+
+enum subevent_done_status {
+ SUBEVENT_DONE_ALL_RESULTS_COMPLETE = 0x0,
+ SUBEVENT_DONE_PARTIAL_RESULTS = 0x1,
+ SUBEVENT_DONE_ABORTED = 0xF,
+};
+
+enum ranging_abort_reason {
+ RANGING_ABORT_NO_ABORT = 0x0,
+ RANGING_ABORT_LOCAL_HOST_OR_REMOTE = 0x1,
+ RANGING_ABORT_INSUFFICIENT_FILTERED_CHANNELS = 0x2,
+ RANGING_ABORT_INSTANT_HAS_PASSED = 0x3,
+ RANGING_ABORT_UNSPECIFIED = 0xF,
+};
+
+enum subevent_abort_reason {
+ SUBEVENT_ABORT_NO_ABORT = 0x0,
+ SUBEVENT_ABORT_LOCAL_HOST_OR_REMOTE = 0x1,
+ SUBEVENT_ABORT_NO_CS_SYNC_RECEIVED = 0x2,
+ SUBEVENT_ABORT_SCHEDULING_CONFLICTS_OR_LIMITED_RESOURCES = 0x3,
+ SUBEVENT_ABORT_UNSPECIFIED = 0xF,
+};
+
+/* Segmentation header: 1 byte
+ * bit 0: first_segment
+ * bit 1: last_segment
+ * bits 2-7: rolling_segment_counter (6 bits)
+ */
+struct segmentation_header {
+ uint8_t first_segment;
+ uint8_t last_segment;
+ uint8_t rolling_segment_counter;
+};
+
+/* Macros to pack/unpack segmentation header */
+#define SEG_HDR_PACK(first, last, counter) \
+ ((uint8_t)(((first) ? 0x01 : 0x00) | \
+ ((last) ? 0x02 : 0x00) | \
+ (((counter) & 0x3F) << 2)))
+
+struct ranging_header {
+ uint16_t ranging_counter;
+ uint8_t configuration_id;
+ int8_t selected_tx_power;
+ uint8_t antenna_paths_mask;
+ uint8_t pct_format;
+} __packed;
+
+/* Macros to pack/unpack ranging header */
+#define RANGING_HDR_PACK_BYTE0_1(rc, cfg) \
+ ((uint16_t)(((rc) & 0x0FFF) | (((cfg) & 0x0F) << 12)))
+
+#define RANGING_HDR_PACK_BYTE3(ant_mask, pct_fmt) \
+ ((uint8_t)(((ant_mask) & 0x0F) | (((pct_fmt) & 0x03) << 6)))
+
+struct ras_subevent_header {
+ uint16_t start_acl_conn_event;
+ uint16_t frequency_compensation;
+ uint8_t ranging_done_status;
+ uint8_t subevent_done_status;
+ uint8_t ranging_abort_reason;
+ uint8_t subevent_abort_reason;
+ int8_t reference_power_level;
+ uint8_t num_steps_reported;
+};
+
+/* Macros to pack/unpack RAS subevent header status fields */
+#define RAS_DONE_STATUS_PACK(ranging, subevent) \
+ ((uint8_t)(((ranging) & 0x0F) | (((subevent) & 0x0F) << 4)))
+
+#define RAS_ABORT_REASON_PACK(ranging, subevent) \
+ ((uint8_t)(((ranging) & 0x0F) | (((subevent) & 0x0F) << 4)))
+
+struct ras_subevent {
+ struct ras_subevent_header subevent_header;
+ uint8_t subevent_data[];
+};
+
+/* Role maps to Core CS roles (initiator/reflector) */
+enum cs_role {
+ CS_ROLE_INITIATOR = 0x00,
+ CS_ROLE_REFLECTOR = 0x01,
+};
+
+#define CS_INVALID_CONFIG_ID 0xFF
+/* Minimal enums (align to controller values if needed) */
+enum cs_procedure_done_status {
+ CS_PROC_ALL_RESULTS_COMPLETE = 0x00,
+ CS_PROC_PARTIAL_RESULTS = 0x01,
+ CS_PROC_ABORTED = 0x02
+};
+
+/* Main cs_procedure_data */
+struct cs_procedure_data {
+ /* Identity and counters */
+ uint16_t counter;
+ uint8_t num_antenna_paths;
+ /* Flags and status */
+ enum cs_procedure_done_status local_status;
+ enum cs_procedure_done_status remote_status;
+ bool contains_complete_subevent_;
+ /* RAS aggregation */
+ struct segmentation_header segmentation_header_;
+ struct ranging_header ranging_header_;
+ struct iovec ras_raw_data_; /* raw concatenated */
+ uint16_t ras_raw_data_index_;
+ struct ras_subevent_header ras_subevent_header_;
+ struct iovec ras_subevent_data_; /* buffer per subevent */
+ uint8_t ras_subevent_counter_;
+ /* Reference power levels */
+ int8_t initiator_reference_power_level;
+ int8_t reflector_reference_power_level;
+ bool ranging_header_prepended_;
+ bool ras_subevent_header_emitted;
+};
+
+struct cstracker {
+ enum cs_role role; /* INITIATOR/REFLECTOR */
+ uint8_t config_id; /* CS_INVALID_CONFIG_ID */
+ int8_t selected_tx_power; /* PROC_ENABLE_COMPLETE */
+ uint8_t rtt_type; /* RTT type */
+ struct cs_procedure_data *current_proc;
+ /* Cached header values for CONT events (per-connection state) */
+ uint16_t last_proc_counter;
+ uint16_t last_start_acl_conn_evt_counter;
+ uint16_t last_freq_comp;
+ int8_t last_ref_pwr_lvl;
+};
+
/* Ranging Service context */
struct ras {
struct bt_rap_db *rapdb;
@@ -43,9 +192,17 @@ struct ras {
struct gatt_db_attribute *realtime_chrc;
struct gatt_db_attribute *realtime_chrc_ccc;
struct gatt_db_attribute *ondemand_chrc;
+ struct gatt_db_attribute *ondemand_ccc;
struct gatt_db_attribute *cp_chrc;
+ struct gatt_db_attribute *cp_ccc;
struct gatt_db_attribute *ready_chrc;
+ struct gatt_db_attribute *ready_ccc;
struct gatt_db_attribute *overwritten_chrc;
+ struct gatt_db_attribute *overwritten_ccc;
+
+ /* CCC state tracking for mutual exclusivity */
+ uint16_t realtime_ccc_value;
+ uint16_t ondemand_ccc_value;
};
struct bt_rap_db {
@@ -70,6 +227,7 @@ struct bt_rap {
bt_rap_destroy_func_t debug_destroy;
void *debug_data;
void *user_data;
+ struct cstracker *resptracker;
};
static struct queue *rap_db;
@@ -90,6 +248,199 @@ struct bt_rap_ready {
void *data;
};
+uint16_t default_ras_mtu = 247; /*Section 3.1.2 of RAP 1.0*/
+uint8_t ras_segment_header_size = 1;
+
+static struct cs_procedure_data *cs_procedure_data_create(
+ uint16_t procedure_counter,
+ uint8_t num_antenna_paths,
+ uint8_t configuration_id,
+ int8_t selected_tx_power)
+{
+ struct cs_procedure_data *d;
+ uint8_t i;
+
+ d = calloc(1, sizeof(struct cs_procedure_data));
+
+ if (!d)
+ return NULL;
+
+ d->counter = procedure_counter;
+ d->num_antenna_paths = num_antenna_paths;
+ d->local_status = CS_PROC_PARTIAL_RESULTS;
+ d->remote_status = CS_PROC_PARTIAL_RESULTS;
+ d->contains_complete_subevent_ = false;
+ d->segmentation_header_.first_segment = 1;
+ d->segmentation_header_.last_segment = 0;
+ d->segmentation_header_.rolling_segment_counter = 0;
+ d->ranging_header_.ranging_counter = procedure_counter;
+ d->ranging_header_.configuration_id = configuration_id;
+ d->ranging_header_.selected_tx_power = selected_tx_power;
+ d->ranging_header_.antenna_paths_mask = 0;
+
+ for (i = 0; i < num_antenna_paths; i++)
+ d->ranging_header_.antenna_paths_mask |= (1u << i);
+
+ d->ranging_header_.pct_format = IQ;
+ memset(&d->ras_raw_data_, 0, sizeof(d->ras_raw_data_));
+ d->ras_raw_data_index_ = 0;
+ memset(&d->ras_subevent_data_, 0, sizeof(d->ras_subevent_data_));
+ d->ras_subevent_counter_ = 0;
+ d->initiator_reference_power_level = 0;
+ d->reflector_reference_power_level = 0;
+ d->ranging_header_prepended_ = false;
+ d->ras_subevent_header_emitted = false;
+
+ return d;
+}
+
+static void cs_procedure_data_destroy(struct cs_procedure_data *d)
+{
+ if (!d)
+ return;
+
+ free(d->ras_raw_data_.iov_base);
+ free(d->ras_subevent_data_.iov_base);
+ free(d);
+}
+
+static void cs_pd_set_local_status(struct cs_procedure_data *d,
+ enum cs_procedure_done_status s)
+{
+ if (d)
+ d->local_status = s;
+}
+
+static void cs_pd_set_remote_status(struct cs_procedure_data *d,
+ enum cs_procedure_done_status s)
+{
+ if (d)
+ d->remote_status = s;
+}
+
+static void cs_pd_set_reference_power_levels(struct cs_procedure_data *d,
+ int8_t init_lvl, int8_t ref_lvl)
+{
+ if (!d)
+ return;
+
+ d->initiator_reference_power_level = init_lvl;
+ d->reflector_reference_power_level = ref_lvl;
+}
+
+static void cs_pd_ras_begin_subevent(struct cs_procedure_data *d,
+ uint16_t start_acl_conn_event,
+ uint16_t frequency_compensation,
+ int8_t reference_power_level)
+{
+ if (!d)
+ return;
+
+ d->ras_subevent_counter_++;
+ d->ras_subevent_header_.start_acl_conn_event = start_acl_conn_event;
+ d->ras_subevent_header_.frequency_compensation =
+ frequency_compensation;
+ d->ras_subevent_header_.reference_power_level = reference_power_level;
+ d->ras_subevent_header_.num_steps_reported = 0;
+ d->ras_subevent_header_emitted = false;
+ d->ras_subevent_data_.iov_len = 0;
+}
+
+static bool cs_pd_ras_append_subevent_bytes(struct cs_procedure_data *d,
+ const uint8_t *bytes, size_t len)
+{
+ if (!d || !bytes || len == 0)
+ return false;
+
+ return util_iov_append(&d->ras_subevent_data_, bytes, len) != NULL;
+}
+
+static inline size_t serialize_ras_subevent_header(
+ const struct ras_subevent_header *h,
+ uint8_t *out, size_t out_len)
+{
+
+ if (!h || !out || out_len < RAS_SUBEVENT_HEADER_SIZE)
+ return 0;
+
+ put_le16(h->start_acl_conn_event, out + 0);
+ put_le16(h->frequency_compensation, out + 2);
+ out[4] = RAS_DONE_STATUS_PACK(h->ranging_done_status,
+ h->subevent_done_status);
+ out[5] = RAS_ABORT_REASON_PACK(h->ranging_abort_reason,
+ h->subevent_abort_reason);
+ out[6] = h->reference_power_level;
+ out[7] = h->num_steps_reported;
+
+ return RAS_SUBEVENT_HEADER_SIZE;
+}
+
+static bool cs_pd_ras_commit_subevent(struct cs_procedure_data *d,
+ uint8_t num_steps_reported,
+ uint8_t ranging_done_status,
+ uint8_t subevent_done_status,
+ uint8_t ranging_abort_reason,
+ uint8_t subevent_abort_reason)
+{
+ size_t hdr_sz;
+ size_t payload_sz;
+ size_t total;
+ uint8_t *buf;
+ size_t w;
+ bool ok;
+
+ if (!d)
+ return false;
+
+ d->ras_subevent_header_.num_steps_reported =
+ (uint8_t)(d->ras_subevent_header_.num_steps_reported +
+ num_steps_reported);
+ d->ras_subevent_header_.ranging_done_status = ranging_done_status;
+ d->ras_subevent_header_.subevent_done_status = subevent_done_status;
+ d->ras_subevent_header_.ranging_abort_reason = ranging_abort_reason;
+ d->ras_subevent_header_.subevent_abort_reason = subevent_abort_reason;
+
+ if (subevent_done_status == SUBEVENT_DONE_ALL_RESULTS_COMPLETE)
+ d->contains_complete_subevent_ = true;
+
+ if (subevent_done_status == SUBEVENT_DONE_PARTIAL_RESULTS)
+ return true;
+
+ if (!d->ras_subevent_header_emitted) {
+ hdr_sz = RAS_SUBEVENT_HEADER_SIZE;
+ payload_sz = d->ras_subevent_data_.iov_len;
+ total = hdr_sz + payload_sz;
+ buf = (uint8_t *)malloc(total);
+
+ if (!buf)
+ return false;
+
+ w = serialize_ras_subevent_header(&d->ras_subevent_header_,
+ buf, total);
+
+ if (w != hdr_sz) {
+ free(buf);
+ return false;
+ }
+
+ if (payload_sz > 0)
+ memcpy(buf + hdr_sz,
+ (const uint8_t *)d->ras_subevent_data_.iov_base,
+ payload_sz);
+
+ ok = util_iov_append(&d->ras_raw_data_, buf, total) != NULL;
+ free(buf);
+
+ if (!ok)
+ return false;
+
+ d->ras_subevent_data_.iov_len = 0;
+ d->ras_subevent_header_emitted = true;
+ }
+
+ return true;
+}
+
static struct ras *rap_get_ras(struct bt_rap *rap)
{
if (!rap)
@@ -155,6 +506,11 @@ static void rap_free(void *data)
rap_db_free(rap->rrapdb);
+ if (rap->resptracker) {
+ free(rap->resptracker);
+ rap->resptracker = NULL;
+ }
+
queue_destroy(rap->notify, free);
queue_destroy(rap->pending, NULL);
queue_destroy(rap->ready_cbs, rap_ready_free);
@@ -240,6 +596,22 @@ bool bt_rap_set_debug(struct bt_rap *rap, bt_rap_debug_func_t func,
return true;
}
+static void cs_tracker_init(struct cstracker *t)
+{
+ if (!t)
+ return;
+
+ memset(t, 0, sizeof(*t));
+ t->role = CS_ROLE_REFLECTOR;
+ t->config_id = CS_INVALID_CONFIG_ID;
+ t->rtt_type = 0;
+ t->selected_tx_power = 0;
+ t->last_proc_counter = 0;
+ t->last_start_acl_conn_evt_counter = 0;
+ t->last_freq_comp = 0;
+ t->last_ref_pwr_lvl = 0;
+}
+
static void ras_features_read_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
uint8_t opcode, struct bt_att *att,
@@ -304,6 +676,70 @@ static void ras_data_overwritten_read_cb(struct gatt_db_attribute *attrib,
gatt_db_attribute_read_result(attrib, id, 0, value, sizeof(value));
}
+static void ras_ranging_data_ccc_write_cb(struct gatt_db_attribute *attrib,
+ unsigned int id, uint16_t offset,
+ const uint8_t *value, size_t len,
+ uint8_t opcode, struct bt_att *att,
+ void *user_data)
+{
+ struct ras *ras = user_data;
+ uint16_t ccc_value;
+ bool is_realtime;
+ uint16_t *this_ccc;
+ uint16_t *other_ccc;
+
+ if (!ras) {
+ gatt_db_attribute_write_result(attrib, id,
+ BT_ATT_ERROR_UNLIKELY);
+ return;
+ }
+
+ if (offset) {
+ gatt_db_attribute_write_result(attrib, id,
+ BT_ATT_ERROR_INVALID_OFFSET);
+ return;
+ }
+
+ if (len != 2) {
+ gatt_db_attribute_write_result(attrib, id,
+ BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN);
+ return;
+ }
+
+ ccc_value = get_le16(value);
+
+ if (ccc_value != 0x0000 && ccc_value != 0x0001 &&
+ ccc_value != 0x0002 && ccc_value != 0x0003) {
+ gatt_db_attribute_write_result(attrib, id,
+ BT_ERROR_WRITE_REQUEST_REJECTED);
+ return;
+ }
+
+ /* Determine which CCC this is */
+ is_realtime = (attrib == ras->realtime_chrc_ccc);
+ this_ccc = is_realtime ? &ras->realtime_ccc_value :
+ &ras->ondemand_ccc_value;
+ other_ccc = is_realtime ? &ras->ondemand_ccc_value :
+ &ras->realtime_ccc_value;
+
+ /* Check mutual exclusivity: reject if trying to enable realtime
+ * while ondemand is already enabled.
+ * Test case: RAS/SR/SPE/BI-11-C [Client enables both Real-time
+ * Ranging Data and On-demand Ranging Data notifications or
+ * indications]
+ */
+ if (ccc_value != 0x0000 && *other_ccc != 0x0000) {
+ gatt_db_attribute_write_result(attrib, id,
+ BT_ERROR_CCC_IMPROPERLY_CONFIGURED);
+ return;
+ }
+
+ /* Update state */
+ *this_ccc = ccc_value;
+
+ gatt_db_attribute_write_result(attrib, id, 0);
+}
+
/* Service registration – store attribute pointers */
static struct ras *register_ras_service(struct gatt_db *db)
{
@@ -349,9 +785,9 @@ static struct ras *register_ras_service(struct gatt_db *db)
NULL, NULL, ras);
ras->realtime_chrc_ccc =
- gatt_db_service_add_ccc(ras->svc,
- BT_ATT_PERM_READ |
- BT_ATT_PERM_WRITE);
+ gatt_db_service_add_ccc_custom(ras->svc,
+ BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ ras_ranging_data_ccc_write_cb, ras);
/* On-demand Ranging Data */
bt_uuid16_create(&uuid, RAS_ONDEMAND_DATA_UUID);
@@ -364,8 +800,9 @@ static struct ras *register_ras_service(struct gatt_db *db)
ras_ondemand_read_cb, NULL,
ras);
- gatt_db_service_add_ccc(ras->svc,
- BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
+ ras->ondemand_ccc = gatt_db_service_add_ccc_custom(ras->svc,
+ BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+ ras_ranging_data_ccc_write_cb, ras);
/* RAS Control Point */
bt_uuid16_create(&uuid, RAS_CONTROL_POINT_UUID);
@@ -379,8 +816,8 @@ static struct ras *register_ras_service(struct gatt_db *db)
ras_control_point_write_cb,
ras);
- gatt_db_service_add_ccc(ras->svc,
- BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
+ ras->cp_ccc = gatt_db_service_add_ccc(ras->svc,
+ BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
/* RAS Data Ready */
bt_uuid16_create(&uuid, RAS_DATA_READY_UUID);
@@ -394,8 +831,8 @@ static struct ras *register_ras_service(struct gatt_db *db)
ras_data_ready_read_cb, NULL,
ras);
- gatt_db_service_add_ccc(ras->svc,
- BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
+ ras->ready_ccc = gatt_db_service_add_ccc(ras->svc,
+ BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
/* RAS Data Overwritten */
bt_uuid16_create(&uuid, RAS_DATA_OVERWRITTEN_UUID);
@@ -409,8 +846,8 @@ static struct ras *register_ras_service(struct gatt_db *db)
ras_data_overwritten_read_cb,
NULL, ras);
- gatt_db_service_add_ccc(ras->svc,
- BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
+ ras->overwritten_ccc = gatt_db_service_add_ccc(ras->svc,
+ BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
/* Activate the service */
gatt_db_service_set_active(ras->svc, true);
@@ -503,32 +940,741 @@ bool bt_rap_unregister(unsigned int id)
return true;
}
+static inline size_t serialize_segmentation_header(
+ const struct segmentation_header *s,
+ uint8_t *out, size_t out_len)
+{
+ if (!s || !out || out_len < 1)
+ return 0;
+
+ out[0] = SEG_HDR_PACK(s->first_segment, s->last_segment,
+ s->rolling_segment_counter);
+
+ return 1;
+}
+
+static inline size_t serialize_ranging_header(const struct ranging_header *r,
+ uint8_t *out, size_t out_len)
+{
+ uint16_t rcid;
+
+ if (!r || !out || out_len < RAS_RANGING_HEADER_SIZE)
+ return 0;
+
+ /* Little-endian pack: [rc (12 bits) | cfg_id (4 bits)] */
+ rcid = RANGING_HDR_PACK_BYTE0_1(r->ranging_counter,
+ r->configuration_id);
+
+ put_le16(rcid, out + 0);
+ out[2] = r->selected_tx_power;
+ /* Byte 3: antenna_paths_mask | reserved | pct_format */
+ out[3] = RANGING_HDR_PACK_BYTE3(r->antenna_paths_mask,
+ r->pct_format);
+
+ return RAS_RANGING_HEADER_SIZE;
+}
+
+static inline uint16_t ras_att_value_payload_max(struct bt_rap *rap)
+{
+ struct bt_att *att = bt_rap_get_att(rap);
+ uint16_t mtu = att ? bt_att_get_mtu(att) : default_ras_mtu;
+
+ return (uint16_t)(mtu > ATT_OVERHEAD ?
+ (mtu - ATT_OVERHEAD - TOTAL_RAS_RANGING_HEADER_SIZE -
+ ras_segment_header_size) : 0);
+}
+
+/* Prepend data to an iovec - optimized to avoid unnecessary malloc/copy
+ * by using realloc and memmove instead of malloc/memcpy/free pattern.
+ * This reduces memory allocations and is more cache-friendly.
+ */
+static bool iov_prepend_bytes(struct iovec *iov, const uint8_t *bytes,
+ size_t len)
+{
+ size_t new_len;
+ void *new_base;
+
+ if (!iov || !bytes || len == 0)
+ return false;
+
+ new_len = iov->iov_len + len;
+
+ /* Use realloc to potentially expand in-place */
+ new_base = realloc(iov->iov_base, new_len);
+
+ if (!new_base)
+ return false;
+
+ /* Move existing data forward to make room at the beginning */
+ if (iov->iov_len > 0)
+ memmove((uint8_t *)new_base + len, new_base, iov->iov_len);
+
+ /* Copy new data to the beginning */
+ memcpy(new_base, bytes, len);
+
+ iov->iov_base = new_base;
+ iov->iov_len = new_len;
+
+ return true;
+}
+
+/* Append the 4-byte RangingHeader to ras_raw_data_ on first segment */
+static bool ras_maybe_prepend_ranging_header(struct cs_procedure_data *d)
+{
+ uint8_t hdr[RAS_RANGING_HEADER_SIZE];
+ size_t w;
+ bool ok;
+
+ if (!d)
+ return false;
+
+ if (d->ranging_header_prepended_)
+ return false;
+
+ if (!d->segmentation_header_.first_segment)
+ return false;
+
+ if (d->ras_raw_data_index_ != 0)
+ return false;
+
+ w = serialize_ranging_header(&d->ranging_header_, hdr, sizeof(hdr));
+
+ if (w != RAS_RANGING_HEADER_SIZE)
+ return false;
+
+ ok = iov_prepend_bytes(&d->ras_raw_data_, hdr, w);
+
+ if (ok)
+ d->ranging_header_prepended_ = true;
+
+ return ok;
+}
+
+static void send_ras_segment_data(struct bt_rap *rap,
+ struct cs_procedure_data *proc)
+{
+ struct ras *ras;
+ uint16_t value_max;
+ const uint16_t header_len = ras_segment_header_size;
+ uint16_t raw_payload_size;
+ bool ok;
+
+ if (!rap || !proc)
+ return;
+
+ if (!rap->lrapdb || !rap->lrapdb->ras)
+ return;
+
+ ras = rap->lrapdb->ras;
+ value_max = ras_att_value_payload_max(rap);
+
+ if (value_max == 0) {
+ DBG(rap, "value_max=0 (MTU not available?)");
+ return;
+ }
+
+ if (value_max <= header_len) {
+ DBG(rap, "value_max(%u) too small for header", value_max);
+ return;
+ }
+
+ raw_payload_size = (uint16_t)(value_max - header_len);
+
+ /* Convert tail recursion to loop */
+ while (true) {
+ size_t total_len = proc->ras_raw_data_.iov_len;
+ size_t index = proc->ras_raw_data_index_;
+ size_t unsent_data_size;
+ uint16_t copy_size;
+ uint16_t seg_len;
+ uint8_t *seg;
+ uint16_t wr = 0;
+
+ if (index > total_len)
+ index = total_len;
+
+ unsent_data_size = total_len - index;
+
+ if (unsent_data_size == 0)
+ return;
+
+ /* Set last_segment if procedure complete or fits in segment */
+ if ((proc->local_status != CS_PROC_PARTIAL_RESULTS &&
+ unsent_data_size <= raw_payload_size) ||
+ (proc->contains_complete_subevent_ &&
+ unsent_data_size <= raw_payload_size)) {
+ proc->segmentation_header_.last_segment = 1;
+ } else {
+ proc->segmentation_header_.last_segment = 0;
+ }
+
+ /* Wait for more data if needed and not last segment */
+ if (unsent_data_size < raw_payload_size &&
+ proc->segmentation_header_.last_segment == 0) {
+ DBG(rap, "waiting for more data (unsent=%zu < "
+ "payload=%u)", unsent_data_size,
+ raw_payload_size);
+ return;
+ }
+
+ copy_size = (uint16_t)((unsent_data_size < raw_payload_size) ?
+ unsent_data_size : raw_payload_size);
+ seg_len = (uint16_t)(header_len + copy_size);
+ seg = (uint8_t *)malloc(seg_len);
+
+ if (!seg) {
+ DBG(rap, "OOM (%u)", seg_len);
+ return;
+ }
+
+ wr += (uint16_t)serialize_segmentation_header(
+ &proc->segmentation_header_, seg + wr,
+ seg_len - wr);
+ memcpy(seg + wr,
+ (const uint8_t *)proc->ras_raw_data_.iov_base + index,
+ copy_size);
+ wr += copy_size;
+
+ /* Try sending to real-time characteristic */
+ if (ras->realtime_chrc)
+ ok = gatt_db_attribute_notify(ras->realtime_chrc, seg,
+ wr, bt_rap_get_att(rap));
+
+ /* Try sending to on-demand characteristic */
+ if (ras->ondemand_chrc)
+ ok = gatt_db_attribute_notify(ras->ondemand_chrc, seg,
+ wr, bt_rap_get_att(rap));
+
+ free(seg);
+
+ if (!ok) {
+ DBG(rap, "Failed to send RAS notification");
+ return;
+ }
+
+ /* Advance read cursor and update segmentation state */
+ proc->ras_raw_data_index_ += copy_size;
+ proc->segmentation_header_.first_segment = 0;
+ proc->segmentation_header_.rolling_segment_counter =
+ (uint8_t)((proc->segmentation_header_
+ .rolling_segment_counter + 1) & 0x3F);
+
+ if (proc->segmentation_header_.last_segment ||
+ proc->ras_raw_data_index_ >=
+ proc->ras_raw_data_.iov_len) {
+ DBG(rap, "RAS clear ras buffers");
+ proc->ras_raw_data_.iov_len = 0;
+ proc->ras_raw_data_index_ = 0;
+ proc->ranging_header_prepended_ = false;
+ return;
+ }
+ }
+}
+
+static inline void resptracker_reset_current_proc(struct cstracker *t)
+{
+ if (!t)
+ return;
+
+ if (t->current_proc) {
+ cs_procedure_data_destroy(t->current_proc);
+ t->current_proc = NULL;
+ }
+}
+
+static void process_cs_mode_zero(struct bt_rap *rap,
+ struct cs_procedure_data *proc,
+ const struct cs_step_data *step,
+ uint8_t idx, uint8_t mode_byte)
+{
+ const uint8_t *payload;
+ uint8_t plen;
+
+ /* Mode 0: use raw structure bytes */
+ payload = (const uint8_t *)&step->step_mode_data;
+ plen = step->step_data_length;
+ cs_pd_ras_append_subevent_bytes(proc, payload, plen);
+ DBG(rap, "step[%u]: mode=0x%02x Mode0 payload_len=%u sent",
+ idx, mode_byte, (unsigned int)plen);
+}
+
+static void process_cs_mode_one(struct bt_rap *rap,
+ struct cs_procedure_data *proc,
+ const struct cs_step_data *step,
+ uint8_t idx, uint8_t mode_byte)
+{
+ const struct cs_mode_one_data *m1 =
+ &step->step_mode_data.mode_one_data;
+ struct cstracker *resptracker = rap->resptracker;
+ uint8_t buf[16]; /* Max Mode 1 size */
+ uint8_t *p = buf;
+ uint16_t time_val;
+ uint32_t pct1;
+ uint32_t pct2;
+ enum cs_role cs_role = resptracker->role;
+ uint8_t cs_rtt_type = resptracker->rtt_type;
+ uint8_t plen;
+
+ *p++ = m1->packet_quality;
+ *p++ = m1->packet_nadm;
+ *p++ = m1->packet_rssi_dbm;
+
+ /* Time value (2 bytes LE) - use the appropriate field based on role */
+ if (cs_role == CS_ROLE_REFLECTOR)
+ time_val = m1->tod_toa_refl;
+ else
+ time_val = m1->toa_tod_init;
+
+ *p++ = (uint8_t)(time_val & 0xFF);
+ *p++ = (uint8_t)((time_val >> 8) & 0xFF);
+
+ *p++ = m1->packet_ant;
+
+ /* PCT samples if RTT type contains sounding sequence */
+ if (cs_rtt_type == 0x01 || cs_rtt_type == 0x02) {
+ pct1 = ((uint32_t)(m1->packet_pct1.i_sample & 0x0FFF)) |
+ (((uint32_t)(m1->packet_pct1.q_sample & 0x0FFF)) << 12);
+ *p++ = (uint8_t)(pct1 & 0xFF);
+ *p++ = (uint8_t)((pct1 >> 8) & 0xFF);
+ *p++ = (uint8_t)((pct1 >> 16) & 0xFF);
+
+ /* PCT2 (3 bytes) */
+ pct2 = ((uint32_t)(m1->packet_pct2.i_sample & 0x0FFF)) |
+ (((uint32_t)(m1->packet_pct2.q_sample & 0x0FFF)) << 12);
+ *p++ = (uint8_t)(pct2 & 0xFF);
+ *p++ = (uint8_t)((pct2 >> 8) & 0xFF);
+ *p++ = (uint8_t)((pct2 >> 16) & 0xFF);
+ }
+
+ plen = (uint8_t)(p - buf);
+ cs_pd_ras_append_subevent_bytes(proc, buf, plen);
+ DBG(rap, "step[%u]: mode=0x%02x Mode1 serialized payload_len=%u "
+ "role=%s rtt_type=0x%02x",
+ idx, mode_byte, (unsigned int)plen,
+ cs_role == CS_ROLE_INITIATOR ? "INIT" : "REFL", cs_rtt_type);
+}
+
+static void process_cs_mode_two(struct bt_rap *rap,
+ struct cs_procedure_data *proc,
+ const struct cs_step_data *step,
+ uint8_t num_ant_paths,
+ uint8_t idx, uint8_t mode_byte)
+{
+ const struct cs_mode_two_data *m2 =
+ &step->step_mode_data.mode_two_data;
+ /* Max Mode 2 size: 1 + 5*(3+1) = 21 bytes */
+ uint8_t buf[64];
+ uint8_t *p = buf;
+ uint8_t k;
+ uint8_t num_paths = (num_ant_paths + 1) < 5 ?
+ (num_ant_paths + 1) : 5;
+ uint8_t plen;
+
+ *p++ = m2->ant_perm_index;
+
+ /* Serialize each path: PCT (3 bytes) + quality (1 byte) */
+ for (k = 0; k < num_paths; k++) {
+ /* Convert 4-byte structure PCT to 3-byte wire format */
+ uint32_t pct = ((uint32_t)(m2->tone_pct[k].i_sample &
+ 0x0FFF)) |
+ (((uint32_t)(m2->tone_pct[k].q_sample &
+ 0x0FFF)) << 12);
+ *p++ = (uint8_t)(pct & 0xFF);
+ *p++ = (uint8_t)((pct >> 8) & 0xFF);
+ *p++ = (uint8_t)((pct >> 16) & 0xFF);
+
+ *p++ = m2->tone_quality_indicator[k];
+ }
+
+ plen = (uint8_t)(p - buf);
+ cs_pd_ras_append_subevent_bytes(proc, buf, plen);
+ DBG(rap, "step[%u]: mode=0x%02x Mode2 serialized payload_len=%u "
+ "paths=%u",
+ idx, mode_byte, (unsigned int)plen, num_paths);
+}
+
+static void process_cs_mode_three(struct bt_rap *rap,
+ struct cs_procedure_data *proc,
+ const struct cs_step_data *step,
+ uint8_t num_ant_paths,
+ uint8_t idx, uint8_t mode_byte)
+{
+ const struct cs_mode_three_data *m3 =
+ &step->step_mode_data.mode_three_data;
+ const struct cs_mode_one_data *m1 = &m3->mode_one_data;
+ const struct cs_mode_two_data *m2 = &m3->mode_two_data;
+ struct cstracker *resptracker = rap->resptracker;
+ uint8_t buf[80]; /* Max Mode 3 size */
+ uint8_t *p = buf;
+ uint8_t k;
+ uint8_t num_paths = (num_ant_paths + 1) < 5 ?
+ (num_ant_paths + 1) : 5;
+ uint8_t cs_rtt_type = resptracker->rtt_type;
+ enum cs_role cs_role = resptracker->role;
+ uint16_t time_val;
+ bool include_pct;
+ uint8_t plen;
+
+ /* Determine if PCT samples should be included */
+ include_pct = (cs_rtt_type == 0x01 || cs_rtt_type == 0x02) &&
+ (cs_role == CS_ROLE_INITIATOR || cs_role == CS_ROLE_REFLECTOR);
+
+ /* Mode 1 portion - basic fields */
+ *p++ = m1->packet_quality;
+ *p++ = m1->packet_nadm;
+ *p++ = m1->packet_rssi_dbm;
+
+ /* Time value based on role */
+ if (cs_role == CS_ROLE_REFLECTOR)
+ time_val = m1->tod_toa_refl;
+ else
+ time_val = m1->toa_tod_init;
+
+ *p++ = (uint8_t)(time_val & 0xFF);
+ *p++ = (uint8_t)((time_val >> 8) & 0xFF);
+
+ *p++ = m1->packet_ant;
+
+ /* PCT samples if conditions met */
+ if (include_pct) {
+ uint32_t pct1;
+ uint32_t pct2;
+
+ pct1 = ((uint32_t)(m1->packet_pct1.i_sample & 0x0FFF)) |
+ (((uint32_t)(m1->packet_pct1.q_sample & 0x0FFF)) << 12);
+ *p++ = (uint8_t)(pct1 & 0xFF);
+ *p++ = (uint8_t)((pct1 >> 8) & 0xFF);
+ *p++ = (uint8_t)((pct1 >> 16) & 0xFF);
+
+ pct2 = ((uint32_t)(m1->packet_pct2.i_sample & 0x0FFF)) |
+ (((uint32_t)(m1->packet_pct2.q_sample & 0x0FFF)) << 12);
+ *p++ = (uint8_t)(pct2 & 0xFF);
+ *p++ = (uint8_t)((pct2 >> 8) & 0xFF);
+ *p++ = (uint8_t)((pct2 >> 16) & 0xFF);
+ }
+
+ /* Mode 2 portion */
+ *p++ = m2->ant_perm_index;
+
+ for (k = 0; k < num_paths; k++) {
+ uint32_t pct = ((uint32_t)(m2->tone_pct[k].i_sample &
+ 0x0FFF)) |
+ (((uint32_t)(m2->tone_pct[k].q_sample &
+ 0x0FFF)) << 12);
+ *p++ = (uint8_t)(pct & 0xFF);
+ *p++ = (uint8_t)((pct >> 8) & 0xFF);
+ *p++ = (uint8_t)((pct >> 16) & 0xFF);
+
+ *p++ = m2->tone_quality_indicator[k];
+ }
+
+ plen = (uint8_t)(p - buf);
+ cs_pd_ras_append_subevent_bytes(proc, buf, plen);
+ DBG(rap, "step[%u]: mode=0x%02x Mode3 serialized payload_len=%u "
+ "paths=%u role=%s rtt_type=0x%02x pct=%s",
+ idx, mode_byte, (unsigned int)plen, num_paths,
+ cs_role == CS_ROLE_INITIATOR ? "INIT" : "REFL",
+ cs_rtt_type, include_pct ? "YES" : "NO");
+}
+
+static void process_cs_mode_step(struct bt_rap *rap,
+ struct cs_procedure_data *proc,
+ const struct cs_step_data *step,
+ uint8_t num_ant_paths,
+ uint8_t idx)
+{
+ const uint8_t mode = step->step_mode;
+ const uint8_t payload_len = step->step_data_length;
+ uint8_t mode_byte;
+ uint8_t mode_type;
+ const uint8_t *payload;
+ uint8_t plen;
+ bool step_aborted;
+
+ /* Check if step is aborted: bit 7 of step_mode or 0 payload len */
+ step_aborted = (mode & RAS_STEP_ABORTED_BIT) || (payload_len == 0);
+
+ DBG(rap, "step[%u]: mode=0x%02x channel=%u payload_len=%u "
+ "aborted=%s", idx, mode, step->step_chnl, payload_len,
+ step_aborted ? "YES" : "NO");
+
+ mode_byte = step->step_mode;
+
+ if (step_aborted) {
+ /* Ensure abort bit is set */
+ mode_byte |= RAS_STEP_ABORTED_BIT;
+ cs_pd_ras_append_subevent_bytes(proc, &mode_byte, 1);
+ /* No payload when aborted - per RAS spec Table 3.8 */
+ DBG(rap, "step[%u]: mode=0x%02x aborted, no payload sent",
+ idx, mode_byte);
+ return;
+ }
+
+ mode_type = mode & 0x03;
+
+ /* Mode byte first (without abort bit) */
+ cs_pd_ras_append_subevent_bytes(proc, &mode_byte, 1);
+
+ switch (mode_type) {
+ case CS_MODE_ZERO:
+ process_cs_mode_zero(rap, proc, step, idx, mode_byte);
+ break;
+ case CS_MODE_ONE:
+ process_cs_mode_one(rap, proc, step, idx, mode_byte);
+ break;
+ case CS_MODE_TWO:
+ process_cs_mode_two(rap, proc, step, num_ant_paths, idx,
+ mode_byte);
+ break;
+ case CS_MODE_THREE:
+ process_cs_mode_three(rap, proc, step, num_ant_paths, idx,
+ mode_byte);
+ break;
+ default:
+ /* Unknown mode: use raw structure bytes */
+ payload = (const uint8_t *)&step->step_mode_data;
+ plen = step->step_data_length;
+ cs_pd_ras_append_subevent_bytes(proc, payload, plen);
+ DBG(rap, "step[%u]: mode=0x%02x unknown mode, "
+ "payload_len=%u sent",
+ idx, mode_byte, (unsigned int)plen);
+ break;
+ }
+}
+
+/* Unified local subevent handler */
+static void handle_local_subevent_result(struct bt_rap *rap,
+ bool has_header_fields,
+ uint8_t config_id,
+ uint8_t num_ant_paths,
+ uint16_t proc_counter,
+ uint16_t start_acl_conn_evt_counter,
+ uint16_t freq_comp,
+ int8_t ref_pwr_lvl,
+ uint8_t proc_done_status,
+ uint8_t subevt_done_status,
+ uint8_t abort_reason,
+ uint8_t num_steps_reported,
+ const void *step_bytes)
+{
+ struct cstracker *resptracker;
+ struct cs_procedure_data *proc;
+ const struct cs_step_data *steps;
+ uint8_t idx;
+
+ if (!rap || !rap->resptracker || !step_bytes)
+ return;
+
+ resptracker = rap->resptracker;
+
+ if (resptracker->current_proc) {
+ struct cs_procedure_data *cur = resptracker->current_proc;
+
+ if (has_header_fields && cur->counter != proc_counter) {
+ /* Safety: a new procedure; destroy the previous one */
+ resptracker_reset_current_proc(resptracker);
+ }
+ }
+
+ proc = resptracker->current_proc;
+ /* Cache header info from a RESULT event for later CONT usage */
+ if (has_header_fields) {
+ resptracker->last_proc_counter = proc_counter;
+ resptracker->last_start_acl_conn_evt_counter =
+ start_acl_conn_evt_counter;
+ resptracker->last_freq_comp = freq_comp;
+ resptracker->last_ref_pwr_lvl = ref_pwr_lvl;
+ }
+
+ /* Create the procedure on first use */
+ if (!proc) {
+ uint16_t create_counter = has_header_fields ? proc_counter :
+ resptracker->last_proc_counter;
+
+ proc = cs_procedure_data_create(create_counter,
+ num_ant_paths,
+ config_id,
+ resptracker->selected_tx_power);
+ if (!proc)
+ return;
+
+ resptracker->current_proc = proc;
+
+ /* Reference power levels and status defaults */
+ cs_pd_set_reference_power_levels(proc,
+ has_header_fields ? ref_pwr_lvl :
+ resptracker->last_ref_pwr_lvl,
+ has_header_fields ? ref_pwr_lvl :
+ resptracker->last_ref_pwr_lvl);
+ cs_pd_set_local_status(proc,
+ (enum cs_procedure_done_status)proc_done_status);
+ cs_pd_set_remote_status(proc,
+ (enum cs_procedure_done_status)subevt_done_status);
+ }
+
+ /* Begin a new RAS subevent only when we have header fields */
+ if (has_header_fields) {
+ cs_pd_ras_begin_subevent(proc,
+ start_acl_conn_evt_counter,
+ freq_comp,
+ ref_pwr_lvl);
+ }
+
+ /* step_bytes points to an array of struct cs_step_data */
+ steps = (const struct cs_step_data *)step_bytes;
+
+ /* Process each step using helper function */
+ for (idx = 0; idx < num_steps_reported; idx++)
+ process_cs_mode_step(rap, proc, &steps[idx], num_ant_paths,
+ idx);
+
+ /* Update status for this chunk */
+ cs_pd_set_local_status(proc,
+ (enum cs_procedure_done_status)proc_done_status);
+ cs_pd_set_remote_status(proc,
+ (enum cs_procedure_done_status)subevt_done_status);
+
+ /* Commit subevent chunk (RESULT or CONT) */
+ cs_pd_ras_commit_subevent(proc,
+ num_steps_reported,
+ proc_done_status,
+ subevt_done_status,
+ abort_reason & 0x0F,
+ (abort_reason >> 4) & 0x0F);
+
+ /* Ensure first segment body starts with the 4-byte RangingHeader */
+ ras_maybe_prepend_ranging_header(proc);
+
+ if (subevt_done_status != SUBEVENT_DONE_PARTIAL_RESULTS)
+ /* Send RAS raw segment data */
+ send_ras_segment_data(rap, proc);
+
+ /* Procedure complete? Clean up */
+ if (proc_done_status == CS_PROC_ALL_RESULTS_COMPLETE) {
+ DBG(rap, "Destroying CsProcedureData counter=%u and "
+ "clearing current_proc", proc->counter);
+ resptracker_reset_current_proc(resptracker);
+ /* Reset cached header values for next procedure */
+ resptracker->last_proc_counter = 0;
+ resptracker->last_start_acl_conn_evt_counter = 0;
+ resptracker->last_freq_comp = 0;
+ resptracker->last_ref_pwr_lvl = 0;
+ }
+}
+
+static void form_ras_data_with_cs_subevent_result(struct bt_rap *rap,
+ const struct rap_ev_cs_subevent_result *data,
+ uint16_t length)
+{
+ size_t base_len = offsetof(struct rap_ev_cs_subevent_result,
+ step_data);
+
+ if (!rap || !rap->resptracker || !data)
+ return;
+
+ /* Defensive check: base header must be present */
+ if (length < base_len)
+ return;
+
+ DBG(rap, "Received CS subevent result subevent: len=%d", length);
+
+ handle_local_subevent_result(rap,
+ true, /* has header fields */
+ data->config_id,
+ data->num_ant_paths,
+ data->proc_counter,
+ data->start_acl_conn_evt_counter,
+ data->freq_comp,
+ data->ref_pwr_lvl,
+ data->proc_done_status,
+ data->subevt_done_status,
+ data->abort_reason,
+ data->num_steps_reported,
+ data->step_data); /* start of steps */
+}
+
+static void form_ras_data_with_cs_subevent_result_cont(struct bt_rap *rap,
+ const struct rap_ev_cs_subevent_result_cont *cont,
+ uint16_t length)
+{
+ size_t base_len = offsetof(struct rap_ev_cs_subevent_result_cont,
+ step_data);
+ struct cstracker *resptracker;
+
+ if (!rap || !rap->resptracker || !cont)
+ return;
+
+ if (length < base_len)
+ return;
+
+ DBG(rap, "Received CS subevent result continue subevent: len=%d",
+ length);
+
+ resptracker = rap->resptracker;
+
+ /* Use cached header values captured from the last RESULT event */
+ handle_local_subevent_result(rap,
+ false, /* CONT has no header fields */
+ cont->config_id,
+ cont->num_ant_paths,
+ resptracker->last_proc_counter,
+ resptracker->last_start_acl_conn_evt_counter,
+ resptracker->last_freq_comp,
+ resptracker->last_ref_pwr_lvl,
+ cont->proc_done_status,
+ cont->subevt_done_status,
+ cont->abort_reason,
+ cont->num_steps_reported,
+ cont->step_data);
+}
+
void bt_rap_hci_cs_subevent_result_cont_callback(uint16_t length,
const void *param,
void *user_data)
{
+ const struct rap_ev_cs_subevent_result_cont *cont = param;
struct bt_rap *rap = user_data;
DBG(rap, "Received CS subevent CONT: len=%d", length);
+
+ form_ras_data_with_cs_subevent_result_cont(rap, cont, length);
}
void bt_rap_hci_cs_subevent_result_callback(uint16_t length,
const void *param,
void *user_data)
{
+ const struct rap_ev_cs_subevent_result *data = param;
struct bt_rap *rap = user_data;
DBG(rap, "Received CS subevent: len=%d", length);
+
+ /* Populate CsProcedureData and send RAS payload */
+ form_ras_data_with_cs_subevent_result(rap, data, length);
}
void bt_rap_hci_cs_procedure_enable_complete_callback(uint16_t length,
const void *param,
void *user_data)
{
+ const struct rap_ev_cs_proc_enable_cmplt *data = param;
struct bt_rap *rap = user_data;
+ struct cstracker *resptracker;
DBG(rap, "Received CS procedure enable complete subevent: len=%d",
length);
+
+ if (!rap->resptracker) {
+ resptracker = new0(struct cstracker, 1);
+ cs_tracker_init(resptracker);
+ rap->resptracker = resptracker;
+ }
+
+ resptracker = rap->resptracker;
+
+ /* Populate responder tracker */
+ resptracker->config_id = data->config_id;
+ resptracker->selected_tx_power = data->sel_tx_pwr;
}
void bt_rap_hci_cs_sec_enable_complete_callback(uint16_t length,
@@ -544,9 +1690,27 @@ void bt_rap_hci_cs_config_complete_callback(uint16_t length,
const void *param,
void *user_data)
{
+ const struct rap_ev_cs_config_cmplt *data = param;
struct bt_rap *rap = user_data;
+ struct cstracker *resptracker;
+
+ if (!rap)
+ return;
DBG(rap, "Received CS config complete subevent: len=%d", length);
+
+ if (!rap->resptracker) {
+ resptracker = new0(struct cstracker, 1);
+ cs_tracker_init(resptracker);
+ rap->resptracker = resptracker;
+ }
+
+ resptracker = rap->resptracker;
+
+ /* Basic fields */
+ resptracker->config_id = data->config_id;
+ resptracker->role = data->role;
+ resptracker->rtt_type = data->rtt_type;
}
struct bt_rap *bt_rap_new(struct gatt_db *ldb, struct gatt_db *rdb)
@@ -786,7 +1950,7 @@ bool bt_rap_attach(struct bt_rap *rap, struct bt_gatt_client *client)
bt_uuid16_create(&uuid, RAS_UUID16);
- gatt_db_foreach_service(rap->lrapdb->db, &uuid,
+ gatt_db_foreach_service(rap->rrapdb->db, &uuid,
foreach_rap_service, rap);
return true;
diff --git a/src/shared/rap.h b/src/shared/rap.h
index 15ddea295..c9431aecd 100644
--- a/src/shared/rap.h
+++ b/src/shared/rap.h
@@ -97,11 +97,11 @@ struct cs_mode_zero_data {
struct cs_mode_one_data {
uint8_t packet_quality;
- uint8_t packet_rssi_dbm;
- uint8_t packet_ant;
uint8_t packet_nadm;
+ uint8_t packet_rssi_dbm;
int16_t toa_tod_init;
int16_t tod_toa_refl;
+ uint8_t packet_ant;
struct pct_iq_sample packet_pct1;
struct pct_iq_sample packet_pct2;
};
--
2.34.1
^ permalink raw reply related
* [PATCH BlueZ v6 2/3] unit/test-rap: Add PTS tests for CS reflector
From: Prathibha Madugonde @ 2026-04-29 15:29 UTC (permalink / raw)
To: linux-bluetooth; +Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg
In-Reply-To: <20260429152942.2940978-1-prathm@qti.qualcomm.com>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=UTF-8, Size: 13925 bytes --]
From: Prathibha Madugonde <prathibha.madugonde@oss.qualcomm.com>
Added below RAS - Real time Ranging PTS testcases:
RAS/SR/RCO/BV-01-C [Characteristic Read - RAS Features]
RAS/SR/RRD/BV-01-C [Real-time Ranging Data]
RAS/SR/RRD/BV-03-C [Real-time Ranging Data notifications and indications]
RAS/SR/RRD/BV-05-C [Real-Time Ranging Data disconnection]
RAS/SR/SPE/BI-11-C [Client enables both Real-time and On-demand]
---
unit/test-rap.c | 327 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 323 insertions(+), 4 deletions(-)
diff --git a/unit/test-rap.c b/unit/test-rap.c
index 884cb1c96..af4554c0e 100644
--- a/unit/test-rap.c
+++ b/unit/test-rap.c
@@ -37,6 +37,7 @@ struct test_data_ras {
size_t iovcnt;
struct iovec *iov;
unsigned int ras_id;
+ struct bt_rap *rap; /* Store rap instance for CS injection */
};
struct test_data_rap {
@@ -68,8 +69,8 @@ struct notify {
do { \
const struct iovec iov[] = { args }; \
static struct test_data_ras data; \
- data.iovcnt = ARRAY_SIZE(iov_data(args)); \
- data.iov = util_iov_dup(iov, ARRAY_SIZE(iov_data(args))); \
+ data.iovcnt = ARRAY_SIZE(iov); \
+ data.iov = util_iov_dup(iov, ARRAY_SIZE(iov)); \
tester_add(name, &data, NULL, function, \
test_teardown_ras); \
} while (0)
@@ -155,6 +156,94 @@ static void gatt_notify_cb(struct gatt_db_attribute *attrib,
printf("%s: Failed to send notification\n", __func__);
}
+static void gatt_ccc_write_cb(struct gatt_db_attribute *attrib,
+ unsigned int id, uint16_t offset,
+ const uint8_t *value, size_t len,
+ uint8_t opcode, struct bt_att *att,
+ void *user_data)
+{
+ struct test_data_ras *data = user_data;
+ struct ccc_state *ccc;
+ uint16_t handle;
+ uint16_t ccc_value;
+ uint8_t ecode = 0;
+
+ handle = gatt_db_attribute_get_handle(attrib);
+
+ if (offset) {
+ ecode = BT_ATT_ERROR_INVALID_OFFSET;
+ goto done;
+ }
+
+ if (len != 2) {
+ ecode = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
+ goto done;
+ }
+
+ ccc_value = get_le16(value);
+
+ ccc = get_ccc_state(data, handle);
+ if (!ccc) {
+ ecode = BT_ATT_ERROR_UNLIKELY;
+ goto done;
+ }
+
+ ccc->value = ccc_value;
+
+ /* Send write response first */
+ gatt_db_attribute_write_result(attrib, id, 0);
+
+ /* If notifications/indications enabled on Real-time Ranging Data CCCD,
+ * inject fake HCI CS subevent data to trigger notifications
+ */
+ if (handle == 0x0006 && ccc_value != 0x0000 && data->rap) {
+ size_t event_size = sizeof(struct rap_ev_cs_subevent_result) +
+ sizeof(struct cs_step_data);
+ struct rap_ev_cs_subevent_result *fake_event;
+ struct cs_mode_zero_data *mode_zero;
+
+ if (tester_use_debug())
+ tester_debug("Injecting fake CS data...");
+
+ fake_event = g_malloc0(event_size);
+ if (!fake_event)
+ return; /* Already sent write response */
+
+ /* Fill in the header fields */
+ fake_event->conn_hdl = 0x0001;
+ fake_event->config_id = 0x01;
+ fake_event->start_acl_conn_evt_counter = 0x0000;
+ fake_event->proc_counter = 0x0001;
+ fake_event->freq_comp = 0x0000;
+ fake_event->ref_pwr_lvl = 0x00;
+ fake_event->proc_done_status = 0x00;
+ fake_event->subevt_done_status = 0x00;
+ fake_event->abort_reason = 0x00;
+ fake_event->num_ant_paths = 0x01;
+ fake_event->num_steps_reported = 0x01;
+
+ fake_event->step_data[0].step_mode = CS_MODE_ZERO;
+ fake_event->step_data[0].step_chnl = 0x00;
+ /* Mode 0: 1+1+1+4 bytes */
+ fake_event->step_data[0].step_data_length = 4;
+mode_zero = &fake_event->step_data[0].step_mode_data.mode_zero_data;
+ mode_zero->packet_quality = 0x01;
+ mode_zero->packet_rssi_dbm = 0x02;
+ mode_zero->packet_ant = 0x03;
+ mode_zero->init_measured_freq_offset = 0x04;
+
+ /* Inject the fake event to trigger notification */
+ bt_rap_hci_cs_subevent_result_callback(event_size, fake_event,
+ data->rap);
+
+ g_free(fake_event);
+ }
+ return;
+
+done:
+ gatt_db_attribute_write_result(attrib, id, ecode);
+}
+
static void gatt_ccc_read_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
uint8_t opcode, struct bt_att *att,
@@ -184,10 +273,21 @@ done:
static void ras_attached(struct bt_rap *rap, void *user_data)
{
+ struct test_data_ras *data = user_data;
+
+ if (data) {
+ data->rap = rap;
+ bt_rap_ref(rap); /* Keep a reference */
+ }
}
static void ras_detached(struct bt_rap *rap, void *user_data)
{
+ struct test_data_ras *data = user_data;
+
+ if (data && data->rap == rap)
+ data->rap = NULL;
+
bt_rap_unref(rap);
}
@@ -205,17 +305,18 @@ static void test_server(const void *user_data)
att = bt_att_new(io_get_fd(io), false);
g_assert(att);
+ bt_att_set_security(att, BT_ATT_SECURITY_MEDIUM);
bt_att_set_debug(att, BT_ATT_DEBUG, print_debug, "bt_att:", NULL);
data->db = gatt_db_new();
g_assert(data->db);
- gatt_db_ccc_register(data->db, gatt_ccc_read_cb, NULL,
+ gatt_db_ccc_register(data->db, gatt_ccc_read_cb, gatt_ccc_write_cb,
gatt_notify_cb, data);
bt_rap_add_db(data->db);
- data->ras_id = bt_rap_register(ras_attached, ras_detached, NULL);
+ data->ras_id = bt_rap_register(ras_attached, ras_detached, data);
data->server = bt_gatt_server_new(data->db, att, 64, 0);
g_assert(data->server);
@@ -426,6 +527,210 @@ static void test_server(const void *user_data)
DISC_RAS_CHAR_AFTER_TYPE, \
RAS_FIND_INFO
+/*
+ * RAS/SR/RCO/BV-01-C Characteristic Read: RAS Features
+ *
+ * ATT: Read Request (0x0a) len 2
+ * Handle: 0x0003 (RAS Features value handle)
+ *
+ * ATT: Read Response (0x0b) len 5
+ * Value: 0x01 0x00 0x00 0x00
+ * Feature bits:
+ * Bit 0: Real-time ranging (1 = supported)
+ * Bit 1: Retrieve stored results (0 = not supported)
+ * Bit 2: Abort operation (0 = not supported)
+ *
+ * Note: The RAS Features characteristic is registered with
+ * BT_ATT_PERM_READ | BT_ATT_PERM_READ_ENCRYPT. Since the test sets
+ * BT_ATT_SECURITY_MEDIUM, the encryption requirement is satisfied
+ * and the server returns the feature value showing real-time ranging
+ * support.
+ */
+
+#define ATT_READ_RAS_FEATURES \
+ IOV_DATA(0x0a, 0x03, 0x00), \
+ IOV_DATA(0x0b, 0x01, 0x00, 0x00, 0x00)
+
+#define RAS_SR_RCO_BV_01_C \
+ ATT_EXCHANGE_MTU, \
+ DISCOVER_PRIM_SERV_NOTIF, \
+ RAS_FIND_BY_TYPE_VALUE, \
+ DISC_RAS_CHAR_AFTER_TYPE, \
+ RAS_FIND_INFO, \
+ ATT_READ_RAS_FEATURES
+
+/*
+ * RAS Real-time Ranging Data CCCD Configuration
+ * Round 1: Enable/Disable notifications (CCCD = 0x0001)
+ * Round 2: Enable/Disable indications (CCCD = 0x0002)
+ */
+#define RAS_REALTIME_CCCD_CONFIG \
+ /* Round 1: Enable notifications on Real-time Ranging Data CCCD */ \
+ /* (handle 0x0006) */ \
+ IOV_DATA(0x12, 0x06, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x13), \
+ /* Disable notifications */ \
+ IOV_DATA(0x12, 0x06, 0x00, 0x00, 0x00), \
+ IOV_DATA(0x13), \
+ /* Round 2: Enable indications on Real-time Ranging Data CCCD */ \
+ IOV_DATA(0x12, 0x06, 0x00, 0x02, 0x00), \
+ IOV_DATA(0x13), \
+ /* Disable indications */ \
+ IOV_DATA(0x12, 0x06, 0x00, 0x00, 0x00), \
+ IOV_DATA(0x13)
+
+/*
+ * Enable both notifications and indications (CCCD = 0x0003)
+ * Expect notification (0x1b) to be sent, not indication (0x1d)
+ * Then disable CCCD
+ *
+ * Note: This test is currently disabled because the GATT server rejects
+ * CCCD value 0x0003 (both notifications and indications enabled) before
+ * reaching the custom callback. The test infrastructure needs to be updated
+ * to support this scenario.
+ */
+#define RAS_REALTIME_CCCD_BOTH_ENABLE_DISABLE \
+ /* Enable notifications only (CCCD = 0x0001) */ \
+ IOV_DATA(0x12, 0x06, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x13), \
+ /* Disable CCCD */ \
+ IOV_DATA(0x12, 0x06, 0x00, 0x00, 0x00), \
+ IOV_DATA(0x13)
+
+/*
+ * Disconnection/Reconnection simulation for Real-time Ranging Data
+ * Enable notifications, disable (disconnect), re-enable (reconnect), disable
+ */
+#define RAS_REALTIME_CCCD_DISCONNECT_RECONNECT \
+ /* Step 1: Enable notifications */ \
+ IOV_DATA(0x12, 0x06, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x13), \
+ /* Step 3: Disable CCCD (simulates disconnection) */ \
+ IOV_DATA(0x12, 0x06, 0x00, 0x00, 0x00), \
+ IOV_DATA(0x13), \
+ /* Step 4: Re-enable notifications (simulates reconnection) */ \
+ IOV_DATA(0x12, 0x06, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x13), \
+ /* Disable CCCD to clean up */ \
+ IOV_DATA(0x12, 0x06, 0x00, 0x00, 0x00), \
+ IOV_DATA(0x13)
+
+/*
+ * RAS/SR/RRD/BV-01-C [Real-time Ranging Data]
+ * Verify that the IUT can configure CCCD for notifications/indications
+ * of the Real-time Ranging Data characteristic.
+ */
+#define RAS_SR_RRD_BV_01_C \
+ ATT_EXCHANGE_MTU, \
+ DISCOVER_PRIM_SERV_NOTIF, \
+ RAS_FIND_BY_TYPE_VALUE, \
+ DISC_RAS_CHAR_AFTER_TYPE, \
+ RAS_FIND_INFO, \
+ RAS_REALTIME_CCCD_CONFIG
+
+/*
+ * RAS/SR/RRD/BV-03-C [Real-time Ranging Data notifications and indications]
+ * Verify that the IUT only sends Real-time Ranging Data notifications when
+ * configured for both notifications and indications (CCCD = 0x0003).
+ *
+ * Test Procedure:
+ * 1. Write 0x0003 to Real-time Ranging Data CCCD (enable both
+ * notifications and indications)
+ * 2. Trigger CS Subevent Data (via fake HCI event injection)
+ * 3. Verify IUT sends only notifications (0x1b), not indications (0x1d)
+ */
+#define RAS_SR_RRD_BV_03_C \
+ ATT_EXCHANGE_MTU, \
+ DISCOVER_PRIM_SERV_NOTIF, \
+ RAS_FIND_BY_TYPE_VALUE, \
+ DISC_RAS_CHAR_AFTER_TYPE, \
+ RAS_FIND_INFO, \
+ RAS_REALTIME_CCCD_BOTH_ENABLE_DISABLE
+
+/*
+ * RAS/SR/RRD/BV-05-C [Real-Time Ranging Data disconnection]
+ * Verify that the IUT does not resume sending Real-time Ranging Data
+ * notifications or indications after a disconnection occurs.
+ *
+ * Test Procedure:
+ * 1. Enable Real-time Ranging Data notifications
+ * 2. Trigger CS Subevent Data (IUT sends notifications)
+ * 3. Disable CCCD (simulates disconnection - CCCD resets to 0x0000)
+ * 4. Re-enable notifications (simulates reconnection and reconfiguration)
+ * 5. Verify IUT does not send old ranging data
+ *
+ * Note: In a unit test, we simulate disconnection by disabling and re-enabling
+ * the CCCD. The RAP implementation should clear any pending data when CCCD is
+ * disabled, ensuring no old data is sent after re-enabling.
+ */
+#define RAS_SR_RRD_BV_05_C \
+ ATT_EXCHANGE_MTU, \
+ DISCOVER_PRIM_SERV_NOTIF, \
+ RAS_FIND_BY_TYPE_VALUE, \
+ DISC_RAS_CHAR_AFTER_TYPE, \
+ RAS_FIND_INFO, \
+ RAS_REALTIME_CCCD_DISCONNECT_RECONNECT
+
+/*
+ * RAS/SR/SPE/BI-11-C [Client enables both Real-time Ranging Data and
+ * On-demand Ranging Data notifications or indications]
+ *
+ * Test Purpose:
+ * Verify that the IUT responds with the Client Characteristic Configuration
+ * Descriptor Improperly Configured error when both Real-time Ranging Data
+ * and On-demand Ranging Data notifications or indications are enabled.
+ *
+ * Test Procedure:
+ * 1. Write 0x0001 to Real-time Ranging Data CCCD (enable notifications)
+ * 2. Write 0x0001 to On-demand Ranging Data CCCD (should fail with 0xFD)
+ * 3. Read both CCCDs to verify Real-time is 0x0001, On-demand is 0x0000
+ * 4. Write 0x0000 to Real-time Ranging Data CCCD (disable)
+ * 5. Write 0x0001 to On-demand Ranging Data CCCD (enable notifications)
+ * 6. Write 0x0001 to Real-time Ranging Data CCCD (should fail with 0xFD)
+ * 7. Read both CCCDs to verify Real-time is 0x0000, On-demand is 0x0001
+ *
+ * Expected Outcome:
+ * - Steps 2 and 6: IUT rejects with error code 0xFD
+ * - Step 3: Real-time CCCD = 0x0001, On-demand CCCD = 0x0000
+ * - Step 7: Real-time CCCD = 0x0000, On-demand CCCD = 0x0001
+ */
+#define RAS_SR_SPE_BI_11_C \
+ ATT_EXCHANGE_MTU, \
+ DISCOVER_PRIM_SERV_NOTIF, \
+ RAS_FIND_BY_TYPE_VALUE, \
+ DISC_RAS_CHAR_AFTER_TYPE, \
+ RAS_FIND_INFO, \
+ /* Step 1: Enable notifications on Real-time Ranging Data CCCD */ \
+ /* (handle 0x0006) */ \
+ IOV_DATA(0x12, 0x06, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x13), \
+ /* Step 2: Try to enable notifications on On-demand Ranging Data */ \
+ /* CCCD (handle 0x0009) - should fail with 0xFD */ \
+ IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x01, 0x12, 0x09, 0x00, 0xFD), \
+ /* Step 4: Read Real-time Ranging Data CCCD (should be 0x0001) */ \
+ IOV_DATA(0x0a, 0x06, 0x00), \
+ IOV_DATA(0x0b, 0x01, 0x00), \
+ /* Step 4: Read On-demand Ranging Data CCCD (should be 0x0000) */ \
+ IOV_DATA(0x0a, 0x09, 0x00), \
+ IOV_DATA(0x0b, 0x00, 0x00), \
+ /* Step 5: Disable Real-time Ranging Data CCCD */ \
+ IOV_DATA(0x12, 0x06, 0x00, 0x00, 0x00), \
+ IOV_DATA(0x13), \
+ /* Step 6: Enable notifications on On-demand Ranging Data CCCD */ \
+ IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x13), \
+ /* Step 7: Try to enable notifications on Real-time Ranging Data */ \
+ /* CCCD - should fail with 0xFD */ \
+ IOV_DATA(0x12, 0x06, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x01, 0x12, 0x06, 0x00, 0xFD), \
+ /* Step 9: Read Real-time Ranging Data CCCD (should be 0x0000) */ \
+ IOV_DATA(0x0a, 0x06, 0x00), \
+ IOV_DATA(0x0b, 0x00, 0x00), \
+ /* Step 9: Read On-demand Ranging Data CCCD (should be 0x0001) */ \
+ IOV_DATA(0x0a, 0x09, 0x00), \
+ IOV_DATA(0x0b, 0x01, 0x00)
+
int main(int argc, char *argv[])
{
tester_init(&argc, &argv);
@@ -441,6 +746,20 @@ int main(int argc, char *argv[])
RAS_SR_SGGIT_CHA_BV_03_C);
define_test_ras("RAS/SR/SGGIT/CHA/BV-04-C", test_server,
RAS_SR_SGGIT_CHA_BV_04_C);
+ /* RAS Read Characteristic Operations */
+ define_test_ras("RAS/SR/RCO/BV-01-C", test_server,
+ RAS_SR_RCO_BV_01_C);
+ /* RAS Real-time Ranging Data */
+ define_test_ras("RAS/SR/RRD/BV-01-C", test_server,
+ RAS_SR_RRD_BV_01_C);
+ /* RAS Real-time Ranging Data with CS injection */
+ define_test_ras("RAS/SR/RRD/BV-03-C", test_server,
+ RAS_SR_RRD_BV_03_C);
+ define_test_ras("RAS/SR/RRD/BV-05-C", test_server,
+ RAS_SR_RRD_BV_05_C);
+ /* RAS Special Procedures - Mutual Exclusivity */
+ define_test_ras("RAS/SR/SPE/BI-11-C", test_server,
+ RAS_SR_SPE_BI_11_C);
return tester_run();
}
--
2.34.1
^ permalink raw reply related
* [PATCH BlueZ v6 3/3] profiles/ranging: Read cs_mode_one_data members
From: Prathibha Madugonde @ 2026-04-29 15:29 UTC (permalink / raw)
To: linux-bluetooth; +Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg
In-Reply-To: <20260429152942.2940978-1-prathm@qti.qualcomm.com>
From: Prathibha Madugonde <prathibha.madugonde@oss.qualcomm.com>
Rearrage reading of cs_mode_one_data struct members as per spec.
---
profiles/ranging/rap_hci.c | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/profiles/ranging/rap_hci.c b/profiles/ranging/rap_hci.c
index a3d2df608..08ddc077c 100644
--- a/profiles/ranging/rap_hci.c
+++ b/profiles/ranging/rap_hci.c
@@ -632,19 +632,22 @@ static void parse_mode_one_data(struct iovec *iov,
}
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;
+ /* Parse fixed fields in specification order */
+ if (!util_iov_pull_u8(iov, &mode_data->packet_quality) ||
+ !util_iov_pull_u8(iov, &mode_data->packet_nadm) ||
+ !util_iov_pull_u8(iov, &mode_data->packet_rssi_dbm) ||
+ !util_iov_pull_le16(iov, &time_val) ||
+ !util_iov_pull_u8(iov, &mode_data->packet_ant)) {
+ DBG("Mode 1: failed to parse basic fields");
+ memset(mode_data, 0, sizeof(*mode_data));
+ return;
}
+ 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;
--
2.34.1
^ permalink raw reply related
* [bluez/bluez]
From: BluezTestBot @ 2026-04-29 15:30 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1087302
Home: https://github.com/bluez/bluez
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* Re: [PATCH v2] Bluetooth: btusb: Allow firmware re-download when version matches
From: Luiz Augusto von Dentz @ 2026-04-29 16:14 UTC (permalink / raw)
To: Shuai Zhang
Cc: Marcel Holtmann, linux-bluetooth, linux-kernel, linux-arm-msm,
cheng.jiang, quic_chezhou, wei.deng, jinwang.li, mengshi.wu
In-Reply-To: <CABBYNZLP+rBrjhdKJLE7N47Bg-g4-6E3vS3yZXvMKwYQ2rMcUA@mail.gmail.com>
Hi Shuai,
On Wed, Apr 29, 2026 at 11:17 AM Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
>
> Hi Shuai,
>
> On Wed, Apr 29, 2026 at 8:12 AM Shuai Zhang
> <shuai.zhang@oss.qualcomm.com> wrote:
> >
> > The Bluetooth host decides whether to download firmware by reading the
> > controller firmware download completion flag and firmware version
> > information.
> >
> > If a USB error occurs during the firmware download process (for example
> > due to a USB disconnect), the download is aborted immediately. An
> > incomplete firmware transfer does not cause the controller to set the
> > download completion flag, but the firmware version information may be
> > updated at an early stage of the download process.
>
> Hold on, if the download has been aborted then the version should be
> reverted, or rather just update once the firmware loading is complete,
> so this indicates there is a bug somewhere that needs fixing, not
> worked around.
>
> > In this case, after USB reconnection, the host attempts to re-download
> > the firmware because the download completion flag is not set. However,
> > since the controller reports the same firmware version as the target
> > firmware, the download is skipped. This ultimately results in the
> > firmware not being properly updated on the controller.
> >
> > This change removes the restriction that skips firmware download when
> > the versions are equal. It covers scenarios where the USB connection
> > can be disconnected at any time and ensures that firmware download can
> > be retriggered after USB reconnection, allowing the Bluetooth firmware
> > to be correctly and completely updated.
> >
> > Signed-off-by: Shuai Zhang <shuai.zhang@oss.qualcomm.com>
> > ---
> > Changes v2:
> > - Update code comments and commit message to reflect the correct logic.
> > - Align the commit title with upstream conventions.
> > - Link v1
> > https://lore.kernel.org/all/20260108074353.1027877-1-shuai.zhang@oss.qualcomm.com/
> > ---
> > drivers/bluetooth/btusb.c | 8 +++++++-
> > 1 file changed, 7 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> > index 572091e60..70abbabea 100644
> > --- a/drivers/bluetooth/btusb.c
> > +++ b/drivers/bluetooth/btusb.c
> > @@ -3550,7 +3550,13 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev,
> > "firmware rome 0x%x build 0x%x",
> > rver_rom, rver_patch, ver_rom, ver_patch);
> >
> > - if (rver_rom != ver_rom || rver_patch <= ver_patch) {
> > + /* Allow rampatch when the patch version equals the firmware version.
> > + * A firmware download may be aborted by a transient USB error (e.g.
> > + * disconnect) after the controller updates version info but before
> > + * completion.
> > + * Allowing equal versions enables re-flashing during recovery.
> > + */
> > + if (rver_rom != ver_rom || rver_patch < ver_patch) {
>
> As I said above, this sounds more like a workaround. That said, I
> wonder why it would print an error if the version matches, it sounds
> to be that if the version matches it should just skip and consider it
> has been loaded already in case the actual problem is fixed by setting
> the new version only when loading has been completed.
Btw, the following also seem valid although not introduced by this change:
https://sashiko.dev/#/patchset/20260429121207.1306526-1-shuai.zhang%40oss.qualcomm.com
> > bt_dev_err(hdev, "rampatch file version did not match with firmware");
> > err = -EINVAL;
> > goto done;
> > --
> > 2.34.1
> >
>
>
> --
> Luiz Augusto von Dentz
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH 7/9] Bluetooth: hci_sync: Add NVMEM-backed BD address retrieval
From: Loic Poulain @ 2026-04-29 16:22 UTC (permalink / raw)
To: Andrew Lunn
Cc: Bartosz Golaszewski, Ulf Hansson, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
Jens Axboe, Johannes Berg, Jeff Johnson, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, linux-mmc, devicetree, linux-kernel, linux-arm-msm,
linux-block, linux-wireless, ath10k, linux-bluetooth, netdev,
daniel
In-Reply-To: <e0adaf64-10d7-4e28-8403-769e3070ec30@lunn.ch>
Hi Bartosz, Andrew,
On Wed, Apr 29, 2026 at 3:15 PM Andrew Lunn <andrew@lunn.ch> wrote:
>
> On Wed, Apr 29, 2026 at 10:53:13AM +0200, Bartosz Golaszewski wrote:
> > On Tue, Apr 28, 2026 at 4:23 PM Loic Poulain
> > <loic.poulain@oss.qualcomm.com> wrote:
> > >
> > > Some devices store the Bluetooth BD address in non-volatile
> > > memory, which can be accessed through the NVMEM framework.
> > > Similar to Ethernet or WiFi MAC addresses, add support for
> > > reading the BD address from a 'local-bd-address' NVMEM cell.
> > >
> > > As with the device-tree provided BD address, add a quirk to
> > > indicate whether a device or platform should attempt to read
> > > the address from NVMEM when no valid in-chip address is present.
> > > Also add a quirk to indicate if the address is stored in
> > > big-endian byte order.
> > >
> > > Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> > > ---
> >
> > Is there any reason why we can't extend the existing
> > of_get_mac_address() with another property name and use it here? It
> > already has support for mac addresses from nvmem.
>
> Does it even need to be a different property name? Is a bluetooth MAC
> address somehow different to an Ethernet MAC address? Isn't it just a
> EUI-48, independent of it being Ethernet, Bluetooth, wifi, fddi, token
> ring, homing pigeon?
In terms of naming, I followed the pattern of the existing DT
properties: for Ethernet/WiFi there is mac-address property, and for
Bluetooth a local-bd-address property. So it seems reasonable to reuse
the same naming for the NVMEM labelling. Also One thing to keep in
mind is that Bluetooth has historically handled addresses in
little-endian format, while Ethernet MAC addresses are typically
stored in big-endian format (as far as I know).
That said, a more generic EUI-48 identifier could also make sense if
we want to go in that direction, with expected property/nvmem-cell
name(s) as parameters?
Regards,
Loic
^ permalink raw reply
* RE: Bluetooth: btrtl: fix RTL8761B/BU broken LE extended scan
From: bluez.test.bot @ 2026-04-29 16:43 UTC (permalink / raw)
To: linux-bluetooth, alexej
In-Reply-To: <20260429151343.28142-1-alexej@sidorenko.cz>
[-- Attachment #1: Type: text/plain, Size: 882 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=1087576
---Test result---
Test Summary:
CheckPatch PASS 0.72 seconds
GitLint PASS 0.33 seconds
SubjectPrefix PASS 0.16 seconds
BuildKernel PASS 25.55 seconds
CheckAllWarning PASS 28.38 seconds
CheckSparse PASS 26.93 seconds
BuildKernel32 PASS 25.18 seconds
TestRunnerSetup PASS 561.16 seconds
IncrementalBuild PASS 24.22 seconds
https://github.com/bluez/bluetooth-next/pull/133
---
Regards,
Linux Bluetooth
^ permalink raw reply
* [bluez/bluez] 62ddd2: src/shared: Add RAS packet format and notification...
From: prathibhamadugonde @ 2026-04-29 17:00 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1087593
Home: https://github.com/bluez/bluez
Commit: 62ddd2ea0370831d471a189551380c197e076a6d
https://github.com/bluez/bluez/commit/62ddd2ea0370831d471a189551380c197e076a6d
Author: Prathibha Madugonde <prathibha.madugonde@oss.qualcomm.com>
Date: 2026-04-29 (Wed, 29 Apr 2026)
Changed paths:
M src/shared/rap.c
M src/shared/rap.h
Log Message:
-----------
src/shared: Add RAS packet format and notification support
Implement complete RAS data pipeline:
- Handle HCI CS subevent result/continuation events
- Serialize ranging/subevent headers per spec
- GATT notifications for real-time ranging data
Commit: ef82bc92632ac28d2a435938ddf07614db4518e9
https://github.com/bluez/bluez/commit/ef82bc92632ac28d2a435938ddf07614db4518e9
Author: Prathibha Madugonde <prathibha.madugonde@oss.qualcomm.com>
Date: 2026-04-29 (Wed, 29 Apr 2026)
Changed paths:
M profiles/ranging/rap_hci.c
Log Message:
-----------
profiles/ranging: Read cs_mode_one_data members
Rearrage reading of cs_mode_one_data struct members as per spec.
Compare: https://github.com/bluez/bluez/compare/62ddd2ea0370%5E...ef82bc92632a
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* RE: Add RAS Packet format and Notification support
From: bluez.test.bot @ 2026-04-29 17:56 UTC (permalink / raw)
To: linux-bluetooth, prathibha.madugonde
In-Reply-To: <20260429152942.2940978-2-prathm@qti.qualcomm.com>
[-- Attachment #1: Type: text/plain, Size: 989 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1087593
---Test result---
Test Summary:
CheckPatch PASS 2.88 seconds
GitLint PASS 0.68 seconds
BuildEll PASS 20.16 seconds
BluezMake PASS 633.33 seconds
MakeCheck PASS 1.04 seconds
MakeDistcheck PASS 244.49 seconds
CheckValgrind PASS 221.27 seconds
CheckSmatch PASS 349.22 seconds
bluezmakeextell PASS 180.63 seconds
IncrementalBuild PASS 638.28 seconds
ScanBuild PASS 1025.08 seconds
https://github.com/bluez/bluez/pull/2085
---
Regards,
Linux Bluetooth
^ permalink raw reply
* bluetooth hci0: Direct firmware load for rtl_bt/rtl8761a_config.bin failed with error -2
From: Zenm Chen @ 2026-04-29 19:10 UTC (permalink / raw)
To: linux-bluetooth, max.chou, hildawu; +Cc: pkshih
Hi,
Recently I got an RTL8812AEBT card which is a WiFi5 + BT4.0 device.
Bluetooth is working fine but I see the warning below in dmesg. It seems
the config file rtl_bt/rtl8761a_config.bin is missing, not sure if this
should be fixed or not.
$ dmesg
[ 171.900777] Bluetooth: Core ver 2.22
[ 171.900818] NET: Registered PF_BLUETOOTH protocol family
[ 171.900820] Bluetooth: HCI device and connection manager initialized
[ 171.900825] Bluetooth: HCI socket layer initialized
[ 171.900827] Bluetooth: L2CAP socket layer initialized
[ 171.900831] Bluetooth: SCO socket layer initialized
[ 171.934237] usbcore: registered new interface driver btusb
[ 171.941534] Bluetooth: hci0: RTL: examining hci_ver=06 hci_rev=000a lmp_ver=06 lmp_subver=8761
[ 171.943635] Bluetooth: hci0: RTL: rom_version status=0 version=3
[ 171.945657] Bluetooth: hci0: RTL: btrtl_initialize: key id 0
[ 171.945664] Bluetooth: hci0: RTL: loading rtl_bt/rtl8761a_fw.bin
[ 171.949630] Bluetooth: hci0: RTL: loading rtl_bt/rtl8761a_config.bin
[ 171.949697] bluetooth hci0: Direct firmware load for rtl_bt/rtl8761a_config.bin failed with error -2
[ 171.949712] Bluetooth: hci0: RTL: cfg_sz -2, total sz 22640
[ 172.020303] Bluetooth: BNEP (Ethernet Emulation) ver 1.3
[ 172.020309] Bluetooth: BNEP filters: protocol multicast
[ 172.020314] Bluetooth: BNEP socket layer initialized
[ 172.524780] Bluetooth: hci0: RTL: fw version 0x0e3e4380
[ 172.664330] Bluetooth: MGMT ver 1.22
[ 172.683252] NET: Registered PF_ALG protocol family
[ 172.744110] Bluetooth: RFCOMM TTY layer initialized
[ 172.744124] Bluetooth: RFCOMM socket layer initialized
[ 172.744136] Bluetooth: RFCOMM ver 1.11
$ sudo lsusb -v -d 0bda:b761
Bus 003 Device 004: ID 0bda:b761 Realtek Semiconductor Corp. Bluetooth Radio
Negotiated speed: Full Speed (12Mbps)
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.10
bDeviceClass 224 Wireless
bDeviceSubClass 1 Radio Frequency
bDeviceProtocol 1 Bluetooth
bMaxPacketSize0 64
idVendor 0x0bda Realtek Semiconductor Corp.
idProduct 0xb761 Bluetooth Radio
bcdDevice 2.00
iManufacturer 1 Realtek
iProduct 2 Bluetooth Radio
iSerial 3 00e04c000001
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x00b1
bNumInterfaces 2
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xe0
Self Powered
Remote Wakeup
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 224 Wireless
bInterfaceSubClass 1 Radio Frequency
bInterfaceProtocol 1 Bluetooth
iInterface 4 Bluetooth Radio
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0010 1x 16 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 224 Wireless
bInterfaceSubClass 1 Radio Frequency
bInterfaceProtocol 1 Bluetooth
iInterface 4 Bluetooth Radio
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x03 EP 3 OUT
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0000 1x 0 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0000 1x 0 bytes
bInterval 1
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 1
bNumEndpoints 2
bInterfaceClass 224 Wireless
bInterfaceSubClass 1 Radio Frequency
bInterfaceProtocol 1 Bluetooth
iInterface 4 Bluetooth Radio
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x03 EP 3 OUT
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0009 1x 9 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0009 1x 9 bytes
bInterval 1
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 2
bNumEndpoints 2
bInterfaceClass 224 Wireless
bInterfaceSubClass 1 Radio Frequency
bInterfaceProtocol 1 Bluetooth
iInterface 4 Bluetooth Radio
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x03 EP 3 OUT
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0011 1x 17 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0011 1x 17 bytes
bInterval 1
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 3
bNumEndpoints 2
bInterfaceClass 224 Wireless
bInterfaceSubClass 1 Radio Frequency
bInterfaceProtocol 1 Bluetooth
iInterface 4 Bluetooth Radio
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x03 EP 3 OUT
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0019 1x 25 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0019 1x 25 bytes
bInterval 1
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 4
bNumEndpoints 2
bInterfaceClass 224 Wireless
bInterfaceSubClass 1 Radio Frequency
bInterfaceProtocol 1 Bluetooth
iInterface 4 Bluetooth Radio
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x03 EP 3 OUT
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0021 1x 33 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0021 1x 33 bytes
bInterval 1
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 5
bNumEndpoints 2
bInterfaceClass 224 Wireless
bInterfaceSubClass 1 Radio Frequency
bInterfaceProtocol 1 Bluetooth
iInterface 4 Bluetooth Radio
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x03 EP 3 OUT
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0031 1x 49 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0031 1x 49 bytes
bInterval 1
Binary Object Store Descriptor:
bLength 5
bDescriptorType 15
wTotalLength 0x000c
bNumDeviceCaps 1
USB 2.0 Extension Device Capability:
bLength 7
bDescriptorType 16
bDevCapabilityType 2
bmAttributes 0x00000002
HIRD Link Power Management (LPM) Supported
Device Status: 0x0001
Self Powered
$ sudo cat /sys/kernel/debug/usb/devices
T: Bus=03 Lev=01 Prnt=01 Port=04 Cnt=03 Dev#= 4 Spd=12 MxCh= 0
D: Ver= 2.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=0bda ProdID=b761 Rev= 2.00
S: Manufacturer=Realtek
S: Product=Bluetooth Radio
S: SerialNumber=00e04c000001
C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
^ permalink raw reply
* Re: [PATCH 0/9] Support for block device NVMEM providers
From: Loic Poulain @ 2026-04-29 20:20 UTC (permalink / raw)
To: Andrew Lunn
Cc: Ulf Hansson, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Jens Axboe, Johannes Berg,
Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, linux-mmc, devicetree, linux-kernel, linux-arm-msm,
linux-block, linux-wireless, ath10k, linux-bluetooth, netdev,
daniel
In-Reply-To: <b4de6c89-dd89-4e02-8d79-911e4f9f0813@lunn.ch>
Hi Andrew,
On Wed, Apr 29, 2026 at 3:06 AM Andrew Lunn <andrew@lunn.ch> wrote:
>
> > Note that this is currently limited to eMMC-backed block devices, as
> > only the eMMC core associates a firmware node with the block device
> > (add_disk_fwnode). This can be easily extended in the future to
> > support additional block drivers.
>
> Would this be
>
> https://elixir.bootlin.com/linux/v7.0.1/source/drivers/mmc/core/block.c#L2641
>
> Looking at that function, mmc_blk_alloc_req() i don't see it doing
> anything different between an eMMC and MMC.
Yes, that’s correct, in the previous sentence I should have referred
to MMC-backed storage rather than specifically eMMC, since the MMC
scope also includes removable MMC/SD cards. That said, eMMC is more
likely to be used as an NVMEM area.
>
> An eMMC you don't expect to go away, since it is soldered
> down. However an MMC can be ejected. Is the code prepared for that?
I was about to say this wouldn’t be an issue, since the NVMEM device
would be unregistered along with the MMC card removal. However,
looking at nvmem_unregister(), it simply performs a kref_put(). This
means that if a consumer still holds a reference, e.g. through an
nvmem_cell, it might still be able to access the NVMEM reg_read
callback after the NVMEM device has been unregistered and the
NVMEM provider data (bnv) has been freed...
I guess I need to try and dig into this but at first glance it seems to be a
general NVMEM issue, since even though most NVMEM providers are
not hard-removable, there is nothing that fundamentally prevents them
from being logically removed/unbound at runtime.
Regards,
Loic
^ permalink raw reply
* RE: bluetooth hci0: Direct firmware load for rtl_bt/rtl8761a_config.bin failed with error -2
From: Max Chou @ 2026-04-30 2:22 UTC (permalink / raw)
To: Zenm Chen, linux-bluetooth@vger.kernel.org, Hilda Wu; +Cc: Ping-Ke Shih
In-Reply-To: <20260429191004.11965-1-zenmchen@gmail.com>
Hi!
The config file rtl8761a_config is not mandatory. In ic_id_table[],
.config_needed is indeed set to false. Please rest assured regarding
this matter.
If you would like to fix the warning message, it would be good to
send a patch to add rtl8761a_config.bin containing only the header
to the linux-firmware repository.
BRs,
Max
> -----Original Message-----
> From: Zenm Chen <zenmchen@gmail.com>
> Sent: Thursday, April 30, 2026 3:10 AM
> To: linux-bluetooth@vger.kernel.org; Max Chou <max.chou@realtek.com>;
> Hilda Wu <hildawu@realtek.com>
> Cc: Ping-Ke Shih <pkshih@realtek.com>
> Subject: bluetooth hci0: Direct firmware load for rtl_bt/rtl8761a_config.bin
> failed with error -2
>
>
> External mail : This email originated from outside the organization. Do not
> reply, click links, or open attachments unless you recognize the sender and
> know the content is safe.
>
>
>
> Hi,
>
> Recently I got an RTL8812AEBT card which is a WiFi5 + BT4.0 device.
> Bluetooth is working fine but I see the warning below in dmesg. It seems the
> config file rtl_bt/rtl8761a_config.bin is missing, not sure if this should be
> fixed or not.
>
> $ dmesg
> [ 171.900777] Bluetooth: Core ver 2.22
> [ 171.900818] NET: Registered PF_BLUETOOTH protocol family
> [ 171.900820] Bluetooth: HCI device and connection manager initialized
> [ 171.900825] Bluetooth: HCI socket layer initialized [ 171.900827]
> Bluetooth: L2CAP socket layer initialized [ 171.900831] Bluetooth: SCO
> socket layer initialized [ 171.934237] usbcore: registered new interface
> driver btusb [ 171.941534] Bluetooth: hci0: RTL: examining hci_ver=06
> hci_rev=000a lmp_ver=06 lmp_subver=8761 [ 171.943635] Bluetooth: hci0:
> RTL: rom_version status=0 version=3 [ 171.945657] Bluetooth: hci0: RTL:
> btrtl_initialize: key id 0 [ 171.945664] Bluetooth: hci0: RTL: loading
> rtl_bt/rtl8761a_fw.bin [ 171.949630] Bluetooth: hci0: RTL: loading
> rtl_bt/rtl8761a_config.bin [ 171.949697] bluetooth hci0: Direct firmware
> load for rtl_bt/rtl8761a_config.bin failed with error -2 [ 171.949712]
> Bluetooth: hci0: RTL: cfg_sz -2, total sz 22640 [ 172.020303] Bluetooth:
> BNEP (Ethernet Emulation) ver 1.3 [ 172.020309] Bluetooth: BNEP filters:
> protocol multicast [ 172.020314] Bluetooth: BNEP socket layer initialized
> [ 172.524780] Bluetooth: hci0: RTL: fw version 0x0e3e4380 [ 172.664330]
> Bluetooth: MGMT ver 1.22 [ 172.683252] NET: Registered PF_ALG protocol
> family [ 172.744110] Bluetooth: RFCOMM TTY layer initialized
> [ 172.744124] Bluetooth: RFCOMM socket layer initialized [ 172.744136]
> Bluetooth: RFCOMM ver 1.11
>
> $ sudo lsusb -v -d 0bda:b761
> Bus 003 Device 004: ID 0bda:b761 Realtek Semiconductor Corp. Bluetooth
> Radio Negotiated speed: Full Speed (12Mbps) Device Descriptor:
> bLength 18
> bDescriptorType 1
> bcdUSB 2.10
> bDeviceClass 224 Wireless
> bDeviceSubClass 1 Radio Frequency
> bDeviceProtocol 1 Bluetooth
> bMaxPacketSize0 64
> idVendor 0x0bda Realtek Semiconductor Corp.
> idProduct 0xb761 Bluetooth Radio
> bcdDevice 2.00
> iManufacturer 1 Realtek
> iProduct 2 Bluetooth Radio
> iSerial 3 00e04c000001
> bNumConfigurations 1
> Configuration Descriptor:
> bLength 9
> bDescriptorType 2
> wTotalLength 0x00b1
> bNumInterfaces 2
> bConfigurationValue 1
> iConfiguration 0
> bmAttributes 0xe0
> Self Powered
> Remote Wakeup
> MaxPower 500mA
> Interface Descriptor:
> bLength 9
> bDescriptorType 4
> bInterfaceNumber 0
> bAlternateSetting 0
> bNumEndpoints 3
> bInterfaceClass 224 Wireless
> bInterfaceSubClass 1 Radio Frequency
> bInterfaceProtocol 1 Bluetooth
> iInterface 4 Bluetooth Radio
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x81 EP 1 IN
> bmAttributes 3
> Transfer Type Interrupt
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0010 1x 16 bytes
> bInterval 1
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x02 EP 2 OUT
> bmAttributes 2
> Transfer Type Bulk
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0040 1x 64 bytes
> bInterval 0
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x82 EP 2 IN
> bmAttributes 2
> Transfer Type Bulk
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0040 1x 64 bytes
> bInterval 0
> Interface Descriptor:
> bLength 9
> bDescriptorType 4
> bInterfaceNumber 1
> bAlternateSetting 0
> bNumEndpoints 2
> bInterfaceClass 224 Wireless
> bInterfaceSubClass 1 Radio Frequency
> bInterfaceProtocol 1 Bluetooth
> iInterface 4 Bluetooth Radio
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x03 EP 3 OUT
> bmAttributes 1
> Transfer Type Isochronous
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0000 1x 0 bytes
> bInterval 1
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x83 EP 3 IN
> bmAttributes 1
> Transfer Type Isochronous
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0000 1x 0 bytes
> bInterval 1
> Interface Descriptor:
> bLength 9
> bDescriptorType 4
> bInterfaceNumber 1
> bAlternateSetting 1
> bNumEndpoints 2
> bInterfaceClass 224 Wireless
> bInterfaceSubClass 1 Radio Frequency
> bInterfaceProtocol 1 Bluetooth
> iInterface 4 Bluetooth Radio
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x03 EP 3 OUT
> bmAttributes 1
> Transfer Type Isochronous
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0009 1x 9 bytes
> bInterval 1
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x83 EP 3 IN
> bmAttributes 1
> Transfer Type Isochronous
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0009 1x 9 bytes
> bInterval 1
> Interface Descriptor:
> bLength 9
> bDescriptorType 4
> bInterfaceNumber 1
> bAlternateSetting 2
> bNumEndpoints 2
> bInterfaceClass 224 Wireless
> bInterfaceSubClass 1 Radio Frequency
> bInterfaceProtocol 1 Bluetooth
> iInterface 4 Bluetooth Radio
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x03 EP 3 OUT
> bmAttributes 1
> Transfer Type Isochronous
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0011 1x 17 bytes
> bInterval 1
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x83 EP 3 IN
> bmAttributes 1
> Transfer Type Isochronous
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0011 1x 17 bytes
> bInterval 1
> Interface Descriptor:
> bLength 9
> bDescriptorType 4
> bInterfaceNumber 1
> bAlternateSetting 3
> bNumEndpoints 2
> bInterfaceClass 224 Wireless
> bInterfaceSubClass 1 Radio Frequency
> bInterfaceProtocol 1 Bluetooth
> iInterface 4 Bluetooth Radio
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x03 EP 3 OUT
> bmAttributes 1
> Transfer Type Isochronous
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0019 1x 25 bytes
> bInterval 1
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x83 EP 3 IN
> bmAttributes 1
> Transfer Type Isochronous
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0019 1x 25 bytes
> bInterval 1
> Interface Descriptor:
> bLength 9
> bDescriptorType 4
> bInterfaceNumber 1
> bAlternateSetting 4
> bNumEndpoints 2
> bInterfaceClass 224 Wireless
> bInterfaceSubClass 1 Radio Frequency
> bInterfaceProtocol 1 Bluetooth
> iInterface 4 Bluetooth Radio
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x03 EP 3 OUT
> bmAttributes 1
> Transfer Type Isochronous
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0021 1x 33 bytes
> bInterval 1
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x83 EP 3 IN
> bmAttributes 1
> Transfer Type Isochronous
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0021 1x 33 bytes
> bInterval 1
> Interface Descriptor:
> bLength 9
> bDescriptorType 4
> bInterfaceNumber 1
> bAlternateSetting 5
> bNumEndpoints 2
> bInterfaceClass 224 Wireless
> bInterfaceSubClass 1 Radio Frequency
> bInterfaceProtocol 1 Bluetooth
> iInterface 4 Bluetooth Radio
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x03 EP 3 OUT
> bmAttributes 1
> Transfer Type Isochronous
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0031 1x 49 bytes
> bInterval 1
> Endpoint Descriptor:
> bLength 7
> bDescriptorType 5
> bEndpointAddress 0x83 EP 3 IN
> bmAttributes 1
> Transfer Type Isochronous
> Synch Type None
> Usage Type Data
> wMaxPacketSize 0x0031 1x 49 bytes
> bInterval 1
> Binary Object Store Descriptor:
> bLength 5
> bDescriptorType 15
> wTotalLength 0x000c
> bNumDeviceCaps 1
> USB 2.0 Extension Device Capability:
> bLength 7
> bDescriptorType 16
> bDevCapabilityType 2
> bmAttributes 0x00000002
> HIRD Link Power Management (LPM) Supported
> Device Status: 0x0001
> Self Powered
>
> $ sudo cat /sys/kernel/debug/usb/devices
> T: Bus=03 Lev=01 Prnt=01 Port=04 Cnt=03 Dev#= 4 Spd=12 MxCh= 0
> D: Ver= 2.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
> P: Vendor=0bda ProdID=b761 Rev= 2.00
> S: Manufacturer=Realtek
> S: Product=Bluetooth Radio
> S: SerialNumber=00e04c000001
> C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA
> I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
> E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
> E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
> I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
> E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
> I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
> E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
> I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
> E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
> I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
> E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
> I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
> E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
> I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
> E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
^ permalink raw reply
* [PATCH] Bluetooth: btintel_pcie: Remove unused ret in btintel_pcie_submit_rx_work()
From: Robertus Diawan Chris @ 2026-04-30 4:05 UTC (permalink / raw)
To: marcel, luiz.dentz
Cc: linux-bluetooth, linux-kernel, linux-kernel-mentees, skhan, me
The variable ret assigned to -EINVAL, however, this value is never read
and re-assigned a new value when the code jumps to label resubmit.
The assignment is redundant and can be removed.
This is reported by Coverity Scan with CID 1598882 as UNUSED_VALUE.
Signed-off-by: Robertus Diawan Chris <robertusdchris@gmail.com>
---
drivers/bluetooth/btintel_pcie.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c
index 2f59c0d6f9ec..ac4f5b45a6af 100644
--- a/drivers/bluetooth/btintel_pcie.c
+++ b/drivers/bluetooth/btintel_pcie.c
@@ -1376,10 +1376,8 @@ static int btintel_pcie_submit_rx_work(struct btintel_pcie_data *data, u8 status
rfh_hdr = buf;
len = rfh_hdr->packet_len;
- if (len <= 0) {
- ret = -EINVAL;
+ if (len <= 0)
goto resubmit;
- }
/* Remove RFH header */
buf += sizeof(*rfh_hdr);
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
--
2.54.0
^ permalink raw reply related
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