* xHCI TT: FS audio capture glitches when btusb SCO runs concurrently
From: Branislav Klocok @ 2026-07-18 10:18 UTC (permalink / raw)
To: linux-usb; +Cc: linux-bluetooth, mathias.nyman
Hi,
I'd like to report (and ask for guidance on) an apparent conflict between
two concurrent full-speed isochronous streams on the same xHCI controller:
a full-speed USB audio device behind a hub (split transactions through the
hub's TT) and the SCO endpoints of an Intel Bluetooth controller (btusb)
on a root port.
Short version: while an HFP call is active over Bluetooth (SCO), the
capture stream of a full-speed USB headset plugged in *behind a dock hub*
is subtly corrupted. After mSBC encoding and the telephony path, the far
end hears severely "robotic" audio. Moving the same headset to a direct
root port makes the problem disappear immediately; moving it back behind
the dock brings it back. CVSD calls are perceptually unaffected.
Environment
-----------
- ThinkPad X1 Carbon 6th gen; xHCI: Intel Sunrise Point-LP [8086:9d2f]
- Kernel 7.1.3-1-default (openSUSE Tumbleweed), BlueZ 5.82,
PipeWire 1.6.8 / WirePlumber 0.5.15 (HFP native backend, laptop = HF)
- Bluetooth: Intel 8265 [8087:0a2b], full-speed, internal (bus 1 root
port 7), fw ibt-12-16
- USB headset: C-Media [0d8c:0014], full-speed, mono capture 48 kHz
- Dock: Lenovo USB dock (hubs 17ef:3071/17ef:3070, cascade incl.
067b:2586 and 05e3:0610)
- HFP counterpart: Android phone (Volla X23) as AG; a call was placed to
a second handset held at my ear, so I judged the far-end quality
directly while speaking
SCO detail during mSBC: eSCO, air mode Transparent, 60-byte RX/TX packet
length, btusb isoc alt setting 1 (9-byte packets), HCI SCO frames
dlen 24. CVSD uses alt setting 2 (17-byte packets).
Reproduction (single call, changing only the capture source / port)
-------------------------------------------------------------------
I kept the same position and speech style throughout and judged the
quality on the far-end handset:
uplink capture source far-end verdict
1. HS webcam (behind the same dock) clean
2. FS headset behind dock hub A severely "robotic"
3. same, headset moved 30 cm away severely "robotic"
(rules out mic proximity/level)
4. FS headset on a DIRECT root port clean
5. FS headset behind dock hub B severely "robotic" again
(immediately reversible)
A parallel capture of the same source during phase 5 (recording to a file
while the stream also feeds the call) contains audible subtle glitching
already at the capture side -- i.e. the corruption exists in the USB
capture data before any Bluetooth/mSBC processing. Amplitude analysis
shows no zero-runs or full-scale clicks, so the defect consists of small
sample-level discontinuities, which the frame-based mSBC codec then
amplifies into severe artifacts, while sample-based CVSD mostly masks
them.
What I ruled out
----------------
- Bluetooth host stack: btmon traces covering a clean -> robotic -> clean
cycle show the HCI SCO TX stream is byte-perfect (intact 60-byte mSBC
framing with H2 headers, ~3333 frames/10 s constant) and the write
timing pattern is identical between clean and robotic phases (bursts of
3x24 B every ~7.5 ms). The RX direction is likewise clean. So
BlueZ/PipeWire/btusb submit correct data on time; the corruption
happens elsewhere.
- Audio content/level: same speech, same position (phase 3).
- The specific adapter/hub: reproduced behind two different hub chains,
and with a different FS combo headset (Sennheiser) behind a different
(Thunderbolt) dock in another location -- there the mSBC *downlink*
died completely while CVSD kept working.
- PipeWire graph effects: an *idle* parallel capture from the FS device
behind the dock (both via PipeWire and via direct ALSA hw:) does NOT
disturb a call whose uplink comes from the HS webcam -- the corruption
only matters when the TT capture stream is the one feeding the call.
Consistent with the corruption being on the TT capture stream itself.
Possibly related: "Bluetooth: hci0: corrupted SCO packet" bursts (~14-32
messages) at SCO setup time, with both codecs, transient. Earlier this
year, on 6.18.8 with the Thunderbolt dock setup, mSBC showed frequent
decode errors but audio still flowed; I have not bisected.
Questions
---------
1. Is this a known limitation of xHCI TT split-isochronous scheduling
with two concurrent FS isoc streams (one behind a TT, one on a root
port)? EHCI had a software TT scheduler
(CONFIG_USB_EHCI_TT_NEWSCHED); as far as I can tell xHCI relies on
hardware scheduling with no equivalent knob.
2. Which captures would help most? I can provide btmon traces (a 26 MB
clean/robotic cycle), usbmon captures, xhci dynamic debug logs and
audio samples, and I'm happy to test patches.
Best regards,
--
Branislav Klocok
email: branislav.klocok@orava.sk
tel: +421908703366
^ permalink raw reply
* Re: SIG-Qualification: Problems with setting TSPC_L2CAP_4_3
From: Chinedu Mmadu @ 2026-07-18 9:34 UTC (permalink / raw)
To: ceggers; +Cc: frederic.danis, linux-bluetooth, luiz.von.dentz
Sent from my iPhone
^ permalink raw reply
* [bluez/bluez]
From: BluezTestBot @ 2026-07-18 4:17 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1113188
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
* [bluetooth-next:master] BUILD SUCCESS bd8bee79e1fa8db2d587733f8b6fd9597b04d6e3
From: kernel test robot @ 2026-07-18 4:04 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master
branch HEAD: bd8bee79e1fa8db2d587733f8b6fd9597b04d6e3 Bluetooth: btintel_pcie: serialize reset_type with RECOVERY_IN_PROGRESS
elapsed time: 2063m
configs tested: 131
configs skipped: 1
The following configs have been built successfully.
More configs may be tested in the coming days.
tested configs:
alpha allnoconfig gcc-16.1.0
alpha allyesconfig gcc-16.1.0
alpha defconfig gcc-16.1.0
arc allmodconfig gcc-16.1.0
arc allyesconfig gcc-16.1.0
arc randconfig-001-20260717 gcc-11.5.0
arc randconfig-002-20260717 gcc-13.4.0
arm randconfig-001-20260717 clang-24
arm randconfig-002-20260717 clang-24
arm randconfig-003-20260717 gcc-8.5.0
arm randconfig-004-20260717 gcc-11.5.0
arm u8500_defconfig gcc-16.1.0
arm64 randconfig-001 gcc-14.3.0
arm64 randconfig-001-20260717 gcc-11.5.0
arm64 randconfig-002-20260717 gcc-8.5.0
arm64 randconfig-003-20260717 gcc-8.5.0
arm64 randconfig-004-20260717 gcc-9.5.0
csky allmodconfig gcc-16.1.0
csky randconfig-001-20260717 gcc-13.4.0
csky randconfig-002-20260717 gcc-15.2.0
hexagon randconfig-001-20260717 clang-24
hexagon randconfig-002-20260717 clang-24
i386 allmodconfig gcc-14
i386 buildonly-randconfig-001-20260717 gcc-14
i386 buildonly-randconfig-002-20260717 gcc-14
i386 buildonly-randconfig-003-20260717 clang-22
i386 buildonly-randconfig-004-20260717 gcc-14
i386 buildonly-randconfig-005-20260717 gcc-14
i386 buildonly-randconfig-006-20260717 clang-22
i386 randconfig-001-20260717 gcc-14
i386 randconfig-001-20260718 gcc-14
i386 randconfig-002-20260717 clang-22
i386 randconfig-002-20260718 gcc-14
i386 randconfig-003-20260717 clang-22
i386 randconfig-003-20260718 gcc-14
i386 randconfig-004-20260717 gcc-14
i386 randconfig-004-20260718 gcc-14
i386 randconfig-005-20260717 gcc-14
i386 randconfig-005-20260718 gcc-14
i386 randconfig-006-20260717 gcc-14
i386 randconfig-006-20260718 gcc-14
i386 randconfig-007-20260717 gcc-14
i386 randconfig-007-20260718 gcc-14
i386 randconfig-011-20260717 clang-22
i386 randconfig-011-20260718 clang-22
i386 randconfig-012-20260717 clang-22
i386 randconfig-012-20260718 clang-22
i386 randconfig-013-20260717 clang-22
i386 randconfig-013-20260718 clang-22
i386 randconfig-014-20260717 clang-22
i386 randconfig-014-20260718 clang-22
i386 randconfig-015-20260717 clang-22
i386 randconfig-015-20260718 clang-22
i386 randconfig-016-20260717 gcc-14
i386 randconfig-016-20260718 clang-22
i386 randconfig-017-20260717 clang-22
i386 randconfig-017-20260718 clang-22
loongarch defconfig clang-24
loongarch randconfig-001-20260717 gcc-16.1.0
loongarch randconfig-002-20260717 clang-24
m68k mvme147_defconfig gcc-16.1.0
nios2 allmodconfig gcc-11.5.0
nios2 allnoconfig gcc-11.5.0
nios2 randconfig-001-20260717 gcc-8.5.0
nios2 randconfig-002-20260717 gcc-8.5.0
parisc allmodconfig gcc-16.1.0
parisc allyesconfig gcc-16.1.0
parisc defconfig gcc-16.1.0
parisc randconfig-001 gcc-8.5.0
parisc randconfig-001-20260717 gcc-10.5.0
parisc randconfig-002-20260717 gcc-16.1.0
powerpc randconfig-001-20260717 gcc-13.4.0
powerpc randconfig-002-20260717 gcc-11.5.0
powerpc64 randconfig-001-20260717 gcc-15.2.0
powerpc64 randconfig-002-20260717 gcc-8.5.0
riscv randconfig-001-20260717 clang-16
riscv randconfig-001-20260718 clang-24
riscv randconfig-002-20260717 clang-24
riscv randconfig-002-20260718 clang-24
s390 randconfig-001-20260717 clang-24
s390 randconfig-001-20260718 clang-24
s390 randconfig-002-20260717 clang-20
s390 randconfig-002-20260718 clang-24
sh defconfig gcc-16.1.0
sh randconfig-001-20260717 gcc-9.5.0
sh randconfig-001-20260718 clang-24
sh randconfig-002-20260717 gcc-16.1.0
sh randconfig-002-20260718 clang-24
sparc randconfig-001-20260717 gcc-8.5.0
sparc randconfig-001-20260718 gcc-11.5.0
sparc randconfig-002-20260717 gcc-14.3.0
sparc randconfig-002-20260718 gcc-11.5.0
sparc64 randconfig-001-20260717 clang-22
sparc64 randconfig-001-20260718 gcc-11.5.0
sparc64 randconfig-002-20260717 clang-24
sparc64 randconfig-002-20260718 gcc-11.5.0
um randconfig-001-20260717 clang-24
um randconfig-001-20260718 gcc-11.5.0
um randconfig-002-20260717 clang-21
um randconfig-002-20260718 gcc-11.5.0
x86_64 buildonly-randconfig-001 gcc-12
x86_64 buildonly-randconfig-001-20260717 gcc-14
x86_64 buildonly-randconfig-002-20260717 gcc-14
x86_64 buildonly-randconfig-003-20260717 gcc-14
x86_64 buildonly-randconfig-004-20260717 gcc-14
x86_64 buildonly-randconfig-005-20260717 clang-22
x86_64 buildonly-randconfig-006-20260717 clang-22
x86_64 kexec clang-22
x86_64 randconfig-001-20260717 clang-22
x86_64 randconfig-002-20260717 clang-22
x86_64 randconfig-003-20260717 gcc-14
x86_64 randconfig-004-20260717 gcc-14
x86_64 randconfig-005-20260717 gcc-14
x86_64 randconfig-006-20260717 gcc-13
x86_64 randconfig-011-20260717 gcc-14
x86_64 randconfig-012-20260717 gcc-14
x86_64 randconfig-013-20260717 clang-22
x86_64 randconfig-014-20260717 gcc-12
x86_64 randconfig-015-20260717 gcc-14
x86_64 randconfig-016-20260717 gcc-14
x86_64 randconfig-071-20260717 gcc-14
x86_64 randconfig-072-20260717 gcc-14
x86_64 randconfig-073-20260717 gcc-14
x86_64 randconfig-074-20260717 gcc-12
x86_64 randconfig-075-20260717 gcc-14
x86_64 randconfig-076-20260717 clang-22
x86_64 rhel-9.4-bpf gcc-14
xtensa randconfig-001-20260717 gcc-16.1.0
xtensa randconfig-001-20260718 gcc-11.5.0
xtensa randconfig-002-20260717 gcc-14.3.0
xtensa randconfig-002-20260718 gcc-11.5.0
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* RE: Bluetooth: Replace HCI_VENDOR_PKT usages with HCI_EV_VENDOR
From: bluez.test.bot @ 2026-07-17 23:27 UTC (permalink / raw)
To: linux-bluetooth, zijun.hu
In-Reply-To: <20260717-fix_vendor-v1-1-f22263c1175b@oss.qualcomm.com>
[-- Attachment #1: Type: text/plain, Size: 1181 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=1129860
---Test result---
Test Summary:
CheckPatch PASS 1.75 seconds
VerifyFixes PASS 0.15 seconds
VerifySignedoff PASS 0.20 seconds
GitLint PASS 0.98 seconds
SubjectPrefix PASS 0.30 seconds
BuildKernel PASS 24.91 seconds
CheckAllWarning PASS 27.22 seconds
CheckSparse PASS 26.01 seconds
BuildKernel32 PASS 23.86 seconds
CheckKernelLLVM SKIP 0.00 seconds
TestRunnerSetup PASS 453.70 seconds
IncrementalBuild PASS 28.93 seconds
Details
##############################
Test: CheckKernelLLVM - SKIP
Desc: Build kernel with LLVM + context analysis
Output:
Clang not found
https://github.com/bluez/bluetooth-next/pull/452
---
Regards,
Linux Bluetooth
^ permalink raw reply
* RE: Bluetooth: btbcm: Add entry for BCM4356A3 UART bluetooth
From: bluez.test.bot @ 2026-07-17 22:35 UTC (permalink / raw)
To: linux-bluetooth, webgeek1234
In-Reply-To: <20260717-bcm4356a3-bt-v1-1-ffa2d5233360@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1181 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=1129847
---Test result---
Test Summary:
CheckPatch PASS 0.59 seconds
VerifyFixes PASS 0.09 seconds
VerifySignedoff PASS 0.08 seconds
GitLint PASS 1.51 seconds
SubjectPrefix PASS 0.67 seconds
BuildKernel PASS 29.41 seconds
CheckAllWarning PASS 32.67 seconds
CheckSparse PASS 30.24 seconds
BuildKernel32 PASS 28.53 seconds
CheckKernelLLVM SKIP 0.00 seconds
TestRunnerSetup PASS 528.47 seconds
IncrementalBuild PASS 30.05 seconds
Details
##############################
Test: CheckKernelLLVM - SKIP
Desc: Build kernel with LLVM + context analysis
Output:
Clang not found
https://github.com/bluez/bluetooth-next/pull/451
---
Regards,
Linux Bluetooth
^ permalink raw reply
* [PATCH 3/3] Bluetooth: btusb: Realtek: Replace HCI_VENDOR_PKT usage with HCI_EV_VENDOR
From: Zijun Hu @ 2026-07-17 22:08 UTC (permalink / raw)
To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz
Cc: Zijun Hu, linux-arm-msm, linux-bluetooth, linux-kernel, Zijun Hu
In-Reply-To: <20260717-fix_vendor-v1-0-f22263c1175b@oss.qualcomm.com>
The macros below have different meanings even though they share the
same value 0xff:
HCI_VENDOR_PKT: HCI packet indicator or type
HCI_EV_VENDOR: event code of a VSE
This usage of HCI_VENDOR_PKT is wrongly checking an event code.
Fix by using HCI_EV_VENDOR for event code.
Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
drivers/bluetooth/btusb.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index d69eec8b2911..6973daab91ec 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -2799,7 +2799,7 @@ static int btusb_setup_realtek(struct hci_dev *hdev)
static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb)
{
- if (skb->data[0] == HCI_VENDOR_PKT && skb->data[2] == RTK_SUB_EVENT_CODE_COREDUMP) {
+ if (skb->data[0] == HCI_EV_VENDOR && skb->data[2] == RTK_SUB_EVENT_CODE_COREDUMP) {
struct rtk_dev_coredump_hdr hdr = {
.code = RTK_DEVCOREDUMP_CODE_MEMDUMP,
};
--
2.34.1
^ permalink raw reply related
* [PATCH 2/3] Bluetooth: btusb: QCA: Replace HCI_VENDOR_PKT usages with HCI_EV_VENDOR
From: Zijun Hu @ 2026-07-17 22:08 UTC (permalink / raw)
To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz
Cc: Zijun Hu, linux-arm-msm, linux-bluetooth, linux-kernel, Zijun Hu
In-Reply-To: <20260717-fix_vendor-v1-0-f22263c1175b@oss.qualcomm.com>
The macros below have different meanings even though they share the
same value 0xff:
HCI_VENDOR_PKT: HCI packet indicator or type
HCI_EV_VENDOR: event code of a VSE
These usages of HCI_VENDOR_PKT are wrongly checking an event code.
Fix by using HCI_EV_VENDOR for event code.
Also fix warning "CHECK: Unnecessary parentheses around comparison"
given by checkpatch.pl.
Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
drivers/bluetooth/btusb.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 4c3193ec2d52..d69eec8b2911 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -3276,7 +3276,7 @@ static bool acl_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb)
goto out;
event_hdr = skb_pull_data(clone, sizeof(*event_hdr));
- if (!event_hdr || (event_hdr->evt != HCI_VENDOR_PKT))
+ if (!event_hdr || event_hdr->evt != HCI_EV_VENDOR)
goto out;
dump_hdr = skb_pull_data(clone, sizeof(*dump_hdr));
@@ -3302,7 +3302,7 @@ static bool evt_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb)
return false;
event_hdr = skb_pull_data(clone, sizeof(*event_hdr));
- if (!event_hdr || (event_hdr->evt != HCI_VENDOR_PKT))
+ if (!event_hdr || event_hdr->evt != HCI_EV_VENDOR)
goto out;
dump_hdr = skb_pull_data(clone, sizeof(*dump_hdr));
--
2.34.1
^ permalink raw reply related
* [PATCH 0/3] Bluetooth: Replace HCI_VENDOR_PKT usages with HCI_EV_VENDOR
From: Zijun Hu @ 2026-07-17 22:08 UTC (permalink / raw)
To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz
Cc: Zijun Hu, linux-arm-msm, linux-bluetooth, linux-kernel, Zijun Hu
The macros below have different meanings even though they share the
same value 0xff:
HCI_VENDOR_PKT: HCI packet indicator or type
HCI_EV_VENDOR: event code of a VSE
several usage of HCI_VENDOR_PKT is wrongly checking an event code.
Fix by using HCI_EV_VENDOR for event code.
Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
Zijun Hu (3):
Bluetooth: hci_qca: Replace HCI_VENDOR_PKT usage with HCI_EV_VENDOR
Bluetooth: btusb: QCA: Replace HCI_VENDOR_PKT usages with HCI_EV_VENDOR
Bluetooth: btusb: Realtek: Replace HCI_VENDOR_PKT usage with HCI_EV_VENDOR
drivers/bluetooth/btusb.c | 6 +++---
drivers/bluetooth/hci_qca.c | 4 ++--
2 files changed, 5 insertions(+), 5 deletions(-)
---
base-commit: bd8bee79e1fa8db2d587733f8b6fd9597b04d6e3
change-id: 20260717-fix_vendor-6f40af4b1c91
Best regards,
--
Zijun Hu <zijun.hu@oss.qualcomm.com>
^ permalink raw reply
* [PATCH 1/3] Bluetooth: hci_qca: Replace HCI_VENDOR_PKT usage with HCI_EV_VENDOR
From: Zijun Hu @ 2026-07-17 22:08 UTC (permalink / raw)
To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz
Cc: Zijun Hu, linux-arm-msm, linux-bluetooth, linux-kernel, Zijun Hu
In-Reply-To: <20260717-fix_vendor-v1-0-f22263c1175b@oss.qualcomm.com>
The macros below have different meanings even though they share the
same value 0xff:
HCI_VENDOR_PKT: HCI packet indicator or type
HCI_EV_VENDOR: event code of a VSE
This usage of HCI_VENDOR_PKT is wrongly checking an event code.
Fix by using HCI_EV_VENDOR for event code.
Also fix warning "CHECK: Unnecessary parentheses around comparison"
given by checkpatch.pl.
Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
drivers/bluetooth/hci_qca.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index bd29d422c209..f978087612ee 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -1240,8 +1240,8 @@ static int qca_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
* received we store dump into a file before closing hci. This
* dump will help in triaging the issues.
*/
- if ((skb->data[0] == HCI_VENDOR_PKT) &&
- (get_unaligned_be16(skb->data + 2) == QCA_SSR_DUMP_HANDLE))
+ if (skb->data[0] == HCI_EV_VENDOR &&
+ get_unaligned_be16(skb->data + 2) == QCA_SSR_DUMP_HANDLE)
return qca_controller_memdump_event(hdev, skb);
return hci_recv_frame(hdev, skb);
--
2.34.1
^ permalink raw reply related
* [PATCH] Bluetooth: btbcm: Add entry for BCM4356A3 UART bluetooth
From: Aaron Kling via B4 Relay @ 2026-07-17 21:40 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz
Cc: linux-bluetooth, linux-kernel, Aaron Kling
From: Aaron Kling <webgeek1234@gmail.com>
This patch adds the device ID for the bluetooth chip used in the
Nvidia specific Broadcom BCM4356 PCI-E WiFi / UART BT chip.
Signed-off-by: Aaron Kling <webgeek1234@gmail.com>
---
drivers/bluetooth/btbcm.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c
index 463d59890befe..14acea7325478 100644
--- a/drivers/bluetooth/btbcm.c
+++ b/drivers/bluetooth/btbcm.c
@@ -506,6 +506,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = {
{ 0x6606, "BCM4345C5" }, /* 003.006.006 */
{ 0x230f, "BCM4356A2" }, /* 001.003.015 */
{ 0x2310, "BCM4343A2" }, /* 001.003.016 */
+ { 0x2409, "BCM4356A3" }, /* 001.004.009 */
{ 0x220e, "BCM20702A1" }, /* 001.002.014 */
{ 0x420d, "BCM4349B1" }, /* 002.002.013 */
{ 0x420e, "BCM4349B1" }, /* 002.002.014 */
---
base-commit: 49362394dad7df66c274c867a271394c10ca2bb8
change-id: 20260717-bcm4356a3-bt-cd78cc0f42e8
Best regards,
--
Aaron Kling <webgeek1234@gmail.com>
^ permalink raw reply related
* RE: Bluetooth: HIDP: add missing length check for incoming frames
From: bluez.test.bot @ 2026-07-17 16:23 UTC (permalink / raw)
To: linux-bluetooth, yaojiale02
In-Reply-To: <20260717153238.2002330-1-yaojiale02@163.com>
[-- Attachment #1: Type: text/plain, Size: 2389 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=1129697
---Test result---
Test Summary:
CheckPatch PASS 0.58 seconds
VerifyFixes PASS 0.10 seconds
VerifySignedoff PASS 0.11 seconds
GitLint PASS 0.27 seconds
SubjectPrefix PASS 0.16 seconds
BuildKernel PASS 22.57 seconds
CheckAllWarning PASS 25.42 seconds
CheckSparse PASS 25.04 seconds
BuildKernel32 PASS 22.34 seconds
CheckKernelLLVM SKIP 0.00 seconds
TestRunnerSetup PASS 408.54 seconds
TestRunner_l2cap-tester PASS 56.29 seconds
TestRunner_iso-tester PASS 78.41 seconds
TestRunner_bnep-tester PASS 17.10 seconds
TestRunner_mgmt-tester FAIL 204.30 seconds
TestRunner_rfcomm-tester PASS 23.90 seconds
TestRunner_sco-tester PASS 30.72 seconds
TestRunner_ioctl-tester PASS 23.78 seconds
TestRunner_mesh-tester FAIL 23.76 seconds
TestRunner_smp-tester PASS 21.47 seconds
TestRunner_userchan-tester PASS 18.22 seconds
TestRunner_6lowpan-tester PASS 20.95 seconds
IncrementalBuild PASS 21.80 seconds
Details
##############################
Test: CheckKernelLLVM - SKIP
Desc: Build kernel with LLVM + context analysis
Output:
Clang not found
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
Total: 494, Passed: 489 (99.0%), Failed: 1, Not Run: 4
Failed Test Cases
Read Exp Feature - Success Failed 0.232 seconds
##############################
Test: TestRunner_mesh-tester - FAIL
Desc: Run mesh-tester with test-runner
Output:
Total: 10, Passed: 8 (80.0%), Failed: 2, Not Run: 0
Failed Test Cases
Mesh - Send cancel - 1 Timed out 1.977 seconds
Mesh - Send cancel - 2 Timed out 1.988 seconds
https://github.com/bluez/bluetooth-next/pull/450
---
Regards,
Linux Bluetooth
^ permalink raw reply
* Re: [PATCH] Bluetooth: MGMT: dequeue queued mesh send before freeing canceled tx
From: Cen Zhang @ 2026-07-17 15:55 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: Marcel Holtmann, linux-bluetooth, baijiaju1990
In-Reply-To: <CABBYNZKQKpt9gdJUYb6YS_6ryGZLjrofO0OEpu4jsvmA7f00uw@mail.gmail.com>
Hi Luiz,
Luiz Augusto von Dentz <luiz.dentz@gmail.com> 于2026年7月17日周五 23:50写道:
>
> If you really want to bump it just resend it. Sending pings like this
> won't retrigger the CI to pick it up and test it.
Thanks for the clarification. I'll resend it next week.
Best regards,
Cen Zhang
^ permalink raw reply
* Re: [PATCH] Bluetooth: MGMT: dequeue queued mesh send before freeing canceled tx
From: Luiz Augusto von Dentz @ 2026-07-17 15:50 UTC (permalink / raw)
To: Cen Zhang; +Cc: Marcel Holtmann, linux-bluetooth, baijiaju1990
In-Reply-To: <CAFRLqsVdaKE63gAKVuAjv++CM1z8hX1hYh6N3BxHkVaoyKnKVw@mail.gmail.com>
Hi Cen,
On Fri, Jul 17, 2026 at 11:46 AM Cen Zhang <zzzccc427@gmail.com> wrote:
>
> Hi Marcel, Luiz,
>
> Gentle ping on this patch.
>
> Could you please take a look when you have a chance?
If you really want to bump it just resend it. Sending pings like this
won't retrigger the CI to pick it up and test it.
> Thanks!
>
> Best regards,
> Cen Zhang
>
> Cen Zhang <zzzccc427@gmail.com> 于2026年7月3日周五 14:00写道:
> >
> > mesh_next() queues mesh_send_sync() with a raw mgmt_mesh_tx pointer after
> > a previous mesh send completes. MGMT_OP_MESH_SEND_CANCEL can already be
> > queued on the same hci_cmd_sync_work list. If cancel runs before the queued
> > send, it can remove and free the same mgmt_mesh_tx while mesh_send_sync()
> > still carries that pointer as callback data.
> >
> > The buggy scenario involves two paths, with each column showing the order
> > within that path:
> >
> > mesh completion path: cancel command path:
> > 1. mesh_send_done_sync() returns 1. send_cancel is already queued
> > 2. mesh_next() selects next_tx 2. send_cancel finds next_tx
> > 3. mesh_next() queues 3. send_cancel frees next_tx
> > mesh_send_sync(next_tx)
> > 4. mesh_send_sync() later
> > dereferences next_tx
> >
> > Validation reproduced this kernel report:
> > BUG: KASAN: slab-use-after-free in mesh_send_sync+0x5a/0x1c0 [bluetooth]
> > Read of size 1 at addr ffff88811a01d13b by task kworker/u17:0/562
> > Workqueue: hci0 hci_cmd_sync_work [bluetooth]
> >
> > Call Trace:
> > <TASK>
> > dump_stack_lvl+0x66/0xa0
> > print_report+0xce/0x5f0
> > ? mesh_send_sync+0x5a/0x1c0 [bluetooth]
> > ? __virt_addr_valid+0x19f/0x330
> > ? mesh_send_sync+0x5a/0x1c0 [bluetooth]
> > kasan_report+0xe0/0x110
> > ? mesh_send_sync+0x5a/0x1c0 [bluetooth]
> > ? __pfx_mesh_send_sync+0x10/0x10 [bluetooth]
> > mesh_send_sync+0x5a/0x1c0 [bluetooth]
> > ? mesh_send_sync+0x9/0x1c0 [bluetooth]
> > ? __pfx_mesh_send_sync+0x10/0x10 [bluetooth]
> > hci_cmd_sync_work+0x187/0x210 [bluetooth]
> > process_one_work+0x4fd/0xbc0
> > worker_thread+0x2d8/0x570
> > kthread+0x1ad/0x1f0
> > ret_from_fork+0x3c9/0x540
> > ret_from_fork_asm+0x1a/0x30
> >
> > Allocated by task 602:
> > kasan_save_stack+0x33/0x60
> > kasan_save_track+0x17/0x60
> > __kasan_kmalloc+0xaa/0xb0
> > mgmt_mesh_add+0x41/0x1a0 [bluetooth]
> > mesh_send+0x197/0x3a0 [bluetooth]
> > hci_sock_sendmsg+0x96b/0xf80 [bluetooth]
> > __sys_sendto+0x2bc/0x2d0
> > __x64_sys_sendto+0x76/0x90
> > do_syscall_64+0x115/0x6a0
> > entry_SYSCALL_64_after_hwframe+0x77/0x7f
> >
> > Freed by task 562:
> > kasan_save_stack+0x33/0x60
> > kasan_save_track+0x17/0x60
> > kasan_save_free_info+0x3b/0x60
> > __kasan_slab_free+0x5f/0x80
> > kfree+0x313/0x590
> > send_cancel+0x1d8/0x210 [bluetooth]
> > hci_cmd_sync_work+0x187/0x210 [bluetooth]
> > process_one_work+0x4fd/0xbc0
> > worker_thread+0x2d8/0x570
> > kthread+0x1ad/0x1f0
> > ret_from_fork+0x3c9/0x540
> > ret_from_fork_asm+0x1a/0x30
> >
> > Dequeue any queued mesh_send_sync() for the target tx from send_cancel().
> > When a queued send is found, the dequeue path invokes
> > mesh_send_start_complete(), which completes and frees the tx; send_cancel()
> > must not complete it again.
> >
> > Fixes: b338d91703fa ("Bluetooth: Implement support for Mesh")
> > Assisted-by: Codex:gpt-5.5
> > Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
> > ---
> > net/bluetooth/mgmt.c | 23 +++++++++++++++++------
> > 1 file changed, 17 insertions(+), 6 deletions(-)
> >
> > diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> > index 733a4b70e10c..ac4922cb39b5 100644
> > --- a/net/bluetooth/mgmt.c
> > +++ b/net/bluetooth/mgmt.c
> > @@ -2416,17 +2416,28 @@ static int send_cancel(struct hci_dev *hdev, void *data)
> > struct mgmt_mesh_tx *mesh_tx;
> >
> > if (!cancel->handle) {
> > - do {
> > + for (;;) {
> > mesh_tx = mgmt_mesh_next(hdev, cmd->sk);
> >
> > - if (mesh_tx)
> > - mesh_send_complete(hdev, mesh_tx, false);
> > - } while (mesh_tx);
> > + if (!mesh_tx)
> > + break;
> > +
> > + /* Dequeue any queued send before freeing the tx. */
> > + if (hci_cmd_sync_dequeue(hdev, mesh_send_sync, mesh_tx,
> > + mesh_send_start_complete))
> > + continue;
> > +
> > + mesh_send_complete(hdev, mesh_tx, false);
> > + }
> > } else {
> > mesh_tx = mgmt_mesh_find(hdev, cancel->handle);
> >
> > - if (mesh_tx && mesh_tx->sk == cmd->sk)
> > - mesh_send_complete(hdev, mesh_tx, false);
> > + if (mesh_tx && mesh_tx->sk == cmd->sk) {
> > + /* Dequeue any queued send before freeing the tx. */
> > + if (!hci_cmd_sync_dequeue(hdev, mesh_send_sync, mesh_tx,
> > + mesh_send_start_complete))
> > + mesh_send_complete(hdev, mesh_tx, false);
> > + }
> > }
> >
> > mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_MESH_SEND_CANCEL,
> > --
> > 2.43.0
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH] Bluetooth: MGMT: Fix ADD_EXT_ADV_DATA rollback of committed instances
From: Cen Zhang @ 2026-07-17 15:47 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz; +Cc: linux-bluetooth, baijiaju1990
In-Reply-To: <20260703060033.570932-1-zzzccc427@gmail.com>
Hi Marcel, Luiz,
Gentle ping on this patch.
Could you please take a look when you have a chance?
Thanks!
Best regards,
Cen Zhang
Cen Zhang <zzzccc427@gmail.com> 于2026年7月3日周五 14:00写道:
>
> add_ext_adv_data() uses clear_new_instance to roll back failures after
> preparing advertising data. That path is valid for a newly created pending
> instance, but a malformed ADD_EXT_ADV_DATA request can also reach it for
> an already committed advertising instance. In that case clear_new_instance
> frees the live adv_info while hci_cmd_sync_work() may still be using it.
>
> The buggy scenario involves two paths, with each column showing the order
> within that path:
>
> advertising enable path: ADD_EXT_ADV_DATA error path:
> 1. look up the committed adv_info 1. accept an update for that instance
> 2. wait for the controller 2. hit clear_new_instance on failure
> response 3. remove and free the live adv_info
> 3. resume and access adv_info
>
> Validation reproduced this kernel report:
> BUG: KASAN: slab-use-after-free in hci_enable_ext_advertising_sync+0x99/0x190 [bluetooth]
> Read of size 1 at addr ffff888104e3f010 by task kworker/u17:1/2502
> Workqueue: hci0 hci_cmd_sync_work [bluetooth]
>
> Call Trace:
> <TASK>
> dump_stack_lvl+0x66/0xa0
> print_report+0xce/0x5f0
> ? hci_enable_ext_advertising_sync+0x99/0x190 [bluetooth]
> ? __virt_addr_valid+0x19f/0x330
> ? hci_enable_ext_advertising_sync+0x99/0x190 [bluetooth]
> kasan_report+0xe0/0x110
> ? hci_enable_ext_advertising_sync+0x99/0x190 [bluetooth]
> ? __pfx_add_ext_adv_data_sync+0x10/0x10 [bluetooth]
> hci_enable_ext_advertising_sync+0x99/0x190 [bluetooth]
> ? __pfx_hci_enable_ext_advertising_sync+0x10/0x10 [bluetooth]
> hci_cmd_sync_work+0x187/0x210 [bluetooth]
> process_one_work+0x4fd/0xbc0
> worker_thread+0x2d8/0x570
> kthread+0x1ad/0x1f0
> ret_from_fork+0x3c9/0x540
> ret_from_fork_asm+0x1a/0x30
>
> Allocated by task 2515:
> kasan_save_stack+0x33/0x60
> kasan_save_track+0x17/0x60
> __kasan_kmalloc+0xaa/0xb0
> hci_add_adv_instance+0x35d/0x440 [bluetooth]
> add_ext_adv_params+0x291/0x510 [bluetooth]
> hci_sock_sendmsg+0x96b/0xf80 [bluetooth]
> __sys_sendto+0x2bc/0x2d0
> __x64_sys_sendto+0x76/0x90
> do_syscall_64+0x115/0x6a0
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
>
> Freed by task 2515:
> kasan_save_stack+0x33/0x60
> kasan_save_track+0x17/0x60
> kasan_save_free_info+0x3b/0x60
> __kasan_slab_free+0x5f/0x80
> kfree+0x313/0x590
> hci_remove_adv_instance+0x130/0x1b0 [bluetooth]
> add_ext_adv_data+0x263/0x640 [bluetooth]
> hci_sock_sendmsg+0x96b/0xf80 [bluetooth]
> __sys_sendto+0x2bc/0x2d0
> __x64_sys_sendto+0x76/0x90
> do_syscall_64+0x115/0x6a0
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
>
> Only pending instances should be rolled back from ADD_EXT_ADV_DATA
> failures. Leave committed instances in place so queued controller work
> cannot retain a freed adv_info pointer.
>
> Fixes: 12410572833a2 ("Bluetooth: Break add adv into two mgmt commands")
> Assisted-by: Codex:gpt-5.5
> Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
> ---
> net/bluetooth/mgmt.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> index 733a4b70e10c..a4126d616efa 100644
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -9220,7 +9220,8 @@ static int add_ext_adv_data(struct sock *sk, struct hci_dev *hdev, void *data,
> goto unlock;
>
> clear_new_instance:
> - hci_remove_adv_instance(hdev, cp->instance);
> + if (adv_instance->pending)
> + hci_remove_adv_instance(hdev, cp->instance);
>
> unlock:
> hci_dev_unlock(hdev);
> --
> 2.43.0
>
^ permalink raw reply
* Re: [PATCH v2] Bluetooth: hci_debugfs: serialize force_bredr_smp writes
From: Cen Zhang @ 2026-07-17 15:46 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz; +Cc: linux-bluetooth, baijiaju1990
In-Reply-To: <20260703081431.922054-1-zzzccc427@gmail.com>
Hi Marcel, Luiz,
Gentle ping on this patch.
Could you please take a look when you have a chance?
Thanks!
Best regards,
Cen Zhang
Cen Zhang <zzzccc427@gmail.com> 于2026年7月3日周五 16:14写道:
>
> force_bredr_smp_write() calls smp_force_bredr() without hci_dev_lock().
> That helper checks HCI_FORCE_BREDR_SMP, updates hdev->smp_bredr_data,
> and then toggles the force flag.
>
> Two same-value writers can both pass the state check and run the same
> enable or disable transition on one hdev. On the disable side, one writer
> can clear hdev->smp_bredr_data while the other still observes the old
> force flag and later passes NULL into smp_del_chan(). The double
> transition can also leave the force flag out of sync with the requested
> state.
>
> Take hci_dev_lock() around smp_force_bredr() in the debugfs write path so
> each request observes and applies one stable BR/EDR SMP transition.
>
> Validation reproduced this kernel report:
>
> KASAN null-ptr-deref in smp_del_chan+0x31/0x90
> RIP: 0033:0x7faae680d340
> RIP: 0010:smp_del_chan+0x31/0x90 [bluetooth]
> Read of size 8
> Call Trace:
> dump_stack_lvl+0x66/0xa0
> kasan_report+0xe0/0x110
> smp_del_chan+0x31/0x90
> smp_force_bredr+0x69/0xc0
> trace_clock_x86_tsc+0x20/0x20
> srso_alias_return_thunk+0x5/0xfbef5
> lock_acquire+0xd0/0x300
> ksys_write+0xd2/0x170
> full_proxy_write+0x9e/0xd0
> vfs_write+0x1b0/0x810
> find_held_lock+0x2b/0x80
> do_user_addr_fault+0x65a/0x890
> rcu_is_watching+0x20/0x50
> do_syscall_64+0x115/0x6a0 (arch/x86/entry/syscall_64.c:87)
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
>
> Fixes: 300acfdec916 ("Bluetooth: Introduce force_bredr_smp debugfs option for testing")
> Assisted-by: Codex:gpt-5.5
> Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
> ---
> v2:
> - Reword commit message to avoid checkpatch's 75-character line warning.
>
> net/bluetooth/hci_debugfs.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c
> index b7f682922a16..ff344564c923 100644
> --- a/net/bluetooth/hci_debugfs.c
> +++ b/net/bluetooth/hci_debugfs.c
> @@ -520,7 +520,9 @@ static ssize_t force_bredr_smp_write(struct file *file,
> if (err)
> return err;
>
> + hci_dev_lock(hdev);
> err = smp_force_bredr(hdev, enable);
> + hci_dev_unlock(hdev);
> if (err)
> return err;
>
> --
> 2.43.0
^ permalink raw reply
* Re: [PATCH] Bluetooth: MGMT: dequeue queued mesh send before freeing canceled tx
From: Cen Zhang @ 2026-07-17 15:46 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz; +Cc: linux-bluetooth, baijiaju1990
In-Reply-To: <20260703060024.570535-1-zzzccc427@gmail.com>
Hi Marcel, Luiz,
Gentle ping on this patch.
Could you please take a look when you have a chance?
Thanks!
Best regards,
Cen Zhang
Cen Zhang <zzzccc427@gmail.com> 于2026年7月3日周五 14:00写道:
>
> mesh_next() queues mesh_send_sync() with a raw mgmt_mesh_tx pointer after
> a previous mesh send completes. MGMT_OP_MESH_SEND_CANCEL can already be
> queued on the same hci_cmd_sync_work list. If cancel runs before the queued
> send, it can remove and free the same mgmt_mesh_tx while mesh_send_sync()
> still carries that pointer as callback data.
>
> The buggy scenario involves two paths, with each column showing the order
> within that path:
>
> mesh completion path: cancel command path:
> 1. mesh_send_done_sync() returns 1. send_cancel is already queued
> 2. mesh_next() selects next_tx 2. send_cancel finds next_tx
> 3. mesh_next() queues 3. send_cancel frees next_tx
> mesh_send_sync(next_tx)
> 4. mesh_send_sync() later
> dereferences next_tx
>
> Validation reproduced this kernel report:
> BUG: KASAN: slab-use-after-free in mesh_send_sync+0x5a/0x1c0 [bluetooth]
> Read of size 1 at addr ffff88811a01d13b by task kworker/u17:0/562
> Workqueue: hci0 hci_cmd_sync_work [bluetooth]
>
> Call Trace:
> <TASK>
> dump_stack_lvl+0x66/0xa0
> print_report+0xce/0x5f0
> ? mesh_send_sync+0x5a/0x1c0 [bluetooth]
> ? __virt_addr_valid+0x19f/0x330
> ? mesh_send_sync+0x5a/0x1c0 [bluetooth]
> kasan_report+0xe0/0x110
> ? mesh_send_sync+0x5a/0x1c0 [bluetooth]
> ? __pfx_mesh_send_sync+0x10/0x10 [bluetooth]
> mesh_send_sync+0x5a/0x1c0 [bluetooth]
> ? mesh_send_sync+0x9/0x1c0 [bluetooth]
> ? __pfx_mesh_send_sync+0x10/0x10 [bluetooth]
> hci_cmd_sync_work+0x187/0x210 [bluetooth]
> process_one_work+0x4fd/0xbc0
> worker_thread+0x2d8/0x570
> kthread+0x1ad/0x1f0
> ret_from_fork+0x3c9/0x540
> ret_from_fork_asm+0x1a/0x30
>
> Allocated by task 602:
> kasan_save_stack+0x33/0x60
> kasan_save_track+0x17/0x60
> __kasan_kmalloc+0xaa/0xb0
> mgmt_mesh_add+0x41/0x1a0 [bluetooth]
> mesh_send+0x197/0x3a0 [bluetooth]
> hci_sock_sendmsg+0x96b/0xf80 [bluetooth]
> __sys_sendto+0x2bc/0x2d0
> __x64_sys_sendto+0x76/0x90
> do_syscall_64+0x115/0x6a0
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
>
> Freed by task 562:
> kasan_save_stack+0x33/0x60
> kasan_save_track+0x17/0x60
> kasan_save_free_info+0x3b/0x60
> __kasan_slab_free+0x5f/0x80
> kfree+0x313/0x590
> send_cancel+0x1d8/0x210 [bluetooth]
> hci_cmd_sync_work+0x187/0x210 [bluetooth]
> process_one_work+0x4fd/0xbc0
> worker_thread+0x2d8/0x570
> kthread+0x1ad/0x1f0
> ret_from_fork+0x3c9/0x540
> ret_from_fork_asm+0x1a/0x30
>
> Dequeue any queued mesh_send_sync() for the target tx from send_cancel().
> When a queued send is found, the dequeue path invokes
> mesh_send_start_complete(), which completes and frees the tx; send_cancel()
> must not complete it again.
>
> Fixes: b338d91703fa ("Bluetooth: Implement support for Mesh")
> Assisted-by: Codex:gpt-5.5
> Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
> ---
> net/bluetooth/mgmt.c | 23 +++++++++++++++++------
> 1 file changed, 17 insertions(+), 6 deletions(-)
>
> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> index 733a4b70e10c..ac4922cb39b5 100644
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -2416,17 +2416,28 @@ static int send_cancel(struct hci_dev *hdev, void *data)
> struct mgmt_mesh_tx *mesh_tx;
>
> if (!cancel->handle) {
> - do {
> + for (;;) {
> mesh_tx = mgmt_mesh_next(hdev, cmd->sk);
>
> - if (mesh_tx)
> - mesh_send_complete(hdev, mesh_tx, false);
> - } while (mesh_tx);
> + if (!mesh_tx)
> + break;
> +
> + /* Dequeue any queued send before freeing the tx. */
> + if (hci_cmd_sync_dequeue(hdev, mesh_send_sync, mesh_tx,
> + mesh_send_start_complete))
> + continue;
> +
> + mesh_send_complete(hdev, mesh_tx, false);
> + }
> } else {
> mesh_tx = mgmt_mesh_find(hdev, cancel->handle);
>
> - if (mesh_tx && mesh_tx->sk == cmd->sk)
> - mesh_send_complete(hdev, mesh_tx, false);
> + if (mesh_tx && mesh_tx->sk == cmd->sk) {
> + /* Dequeue any queued send before freeing the tx. */
> + if (!hci_cmd_sync_dequeue(hdev, mesh_send_sync, mesh_tx,
> + mesh_send_start_complete))
> + mesh_send_complete(hdev, mesh_tx, false);
> + }
> }
>
> mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_MESH_SEND_CANCEL,
> --
> 2.43.0
^ permalink raw reply
* Re: [PATCH BlueZ v1 2/2] profiles/ranging: Add D-Bus ProcedureData signal for Channel Sounding
From: Luiz Augusto von Dentz @ 2026-07-17 15:44 UTC (permalink / raw)
To: Prathibha Madugonde
Cc: linux-bluetooth, quic_mohamull, quic_hbandi, quic_anubhavg
In-Reply-To: <CABBYNZL1rf4LbLNiese8DwRBMMgtCps-VH-nNCbZ9G1Xu=1RBQ@mail.gmail.com>
Hi,
On Fri, Jul 17, 2026 at 11:17 AM Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
>
> Hi.
>
> On Fri, Jul 17, 2026 at 11:07 AM Luiz Augusto von Dentz
> <luiz.dentz@gmail.com> wrote:
> >
> > Hi Prathibha,
> >
> > On Fri, Jul 17, 2026 at 3:27 AM Prathibha Madugonde
> > <prathibha.madugonde@oss.qualcomm.com> wrote:
> > >
> > > From: Prathibha Madugonde <prathibha.madugonde@oss.qualcomm.com>
> > >
> > > Marshal bcs_procedure_data (subevents, steps, mode 0/1/2/3 results,
> > > and CS/procedure-enable config) into an a{sv} dictionary and emit it
> > > as a new ProcedureData signal on the CS D-Bus interface.
> >
> > Was this documented though? It doesn't seem to follow the likes of
> > https://github.com/bluez/bluez/blob/master/doc/org.bluez.ChannelSounding1.rst,
> > for instance we don't use camel case for dictionary options. Also, if
> > this is a result of `StartMeasurement`, we should probably signal it
> > as Results or something like that, but I'd start with documentation so
> > we can agree on the overall design.
>
> Ok, looks like this does follow the documentation already:
>
> https://github.com/bluez/bluez/blob/master/doc/org.bluez.ChannelSounding1.rst#void-proceduredatadict-data
>
> That said that will probably need updating since some dictionaries use
> camel case and others don't, so this needs to converge to a single
> format.
I chatted with Marcel, and we concluded this should probably go as a
data blob since the fields are somewhat analog and meaningless
individually, packing it into a dictionary just to unpack it later is
useless.
> > > Register a procedure_data callback on the RAP HCI state machine so
> > > rap.c is notified when a procedure completes, and propagate the
> > > locally supported T_SW time capability from the read-local-supported-
> > > capabilities response into bt_rap.
> > >
> > > ---
> > > profiles/ranging/rap.c | 497 ++++++++++++++++++++++++++++++++++++-
> > > profiles/ranging/rap_hci.c | 59 +++++
> > > 2 files changed, 555 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/profiles/ranging/rap.c b/profiles/ranging/rap.c
> > > index 3ffc0da76..42e1ef2a4 100644
> > > --- a/profiles/ranging/rap.c
> > > +++ b/profiles/ranging/rap.c
> > > @@ -379,6 +379,492 @@ static const struct cs_dict_param_desc *cs_find_dict_param_desc(
> > > return NULL;
> > > }
> > >
> > > +static void dict_append_byte(DBusMessageIter *dict, const char *key,
> > > + uint8_t val)
> > > +{
> > > + DBusMessageIter entry, variant;
> > > +
> > > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > > + &entry);
> > > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "y",
> > > + &variant);
> > > + dbus_message_iter_append_basic(&variant, DBUS_TYPE_BYTE, &val);
> > > + dbus_message_iter_close_container(&entry, &variant);
> > > + dbus_message_iter_close_container(dict, &entry);
> > > +}
> > > +
> > > +static void dict_append_int32(DBusMessageIter *dict, const char *key,
> > > + dbus_int32_t val)
> > > +{
> > > + DBusMessageIter entry, variant;
> > > +
> > > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > > + &entry);
> > > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "i",
> > > + &variant);
> > > + dbus_message_iter_append_basic(&variant, DBUS_TYPE_INT32, &val);
> > > + dbus_message_iter_close_container(&entry, &variant);
> > > + dbus_message_iter_close_container(dict, &entry);
> > > +}
> > > +
> > > +static void dict_append_uint32(DBusMessageIter *dict, const char *key,
> > > + dbus_uint32_t val)
> > > +{
> > > + DBusMessageIter entry, variant;
> > > +
> > > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > > + &entry);
> > > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "u",
> > > + &variant);
> > > + dbus_message_iter_append_basic(&variant, DBUS_TYPE_UINT32, &val);
> > > + dbus_message_iter_close_container(&entry, &variant);
> > > + dbus_message_iter_close_container(dict, &entry);
> > > +}
> > > +
> > > +static void dict_append_uint64(DBusMessageIter *dict, const char *key,
> > > + dbus_uint64_t val)
> > > +{
> > > + DBusMessageIter entry, variant;
> > > +
> > > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > > + &entry);
> > > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "t",
> > > + &variant);
> > > + dbus_message_iter_append_basic(&variant, DBUS_TYPE_UINT64, &val);
> > > + dbus_message_iter_close_container(&entry, &variant);
> > > + dbus_message_iter_close_container(dict, &entry);
> > > +}
> > > +
> > > +static void dict_append_byte_array(DBusMessageIter *dict, const char *key,
> > > + const uint8_t *data, int len)
> > > +{
> > > + DBusMessageIter entry, variant, arr;
> > > + int i;
> > > +
> > > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > > + &entry);
> > > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "ay",
> > > + &variant);
> > > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "y", &arr);
> > > + for (i = 0; i < len; i++)
> > > + dbus_message_iter_append_basic(&arr, DBUS_TYPE_BYTE, &data[i]);
> > > + dbus_message_iter_close_container(&variant, &arr);
> > > + dbus_message_iter_close_container(&entry, &variant);
> > > + dbus_message_iter_close_container(dict, &entry);
> > > +}
> > > +
> > > +static void append_mode_zero(DBusMessageIter *dict,
> > > + const struct cs_mode_zero_data *m0)
> > > +{
> > > + dict_append_byte(dict, "packetQuality", m0->packet_quality);
> > > + dict_append_byte(dict, "packetRssiDbm", m0->packet_rssi_dbm);
> > > + dict_append_byte(dict, "packetAntenna", m0->packet_ant);
> > > + dict_append_int32(dict, "initiatorMeasuredFreqOffset",
> > > + (dbus_int32_t)m0->init_measured_freq_offset);
> > > +}
> > > +
> > > +static void append_pct_iq_pair(DBusMessageIter *dict, const char *key,
> > > + const struct pct_iq_sample *pct)
> > > +{
> > > + DBusMessageIter entry, variant, arr;
> > > + dbus_int32_t i_s = pct->i_sample;
> > > + dbus_int32_t q_s = pct->q_sample;
> > > +
> > > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > > + &entry);
> > > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "ai",
> > > + &variant);
> > > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "i", &arr);
> > > + dbus_message_iter_append_basic(&arr, DBUS_TYPE_INT32, &i_s);
> > > + dbus_message_iter_append_basic(&arr, DBUS_TYPE_INT32, &q_s);
> > > + dbus_message_iter_close_container(&variant, &arr);
> > > + dbus_message_iter_close_container(&entry, &variant);
> > > + dbus_message_iter_close_container(dict, &entry);
> > > +}
> > > +
> > > +static void append_mode_one(DBusMessageIter *dict,
> > > + const struct cs_mode_one_data *m1)
> > > +{
> > > + dict_append_byte(dict, "packetQuality", m1->packet_quality);
> > > + dict_append_byte(dict, "packetNadm", m1->packet_nadm);
> > > + dict_append_byte(dict, "packetRssiDbm", m1->packet_rssi_dbm);
> > > + dict_append_int32(dict, "toaTodInitiator",
> > > + (dbus_int32_t)m1->toa_tod_init);
> > > + dict_append_int32(dict, "todToaReflector",
> > > + (dbus_int32_t)m1->tod_toa_refl);
> > > + dict_append_byte(dict, "packetAntenna", m1->packet_ant);
> > > + append_pct_iq_pair(dict, "packetPct1", &m1->packet_pct1);
> > > + append_pct_iq_pair(dict, "packetPct2", &m1->packet_pct2);
> > > +}
> > > +
> > > +static void append_mode_two(DBusMessageIter *dict,
> > > + const struct cs_mode_two_data *m2,
> > > + uint8_t num_ant_paths)
> > > +{
> > > + DBusMessageIter entry, variant, arr;
> > > + const char *key;
> > > + int j;
> > > + int num_paths;
> > > +
> > > + /*
> > > + * num_ant_paths is the HCI "number of antenna paths" value
> > > + * (0-indexed), so actual tone sample count = num_ant_paths + 1,
> > > + * capped at array size.
> > > + */
> > > + num_paths = (num_ant_paths + 1) < CS_MAX_ANT_PATHS ?
> > > + (num_ant_paths + 1) : CS_MAX_ANT_PATHS;
> > > +
> > > + dict_append_byte(dict, "antennaPermutationIndex", m2->ant_perm_index);
> > > +
> > > + /* tonePctIQSamples: interleaved (i,q) pairs as "ai" */
> > > + key = "tonePctIQSamples";
> > > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > > + &entry);
> > > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "ai",
> > > + &variant);
> > > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "i", &arr);
> > > + for (j = 0; j < num_paths; j++) {
> > > + dbus_int32_t i_s = m2->tone_pct[j].i_sample;
> > > + dbus_int32_t q_s = m2->tone_pct[j].q_sample;
> > > +
> > > + dbus_message_iter_append_basic(&arr, DBUS_TYPE_INT32, &i_s);
> > > + dbus_message_iter_append_basic(&arr, DBUS_TYPE_INT32, &q_s);
> > > + }
> > > + dbus_message_iter_close_container(&variant, &arr);
> > > + dbus_message_iter_close_container(&entry, &variant);
> > > + dbus_message_iter_close_container(dict, &entry);
> > > +
> > > + /* toneQualityIndicators: "ay" */
> > > + key = "toneQualityIndicators";
> > > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > > + &entry);
> > > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "ay",
> > > + &variant);
> > > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "y", &arr);
> > > + for (j = 0; j < num_paths; j++) {
> > > + uint8_t tqi = m2->tone_quality_indicator[j];
> > > +
> > > + dbus_message_iter_append_basic(&arr, DBUS_TYPE_BYTE, &tqi);
> > > + }
> > > + dbus_message_iter_close_container(&variant, &arr);
> > > + dbus_message_iter_close_container(&entry, &variant);
> > > + dbus_message_iter_close_container(dict, &entry);
> > > +}
> > > +
> > > +static void append_proc_enable_config(DBusMessageIter *outer_dict,
> > > + const struct rap_ev_cs_proc_enable_cmplt *cfg)
> > > +{
> > > + DBusMessageIter entry, variant, inner;
> > > + const char *key = "procedureEnableConfig";
> > > + dbus_uint32_t sub_evt_len_us;
> > > +
> > > + sub_evt_len_us = cfg->sub_evt_len[0] |
> > > + ((uint32_t)cfg->sub_evt_len[1] << 8) |
> > > + ((uint32_t)cfg->sub_evt_len[2] << 16);
> > > +
> > > + dbus_message_iter_open_container(outer_dict, DBUS_TYPE_DICT_ENTRY,
> > > + NULL, &entry);
> > > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "a{sv}",
> > > + &variant);
> > > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "{sv}",
> > > + &inner);
> > > +
> > > + dict_append_byte(&inner, "toneAntennaConfigSelection",
> > > + cfg->tone_ant_config_sel);
> > > + dict_append_uint32(&inner, "subeventLenUs", sub_evt_len_us);
> > > + dict_append_byte(&inner, "subeventsPerEvent", cfg->sub_evts_per_evt);
> > > + dict_append_uint32(&inner, "subeventInterval", cfg->sub_evt_intrvl);
> > > + dict_append_uint32(&inner, "eventInterval", cfg->evt_intrvl);
> > > + dict_append_uint32(&inner, "procedureInterval", cfg->proc_intrvl);
> > > + dict_append_uint32(&inner, "procedureCount", cfg->proc_counter);
> > > + dict_append_uint32(&inner, "maxProcedureLen", cfg->max_proc_len);
> > > +
> > > + dbus_message_iter_close_container(&variant, &inner);
> > > + dbus_message_iter_close_container(&entry, &variant);
> > > + dbus_message_iter_close_container(outer_dict, &entry);
> > > +}
> > > +
> > > +static void append_cs_config_param(DBusMessageIter *outer_dict,
> > > + const struct bcs_procedure_data *bcs)
> > > +{
> > > + DBusMessageIter entry, variant, inner;
> > > + const char *key = "csConfigParam";
> > > + const struct rap_ev_cs_config_cmplt *cfg = &bcs->cs_config;
> > > +
> > > + dbus_message_iter_open_container(outer_dict, DBUS_TYPE_DICT_ENTRY,
> > > + NULL, &entry);
> > > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "a{sv}",
> > > + &variant);
> > > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "{sv}",
> > > + &inner);
> > > +
> > > + dict_append_byte(&inner, "modeType", cfg->main_mode_type);
> > > + dict_append_byte(&inner, "subModeType", cfg->sub_mode_type);
> > > + dict_append_byte(&inner, "rttType", cfg->rtt_type);
> > > + dict_append_byte_array(&inner, "channelMap", cfg->channel_map,
> > > + sizeof(cfg->channel_map));
> > > + dict_append_byte(&inner, "minMainModeSteps", cfg->min_main_mode_steps);
> > > + dict_append_byte(&inner, "maxMainModeSteps", cfg->max_main_mode_steps);
> > > + dict_append_byte(&inner, "mainModeRepetition", cfg->main_mode_rep);
> > > + dict_append_byte(&inner, "mode0Steps", cfg->mode_0_steps);
> > > + dict_append_byte(&inner, "role", cfg->role);
> > > + dict_append_byte(&inner, "csSyncPhyType", cfg->cs_sync_phy);
> > > + dict_append_byte(&inner, "channelSelectionType", cfg->channel_sel_type);
> > > + dict_append_byte(&inner, "ch3cShapeType", cfg->ch3c_shape);
> > > + dict_append_byte(&inner, "ch3cJump", cfg->ch3c_jump);
> > > + dict_append_byte(&inner, "channelMapRepetition", cfg->channel_map_rep);
> > > + dict_append_byte(&inner, "tIp1TimeUs", cfg->t_ip1_time);
> > > + dict_append_byte(&inner, "tIp2TimeUs", cfg->t_ip2_time);
> > > + dict_append_byte(&inner, "tFcsTimeUs", cfg->t_fcs_time);
> > > + dict_append_byte(&inner, "tPmTimeUs", cfg->t_pm_time);
> > > + dict_append_byte(&inner, "tSwTimeUsSupportedByLocal",
> > > + bcs->t_sw_time_us_supported_by_local);
> > > + dict_append_byte(&inner, "tSwTimeUsSupportedByRemote",
> > > + bcs->t_sw_time_us_supported_by_remote);
> > > + dict_append_uint32(&inner, "bleConnInterval", bcs->ble_conn_interval);
> > > +
> > > + dbus_message_iter_close_container(&variant, &inner);
> > > + dbus_message_iter_close_container(&entry, &variant);
> > > + dbus_message_iter_close_container(outer_dict, &entry);
> > > +}
> > > +
> > > +static void append_step_to_dict(DBusMessageIter *dict,
> > > + const struct cs_step_data *step,
> > > + uint8_t num_ant_paths)
> > > +{
> > > + DBusMessageIter entry, variant, inner;
> > > + const char *mode_key;
> > > +
> > > + dict_append_byte(dict, "stepMode", step->step_mode);
> > > + dict_append_byte(dict, "stepChannel", step->step_chnl);
> > > +
> > > + switch (step->step_mode) {
> > > + case CS_MODE_ZERO:
> > > + mode_key = "modeZeroData";
> > > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
> > > + NULL, &entry);
> > > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
> > > + &mode_key);
> > > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
> > > + "a{sv}", &variant);
> > > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
> > > + "{sv}", &inner);
> > > + append_mode_zero(&inner,
> > > + &step->step_mode_data.mode_zero_data);
> > > + dbus_message_iter_close_container(&variant, &inner);
> > > + dbus_message_iter_close_container(&entry, &variant);
> > > + dbus_message_iter_close_container(dict, &entry);
> > > + break;
> > > +
> > > + case CS_MODE_ONE:
> > > + mode_key = "modeOneData";
> > > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
> > > + NULL, &entry);
> > > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
> > > + &mode_key);
> > > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
> > > + "a{sv}", &variant);
> > > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
> > > + "{sv}", &inner);
> > > + append_mode_one(&inner,
> > > + &step->step_mode_data.mode_one_data);
> > > + dbus_message_iter_close_container(&variant, &inner);
> > > + dbus_message_iter_close_container(&entry, &variant);
> > > + dbus_message_iter_close_container(dict, &entry);
> > > + break;
> > > +
> > > + case CS_MODE_TWO:
> > > + mode_key = "modeTwoData";
> > > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
> > > + NULL, &entry);
> > > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
> > > + &mode_key);
> > > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
> > > + "a{sv}", &variant);
> > > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
> > > + "{sv}", &inner);
> > > + append_mode_two(&inner,
> > > + &step->step_mode_data.mode_two_data,
> > > + num_ant_paths);
> > > + dbus_message_iter_close_container(&variant, &inner);
> > > + dbus_message_iter_close_container(&entry, &variant);
> > > + dbus_message_iter_close_container(dict, &entry);
> > > + break;
> > > +
> > > + case CS_MODE_THREE:
> > > + mode_key = "modeThreeData";
> > > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
> > > + NULL, &entry);
> > > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
> > > + &mode_key);
> > > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
> > > + "a{sv}", &variant);
> > > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
> > > + "{sv}", &inner);
> > > + append_mode_one(&inner,
> > > + &step->step_mode_data.mode_three_data.mode_one_data);
> > > + append_mode_two(&inner,
> > > + &step->step_mode_data.mode_three_data.mode_two_data,
> > > + num_ant_paths);
> > > + dbus_message_iter_close_container(&variant, &inner);
> > > + dbus_message_iter_close_container(&entry, &variant);
> > > + dbus_message_iter_close_container(dict, &entry);
> > > + break;
> > > +
> > > + default:
> > > + break;
> > > + }
> > > +}
> > > +
> > > +static void append_subevent_to_dict(DBusMessageIter *dict,
> > > + const struct cs_subevent_result_data *sub)
> > > +{
> > > + DBusMessageIter entry, variant, arr;
> > > + const char *key;
> > > + uint32_t i;
> > > +
> > > + dict_append_int32(dict, "startAclConnEvtCounter",
> > > + (dbus_int32_t)sub->start_acl_conn_evt_counter);
> > > + dict_append_int32(dict, "freqComp", (dbus_int32_t)sub->freq_comp);
> > > + dict_append_byte(dict, "refPwrLvl", (uint8_t)sub->ref_pwr_lvl);
> > > + dict_append_byte(dict, "numAntPaths", sub->num_ant_paths);
> > > + dict_append_byte(dict, "subeventAbortReason",
> > > + sub->subevent_abort_reason);
> > > + dict_append_uint64(dict, "timestampNanos", sub->timestamp_nanos);
> > > + dict_append_uint32(dict, "numSteps", sub->num_steps);
> > > +
> > > + /* stepData: av (each element is a{sv}) */
> > > + key = "stepData";
> > > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > > + &entry);
> > > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "av",
> > > + &variant);
> > > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "v", &arr);
> > > + if (sub->step_data) {
> > > + for (i = 0; i < sub->num_steps; i++) {
> > > + DBusMessageIter inner, step_dict;
> > > +
> > > + dbus_message_iter_open_container(&arr,
> > > + DBUS_TYPE_VARIANT, "a{sv}", &inner);
> > > + dbus_message_iter_open_container(&inner,
> > > + DBUS_TYPE_ARRAY, "{sv}", &step_dict);
> > > + append_step_to_dict(&step_dict, &sub->step_data[i],
> > > + sub->num_ant_paths);
> > > + dbus_message_iter_close_container(&inner, &step_dict);
> > > + dbus_message_iter_close_container(&arr, &inner);
> > > + }
> > > + }
> > > + dbus_message_iter_close_container(&variant, &arr);
> > > + dbus_message_iter_close_container(&entry, &variant);
> > > + dbus_message_iter_close_container(dict, &entry);
> > > +}
> > > +
> > > +static void append_subevent_array(DBusMessageIter *outer_dict,
> > > + const char *key,
> > > + const struct cs_subevent_result_data *subevents,
> > > + uint32_t count)
> > > +{
> > > + DBusMessageIter entry, variant, arr;
> > > + uint32_t i;
> > > +
> > > + dbus_message_iter_open_container(outer_dict, DBUS_TYPE_DICT_ENTRY,
> > > + NULL, &entry);
> > > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "av",
> > > + &variant);
> > > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "v", &arr);
> > > + for (i = 0; i < count; i++) {
> > > + DBusMessageIter inner, sub_dict;
> > > +
> > > + dbus_message_iter_open_container(&arr, DBUS_TYPE_VARIANT,
> > > + "a{sv}", &inner);
> > > + dbus_message_iter_open_container(&inner, DBUS_TYPE_ARRAY,
> > > + "{sv}", &sub_dict);
> > > + append_subevent_to_dict(&sub_dict, &subevents[i]);
> > > + dbus_message_iter_close_container(&inner, &sub_dict);
> > > + dbus_message_iter_close_container(&arr, &inner);
> > > + }
> > > + dbus_message_iter_close_container(&variant, &arr);
> > > + dbus_message_iter_close_container(&entry, &variant);
> > > + dbus_message_iter_close_container(outer_dict, &entry);
> > > +}
> > > +
> > > +static void rap_emit_procedure_data(struct rap_data *data,
> > > + const struct bcs_procedure_data *bcs)
> > > +{
> > > + DBusMessage *signal;
> > > + DBusMessageIter iter, dict;
> > > +
> > > + signal = dbus_message_new_signal(device_get_path(data->device),
> > > + CS_INTERFACE, "ProcedureData");
> > > + if (!signal) {
> > > + error("Failed to allocate ProcedureData signal");
> > > + return;
> > > + }
> > > +
> > > + dbus_message_iter_init_append(signal, &iter);
> > > + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
> > > +
> > > + dict_append_int32(&dict, "procedureCounter",
> > > + (dbus_int32_t)bcs->procedure_counter);
> > > + dict_append_int32(&dict, "procedureSequence",
> > > + (dbus_int32_t)bcs->procedure_sequence);
> > > + dict_append_byte(&dict, "initiatorSelectedTxPower",
> > > + (uint8_t)bcs->initiator_selected_tx_power);
> > > + dict_append_byte(&dict, "reflectorSelectedTxPower",
> > > + (uint8_t)bcs->reflector_selected_tx_power);
> > > +
> > > + dict_append_uint32(&dict, "initiatorSubeventCount",
> > > + bcs->initiator_subevent_count);
> > > + if (bcs->initiator_subevent_results &&
> > > + bcs->initiator_subevent_count > 0)
> > > + append_subevent_array(&dict, "initiatorSubeventResults",
> > > + bcs->initiator_subevent_results,
> > > + bcs->initiator_subevent_count);
> > > +
> > > + dict_append_byte(&dict, "initiatorProcedureAbortReason",
> > > + bcs->initiator_procedure_abort_reason);
> > > +
> > > + dict_append_uint32(&dict, "reflectorSubeventCount",
> > > + bcs->reflector_subevent_count);
> > > + if (bcs->reflector_subevent_results &&
> > > + bcs->reflector_subevent_count > 0)
> > > + append_subevent_array(&dict, "reflectorSubeventResults",
> > > + bcs->reflector_subevent_results,
> > > + bcs->reflector_subevent_count);
> > > +
> > > + dict_append_byte(&dict, "reflectorProcedureAbortReason",
> > > + bcs->reflector_procedure_abort_reason);
> > > +
> > > + append_proc_enable_config(&dict, &bcs->proc_enable_config);
> > > + append_cs_config_param(&dict, bcs);
> > > +
> > > + dbus_message_iter_close_container(&iter, &dict);
> > > +
> > > + g_dbus_send_message(btd_get_dbus_connection(), signal);
> > > +}
> > > +
> > > +static void rap_procedure_data(struct bt_rap *rap,
> > > + struct bcs_procedure_data *bcs,
> > > + void *user_data)
> > > +{
> > > + struct rap_data *data = user_data;
> > > +
> > > + DBG("procedure_counter=%u", bcs->procedure_counter);
> > > + rap_emit_procedure_data(data, bcs);
> > > +}
> > > +
> > > static DBusMessage *start_measurement(DBusConnection *conn,
> > > DBusMessage *msg, void *user_data)
> > > {
> > > @@ -534,6 +1020,9 @@ bad_type:
> > > data->active_session.cfg = cfg;
> > > data->active_session.freq = freq;
> > >
> > > + bt_rap_hci_set_procedure_data_cb(data->hci_sm, rap_procedure_data,
> > > + data, NULL);
> > > +
> > > return dbus_message_new_method_return(msg);
> > > }
> > >
> > > @@ -588,6 +1077,11 @@ static const GDBusPropertyTable cs_dbus_properties[] = {
> > > { }
> > > };
> > >
> > > +static const GDBusSignalTable cs_dbus_signals[] = {
> > > + { GDBUS_SIGNAL("ProcedureData", GDBUS_ARGS({ "data", "a{sv}" })) },
> > > + { }
> > > +};
> > > +
> > > static void rap_measurement_timeout_cb(void *user_data)
> > > {
> > > struct rap_data *data = user_data;
> > > @@ -752,7 +1246,8 @@ static int rap_accept(struct btd_service *service)
> > > g_dbus_register_interface(btd_get_dbus_connection(),
> > > device_get_path(data->device),
> > > CS_INTERFACE, cs_dbus_methods,
> > > - NULL, cs_dbus_properties, data, NULL);
> > > + cs_dbus_signals, cs_dbus_properties,
> > > + data, NULL);
> > >
> > > return 0;
> > > }
> > > diff --git a/profiles/ranging/rap_hci.c b/profiles/ranging/rap_hci.c
> > > index e57f967a2..3da98972e 100644
> > > --- a/profiles/ranging/rap_hci.c
> > > +++ b/profiles/ranging/rap_hci.c
> > > @@ -442,6 +442,8 @@ static void rap_rd_loc_supp_cap_done_cb(const void *data, uint8_t size,
> > > DBG("Sending read remote capabilities for handle 0x%04X",
> > > sm->active_conn_handle);
> > > bt_rap_read_remote_supported_capabilities(sm, sm->active_conn_handle);
> > > +
> > > + bt_rap_set_local_sw_time(sm->rap, rsp->t_sw_time_supported);
> > > }
> > >
> > > static void rap_send_hci_cs_create_config_command(struct cs_state_machine *sm,
> > > @@ -873,6 +875,8 @@ static void rap_rd_rmt_supp_cap_cmplt_evt(const void *data, uint8_t size,
> > > cs_set_state(sm, CS_STATE_INIT);
> > > rap_send_hci_def_settings_command(sm, evt);
> > > }
> > > +
> > > + bt_rap_set_remote_sw_time(sm->rap, evt->t_sw_time_supported);
> > > }
> > >
> > > static void rap_cs_config_cmplt_evt(const void *data, uint8_t size,
> > > @@ -1162,6 +1166,46 @@ static void rap_cs_proc_enable_cmplt_evt(const void *data, uint8_t size,
> > > &rap_ev, sm->rap);
> > > }
> > >
> > > +static void rap_le_conn_update_complete_evt(const void *data, uint8_t size,
> > > + void *user_data)
> > > +{
> > > + struct cs_state_machine *sm = user_data;
> > > + const struct bt_hci_evt_le_conn_update_complete *evt;
> > > + struct rap_conn_mapping *mapping;
> > > + struct bt_rap *rap;
> > > + struct iovec iov;
> > > +
> > > + if (!sm || !data ||
> > > + size < sizeof(struct bt_hci_evt_le_conn_update_complete))
> > > + return;
> > > +
> > > + iov.iov_base = (void *) data;
> > > + iov.iov_len = size;
> > > +
> > > + evt = util_iov_pull_mem(&iov, sizeof(*evt));
> > > + if (!evt) {
> > > + error("Failed to pull LE conn update complete struct");
> > > + return;
> > > + }
> > > +
> > > + DBG("status=0x%02X handle=0x%04X interval=%u",
> > > + evt->status, evt->handle, evt->interval);
> > > +
> > > + if (evt->status != 0)
> > > + return;
> > > +
> > > + mapping = find_mapping_by_handle(sm, evt->handle);
> > > + if (mapping && mapping->rap) {
> > > + DBG("Found handle 0x%04X in mapping cache", evt->handle);
> > > + rap = mapping->rap;
> > > + } else {
> > > + error("No mapping found for handle 0x%04X", evt->handle);
> > > + return;
> > > + }
> > > +
> > > + bt_rap_set_conn_interval(rap, evt->interval);
> > > +}
> > > +
> > > static void parse_i_q_sample(struct iovec *iov, int16_t *i_sample,
> > > int16_t *q_sample)
> > > {
> > > @@ -1662,6 +1706,8 @@ void *bt_rap_attach_hci(struct bt_rap *rap, struct bt_hci *hci,
> > > rap_cs_subevt_result_evt },
> > > { BT_HCI_EVT_LE_CS_SUBEVENT_RESULT_CONTINUE,
> > > rap_cs_subevt_result_cont_evt },
> > > + { BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE,
> > > + rap_le_conn_update_complete_evt },
> > > };
> > > struct cs_state_machine *sm;
> > > unsigned int i;
> > > @@ -1781,6 +1827,19 @@ bool bt_rap_stop_measurement(void *hci_sm)
> > > false);
> > > }
> > >
> > > +bool bt_rap_hci_set_procedure_data_cb(void *hci_sm,
> > > + bt_rap_procedure_data_func_t cb,
> > > + void *user_data,
> > > + bt_rap_destroy_func_t destroy)
> > > +{
> > > + struct cs_state_machine *sm = hci_sm;
> > > +
> > > + if (!sm || !sm->rap)
> > > + return false;
> > > +
> > > + return bt_rap_set_procedure_data_cb(sm->rap, cb, user_data, destroy);
> > > +}
> > > +
> > > bool bt_rap_set_conn_hndl(void *hci_sm, struct bt_rap *rap,
> > > uint16_t handle, const uint8_t *bdaddr, uint8_t bdaddr_type,
> > > bool is_central)
> > > --
> > > 2.34.1
> > >
> >
> >
> > --
> > Luiz Augusto von Dentz
>
>
>
> --
> Luiz Augusto von Dentz
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH] Bluetooth: HIDP: add missing length check for incoming frames
From: Luiz Augusto von Dentz @ 2026-07-17 15:40 UTC (permalink / raw)
To: Jiale Yao
Cc: Marcel Holtmann, Tim Bird, Muhammad Bilal, Kees Cook,
Michael Bommarito, linux-bluetooth, linux-kernel
In-Reply-To: <20260717153238.2002330-1-yaojiale02@163.com>
Hi,
On Fri, Jul 17, 2026 at 11:33 AM Jiale Yao <yaojiale02@163.com> wrote:
>
> In hidp_recv_ctrl_frame() and hidp_recv_intr_frame(), skb->data[0] is
> read without verifying that skb->len >= 1. A zero-length L2CAP PDU
> delivered via the HIDP control or interrupt channel causes an
> out-of-bounds read.
>
> Add pskb_may_pull(skb, 1) guards before both reads, matching the fix
> in commit 6770d3a8acdf ("Bluetooth: bnep: reject short frames before
> parsing") which addressed the same class of bug in BNEP.
>
> Assisted-by: Claude:deepseek-v4-pro
> Signed-off-by: Jiale Yao <yaojiale02@163.com>
> ---
> net/bluetooth/hidp/core.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
> index 0e24c5e2955e..6c7da8aca732 100644
> --- a/net/bluetooth/hidp/core.c
> +++ b/net/bluetooth/hidp/core.c
> @@ -565,6 +565,8 @@ static void hidp_recv_ctrl_frame(struct hidp_session *session,
>
> BT_DBG("session %p skb %p len %u", session, skb, skb->len);
>
> + if (!pskb_may_pull(skb, 1))
> + return;
We can probably replace this with skb_pull_data.
> hdr = skb->data[0];
> skb_pull(skb, 1);
>
> @@ -601,6 +603,8 @@ static void hidp_recv_intr_frame(struct hidp_session *session,
>
> BT_DBG("session %p skb %p len %u", session, skb, skb->len);
>
> + if (!pskb_may_pull(skb, 1))
> + return;
Ditto.
> hdr = skb->data[0];
> skb_pull(skb, 1);
>
> --
> 2.34.1
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* [PATCH] Bluetooth: HIDP: add missing length check for incoming frames
From: Jiale Yao @ 2026-07-17 15:32 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz, Jiale Yao, Tim Bird,
Muhammad Bilal, Kees Cook, Michael Bommarito, linux-bluetooth,
linux-kernel
In hidp_recv_ctrl_frame() and hidp_recv_intr_frame(), skb->data[0] is
read without verifying that skb->len >= 1. A zero-length L2CAP PDU
delivered via the HIDP control or interrupt channel causes an
out-of-bounds read.
Add pskb_may_pull(skb, 1) guards before both reads, matching the fix
in commit 6770d3a8acdf ("Bluetooth: bnep: reject short frames before
parsing") which addressed the same class of bug in BNEP.
Assisted-by: Claude:deepseek-v4-pro
Signed-off-by: Jiale Yao <yaojiale02@163.com>
---
net/bluetooth/hidp/core.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 0e24c5e2955e..6c7da8aca732 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -565,6 +565,8 @@ static void hidp_recv_ctrl_frame(struct hidp_session *session,
BT_DBG("session %p skb %p len %u", session, skb, skb->len);
+ if (!pskb_may_pull(skb, 1))
+ return;
hdr = skb->data[0];
skb_pull(skb, 1);
@@ -601,6 +603,8 @@ static void hidp_recv_intr_frame(struct hidp_session *session,
BT_DBG("session %p skb %p len %u", session, skb, skb->len);
+ if (!pskb_may_pull(skb, 1))
+ return;
hdr = skb->data[0];
skb_pull(skb, 1);
--
2.34.1
^ permalink raw reply related
* Re: [PATCH BlueZ v1 2/2] profiles/ranging: Add D-Bus ProcedureData signal for Channel Sounding
From: Luiz Augusto von Dentz @ 2026-07-17 15:17 UTC (permalink / raw)
To: Prathibha Madugonde
Cc: linux-bluetooth, quic_mohamull, quic_hbandi, quic_anubhavg
In-Reply-To: <CABBYNZ++i-JNcjCz5PG5JKNf9aWgMkm05i4-m7b5TPhTdMmojg@mail.gmail.com>
Hi.
On Fri, Jul 17, 2026 at 11:07 AM Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
>
> Hi Prathibha,
>
> On Fri, Jul 17, 2026 at 3:27 AM Prathibha Madugonde
> <prathibha.madugonde@oss.qualcomm.com> wrote:
> >
> > From: Prathibha Madugonde <prathibha.madugonde@oss.qualcomm.com>
> >
> > Marshal bcs_procedure_data (subevents, steps, mode 0/1/2/3 results,
> > and CS/procedure-enable config) into an a{sv} dictionary and emit it
> > as a new ProcedureData signal on the CS D-Bus interface.
>
> Was this documented though? It doesn't seem to follow the likes of
> https://github.com/bluez/bluez/blob/master/doc/org.bluez.ChannelSounding1.rst,
> for instance we don't use camel case for dictionary options. Also, if
> this is a result of `StartMeasurement`, we should probably signal it
> as Results or something like that, but I'd start with documentation so
> we can agree on the overall design.
Ok, looks like this does follow the documentation already:
https://github.com/bluez/bluez/blob/master/doc/org.bluez.ChannelSounding1.rst#void-proceduredatadict-data
That said that will probably need updating since some dictionaries use
camel case and others don't, so this needs to converge to a single
format.
> > Register a procedure_data callback on the RAP HCI state machine so
> > rap.c is notified when a procedure completes, and propagate the
> > locally supported T_SW time capability from the read-local-supported-
> > capabilities response into bt_rap.
> >
> > ---
> > profiles/ranging/rap.c | 497 ++++++++++++++++++++++++++++++++++++-
> > profiles/ranging/rap_hci.c | 59 +++++
> > 2 files changed, 555 insertions(+), 1 deletion(-)
> >
> > diff --git a/profiles/ranging/rap.c b/profiles/ranging/rap.c
> > index 3ffc0da76..42e1ef2a4 100644
> > --- a/profiles/ranging/rap.c
> > +++ b/profiles/ranging/rap.c
> > @@ -379,6 +379,492 @@ static const struct cs_dict_param_desc *cs_find_dict_param_desc(
> > return NULL;
> > }
> >
> > +static void dict_append_byte(DBusMessageIter *dict, const char *key,
> > + uint8_t val)
> > +{
> > + DBusMessageIter entry, variant;
> > +
> > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > + &entry);
> > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "y",
> > + &variant);
> > + dbus_message_iter_append_basic(&variant, DBUS_TYPE_BYTE, &val);
> > + dbus_message_iter_close_container(&entry, &variant);
> > + dbus_message_iter_close_container(dict, &entry);
> > +}
> > +
> > +static void dict_append_int32(DBusMessageIter *dict, const char *key,
> > + dbus_int32_t val)
> > +{
> > + DBusMessageIter entry, variant;
> > +
> > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > + &entry);
> > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "i",
> > + &variant);
> > + dbus_message_iter_append_basic(&variant, DBUS_TYPE_INT32, &val);
> > + dbus_message_iter_close_container(&entry, &variant);
> > + dbus_message_iter_close_container(dict, &entry);
> > +}
> > +
> > +static void dict_append_uint32(DBusMessageIter *dict, const char *key,
> > + dbus_uint32_t val)
> > +{
> > + DBusMessageIter entry, variant;
> > +
> > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > + &entry);
> > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "u",
> > + &variant);
> > + dbus_message_iter_append_basic(&variant, DBUS_TYPE_UINT32, &val);
> > + dbus_message_iter_close_container(&entry, &variant);
> > + dbus_message_iter_close_container(dict, &entry);
> > +}
> > +
> > +static void dict_append_uint64(DBusMessageIter *dict, const char *key,
> > + dbus_uint64_t val)
> > +{
> > + DBusMessageIter entry, variant;
> > +
> > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > + &entry);
> > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "t",
> > + &variant);
> > + dbus_message_iter_append_basic(&variant, DBUS_TYPE_UINT64, &val);
> > + dbus_message_iter_close_container(&entry, &variant);
> > + dbus_message_iter_close_container(dict, &entry);
> > +}
> > +
> > +static void dict_append_byte_array(DBusMessageIter *dict, const char *key,
> > + const uint8_t *data, int len)
> > +{
> > + DBusMessageIter entry, variant, arr;
> > + int i;
> > +
> > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > + &entry);
> > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "ay",
> > + &variant);
> > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "y", &arr);
> > + for (i = 0; i < len; i++)
> > + dbus_message_iter_append_basic(&arr, DBUS_TYPE_BYTE, &data[i]);
> > + dbus_message_iter_close_container(&variant, &arr);
> > + dbus_message_iter_close_container(&entry, &variant);
> > + dbus_message_iter_close_container(dict, &entry);
> > +}
> > +
> > +static void append_mode_zero(DBusMessageIter *dict,
> > + const struct cs_mode_zero_data *m0)
> > +{
> > + dict_append_byte(dict, "packetQuality", m0->packet_quality);
> > + dict_append_byte(dict, "packetRssiDbm", m0->packet_rssi_dbm);
> > + dict_append_byte(dict, "packetAntenna", m0->packet_ant);
> > + dict_append_int32(dict, "initiatorMeasuredFreqOffset",
> > + (dbus_int32_t)m0->init_measured_freq_offset);
> > +}
> > +
> > +static void append_pct_iq_pair(DBusMessageIter *dict, const char *key,
> > + const struct pct_iq_sample *pct)
> > +{
> > + DBusMessageIter entry, variant, arr;
> > + dbus_int32_t i_s = pct->i_sample;
> > + dbus_int32_t q_s = pct->q_sample;
> > +
> > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > + &entry);
> > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "ai",
> > + &variant);
> > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "i", &arr);
> > + dbus_message_iter_append_basic(&arr, DBUS_TYPE_INT32, &i_s);
> > + dbus_message_iter_append_basic(&arr, DBUS_TYPE_INT32, &q_s);
> > + dbus_message_iter_close_container(&variant, &arr);
> > + dbus_message_iter_close_container(&entry, &variant);
> > + dbus_message_iter_close_container(dict, &entry);
> > +}
> > +
> > +static void append_mode_one(DBusMessageIter *dict,
> > + const struct cs_mode_one_data *m1)
> > +{
> > + dict_append_byte(dict, "packetQuality", m1->packet_quality);
> > + dict_append_byte(dict, "packetNadm", m1->packet_nadm);
> > + dict_append_byte(dict, "packetRssiDbm", m1->packet_rssi_dbm);
> > + dict_append_int32(dict, "toaTodInitiator",
> > + (dbus_int32_t)m1->toa_tod_init);
> > + dict_append_int32(dict, "todToaReflector",
> > + (dbus_int32_t)m1->tod_toa_refl);
> > + dict_append_byte(dict, "packetAntenna", m1->packet_ant);
> > + append_pct_iq_pair(dict, "packetPct1", &m1->packet_pct1);
> > + append_pct_iq_pair(dict, "packetPct2", &m1->packet_pct2);
> > +}
> > +
> > +static void append_mode_two(DBusMessageIter *dict,
> > + const struct cs_mode_two_data *m2,
> > + uint8_t num_ant_paths)
> > +{
> > + DBusMessageIter entry, variant, arr;
> > + const char *key;
> > + int j;
> > + int num_paths;
> > +
> > + /*
> > + * num_ant_paths is the HCI "number of antenna paths" value
> > + * (0-indexed), so actual tone sample count = num_ant_paths + 1,
> > + * capped at array size.
> > + */
> > + num_paths = (num_ant_paths + 1) < CS_MAX_ANT_PATHS ?
> > + (num_ant_paths + 1) : CS_MAX_ANT_PATHS;
> > +
> > + dict_append_byte(dict, "antennaPermutationIndex", m2->ant_perm_index);
> > +
> > + /* tonePctIQSamples: interleaved (i,q) pairs as "ai" */
> > + key = "tonePctIQSamples";
> > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > + &entry);
> > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "ai",
> > + &variant);
> > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "i", &arr);
> > + for (j = 0; j < num_paths; j++) {
> > + dbus_int32_t i_s = m2->tone_pct[j].i_sample;
> > + dbus_int32_t q_s = m2->tone_pct[j].q_sample;
> > +
> > + dbus_message_iter_append_basic(&arr, DBUS_TYPE_INT32, &i_s);
> > + dbus_message_iter_append_basic(&arr, DBUS_TYPE_INT32, &q_s);
> > + }
> > + dbus_message_iter_close_container(&variant, &arr);
> > + dbus_message_iter_close_container(&entry, &variant);
> > + dbus_message_iter_close_container(dict, &entry);
> > +
> > + /* toneQualityIndicators: "ay" */
> > + key = "toneQualityIndicators";
> > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > + &entry);
> > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "ay",
> > + &variant);
> > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "y", &arr);
> > + for (j = 0; j < num_paths; j++) {
> > + uint8_t tqi = m2->tone_quality_indicator[j];
> > +
> > + dbus_message_iter_append_basic(&arr, DBUS_TYPE_BYTE, &tqi);
> > + }
> > + dbus_message_iter_close_container(&variant, &arr);
> > + dbus_message_iter_close_container(&entry, &variant);
> > + dbus_message_iter_close_container(dict, &entry);
> > +}
> > +
> > +static void append_proc_enable_config(DBusMessageIter *outer_dict,
> > + const struct rap_ev_cs_proc_enable_cmplt *cfg)
> > +{
> > + DBusMessageIter entry, variant, inner;
> > + const char *key = "procedureEnableConfig";
> > + dbus_uint32_t sub_evt_len_us;
> > +
> > + sub_evt_len_us = cfg->sub_evt_len[0] |
> > + ((uint32_t)cfg->sub_evt_len[1] << 8) |
> > + ((uint32_t)cfg->sub_evt_len[2] << 16);
> > +
> > + dbus_message_iter_open_container(outer_dict, DBUS_TYPE_DICT_ENTRY,
> > + NULL, &entry);
> > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "a{sv}",
> > + &variant);
> > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "{sv}",
> > + &inner);
> > +
> > + dict_append_byte(&inner, "toneAntennaConfigSelection",
> > + cfg->tone_ant_config_sel);
> > + dict_append_uint32(&inner, "subeventLenUs", sub_evt_len_us);
> > + dict_append_byte(&inner, "subeventsPerEvent", cfg->sub_evts_per_evt);
> > + dict_append_uint32(&inner, "subeventInterval", cfg->sub_evt_intrvl);
> > + dict_append_uint32(&inner, "eventInterval", cfg->evt_intrvl);
> > + dict_append_uint32(&inner, "procedureInterval", cfg->proc_intrvl);
> > + dict_append_uint32(&inner, "procedureCount", cfg->proc_counter);
> > + dict_append_uint32(&inner, "maxProcedureLen", cfg->max_proc_len);
> > +
> > + dbus_message_iter_close_container(&variant, &inner);
> > + dbus_message_iter_close_container(&entry, &variant);
> > + dbus_message_iter_close_container(outer_dict, &entry);
> > +}
> > +
> > +static void append_cs_config_param(DBusMessageIter *outer_dict,
> > + const struct bcs_procedure_data *bcs)
> > +{
> > + DBusMessageIter entry, variant, inner;
> > + const char *key = "csConfigParam";
> > + const struct rap_ev_cs_config_cmplt *cfg = &bcs->cs_config;
> > +
> > + dbus_message_iter_open_container(outer_dict, DBUS_TYPE_DICT_ENTRY,
> > + NULL, &entry);
> > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "a{sv}",
> > + &variant);
> > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "{sv}",
> > + &inner);
> > +
> > + dict_append_byte(&inner, "modeType", cfg->main_mode_type);
> > + dict_append_byte(&inner, "subModeType", cfg->sub_mode_type);
> > + dict_append_byte(&inner, "rttType", cfg->rtt_type);
> > + dict_append_byte_array(&inner, "channelMap", cfg->channel_map,
> > + sizeof(cfg->channel_map));
> > + dict_append_byte(&inner, "minMainModeSteps", cfg->min_main_mode_steps);
> > + dict_append_byte(&inner, "maxMainModeSteps", cfg->max_main_mode_steps);
> > + dict_append_byte(&inner, "mainModeRepetition", cfg->main_mode_rep);
> > + dict_append_byte(&inner, "mode0Steps", cfg->mode_0_steps);
> > + dict_append_byte(&inner, "role", cfg->role);
> > + dict_append_byte(&inner, "csSyncPhyType", cfg->cs_sync_phy);
> > + dict_append_byte(&inner, "channelSelectionType", cfg->channel_sel_type);
> > + dict_append_byte(&inner, "ch3cShapeType", cfg->ch3c_shape);
> > + dict_append_byte(&inner, "ch3cJump", cfg->ch3c_jump);
> > + dict_append_byte(&inner, "channelMapRepetition", cfg->channel_map_rep);
> > + dict_append_byte(&inner, "tIp1TimeUs", cfg->t_ip1_time);
> > + dict_append_byte(&inner, "tIp2TimeUs", cfg->t_ip2_time);
> > + dict_append_byte(&inner, "tFcsTimeUs", cfg->t_fcs_time);
> > + dict_append_byte(&inner, "tPmTimeUs", cfg->t_pm_time);
> > + dict_append_byte(&inner, "tSwTimeUsSupportedByLocal",
> > + bcs->t_sw_time_us_supported_by_local);
> > + dict_append_byte(&inner, "tSwTimeUsSupportedByRemote",
> > + bcs->t_sw_time_us_supported_by_remote);
> > + dict_append_uint32(&inner, "bleConnInterval", bcs->ble_conn_interval);
> > +
> > + dbus_message_iter_close_container(&variant, &inner);
> > + dbus_message_iter_close_container(&entry, &variant);
> > + dbus_message_iter_close_container(outer_dict, &entry);
> > +}
> > +
> > +static void append_step_to_dict(DBusMessageIter *dict,
> > + const struct cs_step_data *step,
> > + uint8_t num_ant_paths)
> > +{
> > + DBusMessageIter entry, variant, inner;
> > + const char *mode_key;
> > +
> > + dict_append_byte(dict, "stepMode", step->step_mode);
> > + dict_append_byte(dict, "stepChannel", step->step_chnl);
> > +
> > + switch (step->step_mode) {
> > + case CS_MODE_ZERO:
> > + mode_key = "modeZeroData";
> > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
> > + NULL, &entry);
> > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
> > + &mode_key);
> > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
> > + "a{sv}", &variant);
> > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
> > + "{sv}", &inner);
> > + append_mode_zero(&inner,
> > + &step->step_mode_data.mode_zero_data);
> > + dbus_message_iter_close_container(&variant, &inner);
> > + dbus_message_iter_close_container(&entry, &variant);
> > + dbus_message_iter_close_container(dict, &entry);
> > + break;
> > +
> > + case CS_MODE_ONE:
> > + mode_key = "modeOneData";
> > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
> > + NULL, &entry);
> > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
> > + &mode_key);
> > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
> > + "a{sv}", &variant);
> > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
> > + "{sv}", &inner);
> > + append_mode_one(&inner,
> > + &step->step_mode_data.mode_one_data);
> > + dbus_message_iter_close_container(&variant, &inner);
> > + dbus_message_iter_close_container(&entry, &variant);
> > + dbus_message_iter_close_container(dict, &entry);
> > + break;
> > +
> > + case CS_MODE_TWO:
> > + mode_key = "modeTwoData";
> > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
> > + NULL, &entry);
> > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
> > + &mode_key);
> > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
> > + "a{sv}", &variant);
> > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
> > + "{sv}", &inner);
> > + append_mode_two(&inner,
> > + &step->step_mode_data.mode_two_data,
> > + num_ant_paths);
> > + dbus_message_iter_close_container(&variant, &inner);
> > + dbus_message_iter_close_container(&entry, &variant);
> > + dbus_message_iter_close_container(dict, &entry);
> > + break;
> > +
> > + case CS_MODE_THREE:
> > + mode_key = "modeThreeData";
> > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
> > + NULL, &entry);
> > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
> > + &mode_key);
> > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
> > + "a{sv}", &variant);
> > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
> > + "{sv}", &inner);
> > + append_mode_one(&inner,
> > + &step->step_mode_data.mode_three_data.mode_one_data);
> > + append_mode_two(&inner,
> > + &step->step_mode_data.mode_three_data.mode_two_data,
> > + num_ant_paths);
> > + dbus_message_iter_close_container(&variant, &inner);
> > + dbus_message_iter_close_container(&entry, &variant);
> > + dbus_message_iter_close_container(dict, &entry);
> > + break;
> > +
> > + default:
> > + break;
> > + }
> > +}
> > +
> > +static void append_subevent_to_dict(DBusMessageIter *dict,
> > + const struct cs_subevent_result_data *sub)
> > +{
> > + DBusMessageIter entry, variant, arr;
> > + const char *key;
> > + uint32_t i;
> > +
> > + dict_append_int32(dict, "startAclConnEvtCounter",
> > + (dbus_int32_t)sub->start_acl_conn_evt_counter);
> > + dict_append_int32(dict, "freqComp", (dbus_int32_t)sub->freq_comp);
> > + dict_append_byte(dict, "refPwrLvl", (uint8_t)sub->ref_pwr_lvl);
> > + dict_append_byte(dict, "numAntPaths", sub->num_ant_paths);
> > + dict_append_byte(dict, "subeventAbortReason",
> > + sub->subevent_abort_reason);
> > + dict_append_uint64(dict, "timestampNanos", sub->timestamp_nanos);
> > + dict_append_uint32(dict, "numSteps", sub->num_steps);
> > +
> > + /* stepData: av (each element is a{sv}) */
> > + key = "stepData";
> > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> > + &entry);
> > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "av",
> > + &variant);
> > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "v", &arr);
> > + if (sub->step_data) {
> > + for (i = 0; i < sub->num_steps; i++) {
> > + DBusMessageIter inner, step_dict;
> > +
> > + dbus_message_iter_open_container(&arr,
> > + DBUS_TYPE_VARIANT, "a{sv}", &inner);
> > + dbus_message_iter_open_container(&inner,
> > + DBUS_TYPE_ARRAY, "{sv}", &step_dict);
> > + append_step_to_dict(&step_dict, &sub->step_data[i],
> > + sub->num_ant_paths);
> > + dbus_message_iter_close_container(&inner, &step_dict);
> > + dbus_message_iter_close_container(&arr, &inner);
> > + }
> > + }
> > + dbus_message_iter_close_container(&variant, &arr);
> > + dbus_message_iter_close_container(&entry, &variant);
> > + dbus_message_iter_close_container(dict, &entry);
> > +}
> > +
> > +static void append_subevent_array(DBusMessageIter *outer_dict,
> > + const char *key,
> > + const struct cs_subevent_result_data *subevents,
> > + uint32_t count)
> > +{
> > + DBusMessageIter entry, variant, arr;
> > + uint32_t i;
> > +
> > + dbus_message_iter_open_container(outer_dict, DBUS_TYPE_DICT_ENTRY,
> > + NULL, &entry);
> > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> > + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "av",
> > + &variant);
> > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "v", &arr);
> > + for (i = 0; i < count; i++) {
> > + DBusMessageIter inner, sub_dict;
> > +
> > + dbus_message_iter_open_container(&arr, DBUS_TYPE_VARIANT,
> > + "a{sv}", &inner);
> > + dbus_message_iter_open_container(&inner, DBUS_TYPE_ARRAY,
> > + "{sv}", &sub_dict);
> > + append_subevent_to_dict(&sub_dict, &subevents[i]);
> > + dbus_message_iter_close_container(&inner, &sub_dict);
> > + dbus_message_iter_close_container(&arr, &inner);
> > + }
> > + dbus_message_iter_close_container(&variant, &arr);
> > + dbus_message_iter_close_container(&entry, &variant);
> > + dbus_message_iter_close_container(outer_dict, &entry);
> > +}
> > +
> > +static void rap_emit_procedure_data(struct rap_data *data,
> > + const struct bcs_procedure_data *bcs)
> > +{
> > + DBusMessage *signal;
> > + DBusMessageIter iter, dict;
> > +
> > + signal = dbus_message_new_signal(device_get_path(data->device),
> > + CS_INTERFACE, "ProcedureData");
> > + if (!signal) {
> > + error("Failed to allocate ProcedureData signal");
> > + return;
> > + }
> > +
> > + dbus_message_iter_init_append(signal, &iter);
> > + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
> > +
> > + dict_append_int32(&dict, "procedureCounter",
> > + (dbus_int32_t)bcs->procedure_counter);
> > + dict_append_int32(&dict, "procedureSequence",
> > + (dbus_int32_t)bcs->procedure_sequence);
> > + dict_append_byte(&dict, "initiatorSelectedTxPower",
> > + (uint8_t)bcs->initiator_selected_tx_power);
> > + dict_append_byte(&dict, "reflectorSelectedTxPower",
> > + (uint8_t)bcs->reflector_selected_tx_power);
> > +
> > + dict_append_uint32(&dict, "initiatorSubeventCount",
> > + bcs->initiator_subevent_count);
> > + if (bcs->initiator_subevent_results &&
> > + bcs->initiator_subevent_count > 0)
> > + append_subevent_array(&dict, "initiatorSubeventResults",
> > + bcs->initiator_subevent_results,
> > + bcs->initiator_subevent_count);
> > +
> > + dict_append_byte(&dict, "initiatorProcedureAbortReason",
> > + bcs->initiator_procedure_abort_reason);
> > +
> > + dict_append_uint32(&dict, "reflectorSubeventCount",
> > + bcs->reflector_subevent_count);
> > + if (bcs->reflector_subevent_results &&
> > + bcs->reflector_subevent_count > 0)
> > + append_subevent_array(&dict, "reflectorSubeventResults",
> > + bcs->reflector_subevent_results,
> > + bcs->reflector_subevent_count);
> > +
> > + dict_append_byte(&dict, "reflectorProcedureAbortReason",
> > + bcs->reflector_procedure_abort_reason);
> > +
> > + append_proc_enable_config(&dict, &bcs->proc_enable_config);
> > + append_cs_config_param(&dict, bcs);
> > +
> > + dbus_message_iter_close_container(&iter, &dict);
> > +
> > + g_dbus_send_message(btd_get_dbus_connection(), signal);
> > +}
> > +
> > +static void rap_procedure_data(struct bt_rap *rap,
> > + struct bcs_procedure_data *bcs,
> > + void *user_data)
> > +{
> > + struct rap_data *data = user_data;
> > +
> > + DBG("procedure_counter=%u", bcs->procedure_counter);
> > + rap_emit_procedure_data(data, bcs);
> > +}
> > +
> > static DBusMessage *start_measurement(DBusConnection *conn,
> > DBusMessage *msg, void *user_data)
> > {
> > @@ -534,6 +1020,9 @@ bad_type:
> > data->active_session.cfg = cfg;
> > data->active_session.freq = freq;
> >
> > + bt_rap_hci_set_procedure_data_cb(data->hci_sm, rap_procedure_data,
> > + data, NULL);
> > +
> > return dbus_message_new_method_return(msg);
> > }
> >
> > @@ -588,6 +1077,11 @@ static const GDBusPropertyTable cs_dbus_properties[] = {
> > { }
> > };
> >
> > +static const GDBusSignalTable cs_dbus_signals[] = {
> > + { GDBUS_SIGNAL("ProcedureData", GDBUS_ARGS({ "data", "a{sv}" })) },
> > + { }
> > +};
> > +
> > static void rap_measurement_timeout_cb(void *user_data)
> > {
> > struct rap_data *data = user_data;
> > @@ -752,7 +1246,8 @@ static int rap_accept(struct btd_service *service)
> > g_dbus_register_interface(btd_get_dbus_connection(),
> > device_get_path(data->device),
> > CS_INTERFACE, cs_dbus_methods,
> > - NULL, cs_dbus_properties, data, NULL);
> > + cs_dbus_signals, cs_dbus_properties,
> > + data, NULL);
> >
> > return 0;
> > }
> > diff --git a/profiles/ranging/rap_hci.c b/profiles/ranging/rap_hci.c
> > index e57f967a2..3da98972e 100644
> > --- a/profiles/ranging/rap_hci.c
> > +++ b/profiles/ranging/rap_hci.c
> > @@ -442,6 +442,8 @@ static void rap_rd_loc_supp_cap_done_cb(const void *data, uint8_t size,
> > DBG("Sending read remote capabilities for handle 0x%04X",
> > sm->active_conn_handle);
> > bt_rap_read_remote_supported_capabilities(sm, sm->active_conn_handle);
> > +
> > + bt_rap_set_local_sw_time(sm->rap, rsp->t_sw_time_supported);
> > }
> >
> > static void rap_send_hci_cs_create_config_command(struct cs_state_machine *sm,
> > @@ -873,6 +875,8 @@ static void rap_rd_rmt_supp_cap_cmplt_evt(const void *data, uint8_t size,
> > cs_set_state(sm, CS_STATE_INIT);
> > rap_send_hci_def_settings_command(sm, evt);
> > }
> > +
> > + bt_rap_set_remote_sw_time(sm->rap, evt->t_sw_time_supported);
> > }
> >
> > static void rap_cs_config_cmplt_evt(const void *data, uint8_t size,
> > @@ -1162,6 +1166,46 @@ static void rap_cs_proc_enable_cmplt_evt(const void *data, uint8_t size,
> > &rap_ev, sm->rap);
> > }
> >
> > +static void rap_le_conn_update_complete_evt(const void *data, uint8_t size,
> > + void *user_data)
> > +{
> > + struct cs_state_machine *sm = user_data;
> > + const struct bt_hci_evt_le_conn_update_complete *evt;
> > + struct rap_conn_mapping *mapping;
> > + struct bt_rap *rap;
> > + struct iovec iov;
> > +
> > + if (!sm || !data ||
> > + size < sizeof(struct bt_hci_evt_le_conn_update_complete))
> > + return;
> > +
> > + iov.iov_base = (void *) data;
> > + iov.iov_len = size;
> > +
> > + evt = util_iov_pull_mem(&iov, sizeof(*evt));
> > + if (!evt) {
> > + error("Failed to pull LE conn update complete struct");
> > + return;
> > + }
> > +
> > + DBG("status=0x%02X handle=0x%04X interval=%u",
> > + evt->status, evt->handle, evt->interval);
> > +
> > + if (evt->status != 0)
> > + return;
> > +
> > + mapping = find_mapping_by_handle(sm, evt->handle);
> > + if (mapping && mapping->rap) {
> > + DBG("Found handle 0x%04X in mapping cache", evt->handle);
> > + rap = mapping->rap;
> > + } else {
> > + error("No mapping found for handle 0x%04X", evt->handle);
> > + return;
> > + }
> > +
> > + bt_rap_set_conn_interval(rap, evt->interval);
> > +}
> > +
> > static void parse_i_q_sample(struct iovec *iov, int16_t *i_sample,
> > int16_t *q_sample)
> > {
> > @@ -1662,6 +1706,8 @@ void *bt_rap_attach_hci(struct bt_rap *rap, struct bt_hci *hci,
> > rap_cs_subevt_result_evt },
> > { BT_HCI_EVT_LE_CS_SUBEVENT_RESULT_CONTINUE,
> > rap_cs_subevt_result_cont_evt },
> > + { BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE,
> > + rap_le_conn_update_complete_evt },
> > };
> > struct cs_state_machine *sm;
> > unsigned int i;
> > @@ -1781,6 +1827,19 @@ bool bt_rap_stop_measurement(void *hci_sm)
> > false);
> > }
> >
> > +bool bt_rap_hci_set_procedure_data_cb(void *hci_sm,
> > + bt_rap_procedure_data_func_t cb,
> > + void *user_data,
> > + bt_rap_destroy_func_t destroy)
> > +{
> > + struct cs_state_machine *sm = hci_sm;
> > +
> > + if (!sm || !sm->rap)
> > + return false;
> > +
> > + return bt_rap_set_procedure_data_cb(sm->rap, cb, user_data, destroy);
> > +}
> > +
> > bool bt_rap_set_conn_hndl(void *hci_sm, struct bt_rap *rap,
> > uint16_t handle, const uint8_t *bdaddr, uint8_t bdaddr_type,
> > bool is_central)
> > --
> > 2.34.1
> >
>
>
> --
> Luiz Augusto von Dentz
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH BlueZ v1 2/2] profiles/ranging: Add D-Bus ProcedureData signal for Channel Sounding
From: Luiz Augusto von Dentz @ 2026-07-17 15:07 UTC (permalink / raw)
To: Prathibha Madugonde
Cc: linux-bluetooth, quic_mohamull, quic_hbandi, quic_anubhavg
In-Reply-To: <20260717072647.255002-3-prathm@qti.qualcomm.com>
Hi Prathibha,
On Fri, Jul 17, 2026 at 3:27 AM Prathibha Madugonde
<prathibha.madugonde@oss.qualcomm.com> wrote:
>
> From: Prathibha Madugonde <prathibha.madugonde@oss.qualcomm.com>
>
> Marshal bcs_procedure_data (subevents, steps, mode 0/1/2/3 results,
> and CS/procedure-enable config) into an a{sv} dictionary and emit it
> as a new ProcedureData signal on the CS D-Bus interface.
Was this documented though? It doesn't seem to follow the likes of
https://github.com/bluez/bluez/blob/master/doc/org.bluez.ChannelSounding1.rst,
for instance we don't use camel case for dictionary options. Also, if
this is a result of `StartMeasurement`, we should probably signal it
as Results or something like that, but I'd start with documentation so
we can agree on the overall design.
> Register a procedure_data callback on the RAP HCI state machine so
> rap.c is notified when a procedure completes, and propagate the
> locally supported T_SW time capability from the read-local-supported-
> capabilities response into bt_rap.
>
> ---
> profiles/ranging/rap.c | 497 ++++++++++++++++++++++++++++++++++++-
> profiles/ranging/rap_hci.c | 59 +++++
> 2 files changed, 555 insertions(+), 1 deletion(-)
>
> diff --git a/profiles/ranging/rap.c b/profiles/ranging/rap.c
> index 3ffc0da76..42e1ef2a4 100644
> --- a/profiles/ranging/rap.c
> +++ b/profiles/ranging/rap.c
> @@ -379,6 +379,492 @@ static const struct cs_dict_param_desc *cs_find_dict_param_desc(
> return NULL;
> }
>
> +static void dict_append_byte(DBusMessageIter *dict, const char *key,
> + uint8_t val)
> +{
> + DBusMessageIter entry, variant;
> +
> + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> + &entry);
> + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "y",
> + &variant);
> + dbus_message_iter_append_basic(&variant, DBUS_TYPE_BYTE, &val);
> + dbus_message_iter_close_container(&entry, &variant);
> + dbus_message_iter_close_container(dict, &entry);
> +}
> +
> +static void dict_append_int32(DBusMessageIter *dict, const char *key,
> + dbus_int32_t val)
> +{
> + DBusMessageIter entry, variant;
> +
> + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> + &entry);
> + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "i",
> + &variant);
> + dbus_message_iter_append_basic(&variant, DBUS_TYPE_INT32, &val);
> + dbus_message_iter_close_container(&entry, &variant);
> + dbus_message_iter_close_container(dict, &entry);
> +}
> +
> +static void dict_append_uint32(DBusMessageIter *dict, const char *key,
> + dbus_uint32_t val)
> +{
> + DBusMessageIter entry, variant;
> +
> + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> + &entry);
> + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "u",
> + &variant);
> + dbus_message_iter_append_basic(&variant, DBUS_TYPE_UINT32, &val);
> + dbus_message_iter_close_container(&entry, &variant);
> + dbus_message_iter_close_container(dict, &entry);
> +}
> +
> +static void dict_append_uint64(DBusMessageIter *dict, const char *key,
> + dbus_uint64_t val)
> +{
> + DBusMessageIter entry, variant;
> +
> + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> + &entry);
> + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "t",
> + &variant);
> + dbus_message_iter_append_basic(&variant, DBUS_TYPE_UINT64, &val);
> + dbus_message_iter_close_container(&entry, &variant);
> + dbus_message_iter_close_container(dict, &entry);
> +}
> +
> +static void dict_append_byte_array(DBusMessageIter *dict, const char *key,
> + const uint8_t *data, int len)
> +{
> + DBusMessageIter entry, variant, arr;
> + int i;
> +
> + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> + &entry);
> + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "ay",
> + &variant);
> + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "y", &arr);
> + for (i = 0; i < len; i++)
> + dbus_message_iter_append_basic(&arr, DBUS_TYPE_BYTE, &data[i]);
> + dbus_message_iter_close_container(&variant, &arr);
> + dbus_message_iter_close_container(&entry, &variant);
> + dbus_message_iter_close_container(dict, &entry);
> +}
> +
> +static void append_mode_zero(DBusMessageIter *dict,
> + const struct cs_mode_zero_data *m0)
> +{
> + dict_append_byte(dict, "packetQuality", m0->packet_quality);
> + dict_append_byte(dict, "packetRssiDbm", m0->packet_rssi_dbm);
> + dict_append_byte(dict, "packetAntenna", m0->packet_ant);
> + dict_append_int32(dict, "initiatorMeasuredFreqOffset",
> + (dbus_int32_t)m0->init_measured_freq_offset);
> +}
> +
> +static void append_pct_iq_pair(DBusMessageIter *dict, const char *key,
> + const struct pct_iq_sample *pct)
> +{
> + DBusMessageIter entry, variant, arr;
> + dbus_int32_t i_s = pct->i_sample;
> + dbus_int32_t q_s = pct->q_sample;
> +
> + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> + &entry);
> + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "ai",
> + &variant);
> + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "i", &arr);
> + dbus_message_iter_append_basic(&arr, DBUS_TYPE_INT32, &i_s);
> + dbus_message_iter_append_basic(&arr, DBUS_TYPE_INT32, &q_s);
> + dbus_message_iter_close_container(&variant, &arr);
> + dbus_message_iter_close_container(&entry, &variant);
> + dbus_message_iter_close_container(dict, &entry);
> +}
> +
> +static void append_mode_one(DBusMessageIter *dict,
> + const struct cs_mode_one_data *m1)
> +{
> + dict_append_byte(dict, "packetQuality", m1->packet_quality);
> + dict_append_byte(dict, "packetNadm", m1->packet_nadm);
> + dict_append_byte(dict, "packetRssiDbm", m1->packet_rssi_dbm);
> + dict_append_int32(dict, "toaTodInitiator",
> + (dbus_int32_t)m1->toa_tod_init);
> + dict_append_int32(dict, "todToaReflector",
> + (dbus_int32_t)m1->tod_toa_refl);
> + dict_append_byte(dict, "packetAntenna", m1->packet_ant);
> + append_pct_iq_pair(dict, "packetPct1", &m1->packet_pct1);
> + append_pct_iq_pair(dict, "packetPct2", &m1->packet_pct2);
> +}
> +
> +static void append_mode_two(DBusMessageIter *dict,
> + const struct cs_mode_two_data *m2,
> + uint8_t num_ant_paths)
> +{
> + DBusMessageIter entry, variant, arr;
> + const char *key;
> + int j;
> + int num_paths;
> +
> + /*
> + * num_ant_paths is the HCI "number of antenna paths" value
> + * (0-indexed), so actual tone sample count = num_ant_paths + 1,
> + * capped at array size.
> + */
> + num_paths = (num_ant_paths + 1) < CS_MAX_ANT_PATHS ?
> + (num_ant_paths + 1) : CS_MAX_ANT_PATHS;
> +
> + dict_append_byte(dict, "antennaPermutationIndex", m2->ant_perm_index);
> +
> + /* tonePctIQSamples: interleaved (i,q) pairs as "ai" */
> + key = "tonePctIQSamples";
> + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> + &entry);
> + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "ai",
> + &variant);
> + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "i", &arr);
> + for (j = 0; j < num_paths; j++) {
> + dbus_int32_t i_s = m2->tone_pct[j].i_sample;
> + dbus_int32_t q_s = m2->tone_pct[j].q_sample;
> +
> + dbus_message_iter_append_basic(&arr, DBUS_TYPE_INT32, &i_s);
> + dbus_message_iter_append_basic(&arr, DBUS_TYPE_INT32, &q_s);
> + }
> + dbus_message_iter_close_container(&variant, &arr);
> + dbus_message_iter_close_container(&entry, &variant);
> + dbus_message_iter_close_container(dict, &entry);
> +
> + /* toneQualityIndicators: "ay" */
> + key = "toneQualityIndicators";
> + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> + &entry);
> + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "ay",
> + &variant);
> + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "y", &arr);
> + for (j = 0; j < num_paths; j++) {
> + uint8_t tqi = m2->tone_quality_indicator[j];
> +
> + dbus_message_iter_append_basic(&arr, DBUS_TYPE_BYTE, &tqi);
> + }
> + dbus_message_iter_close_container(&variant, &arr);
> + dbus_message_iter_close_container(&entry, &variant);
> + dbus_message_iter_close_container(dict, &entry);
> +}
> +
> +static void append_proc_enable_config(DBusMessageIter *outer_dict,
> + const struct rap_ev_cs_proc_enable_cmplt *cfg)
> +{
> + DBusMessageIter entry, variant, inner;
> + const char *key = "procedureEnableConfig";
> + dbus_uint32_t sub_evt_len_us;
> +
> + sub_evt_len_us = cfg->sub_evt_len[0] |
> + ((uint32_t)cfg->sub_evt_len[1] << 8) |
> + ((uint32_t)cfg->sub_evt_len[2] << 16);
> +
> + dbus_message_iter_open_container(outer_dict, DBUS_TYPE_DICT_ENTRY,
> + NULL, &entry);
> + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "a{sv}",
> + &variant);
> + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "{sv}",
> + &inner);
> +
> + dict_append_byte(&inner, "toneAntennaConfigSelection",
> + cfg->tone_ant_config_sel);
> + dict_append_uint32(&inner, "subeventLenUs", sub_evt_len_us);
> + dict_append_byte(&inner, "subeventsPerEvent", cfg->sub_evts_per_evt);
> + dict_append_uint32(&inner, "subeventInterval", cfg->sub_evt_intrvl);
> + dict_append_uint32(&inner, "eventInterval", cfg->evt_intrvl);
> + dict_append_uint32(&inner, "procedureInterval", cfg->proc_intrvl);
> + dict_append_uint32(&inner, "procedureCount", cfg->proc_counter);
> + dict_append_uint32(&inner, "maxProcedureLen", cfg->max_proc_len);
> +
> + dbus_message_iter_close_container(&variant, &inner);
> + dbus_message_iter_close_container(&entry, &variant);
> + dbus_message_iter_close_container(outer_dict, &entry);
> +}
> +
> +static void append_cs_config_param(DBusMessageIter *outer_dict,
> + const struct bcs_procedure_data *bcs)
> +{
> + DBusMessageIter entry, variant, inner;
> + const char *key = "csConfigParam";
> + const struct rap_ev_cs_config_cmplt *cfg = &bcs->cs_config;
> +
> + dbus_message_iter_open_container(outer_dict, DBUS_TYPE_DICT_ENTRY,
> + NULL, &entry);
> + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "a{sv}",
> + &variant);
> + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "{sv}",
> + &inner);
> +
> + dict_append_byte(&inner, "modeType", cfg->main_mode_type);
> + dict_append_byte(&inner, "subModeType", cfg->sub_mode_type);
> + dict_append_byte(&inner, "rttType", cfg->rtt_type);
> + dict_append_byte_array(&inner, "channelMap", cfg->channel_map,
> + sizeof(cfg->channel_map));
> + dict_append_byte(&inner, "minMainModeSteps", cfg->min_main_mode_steps);
> + dict_append_byte(&inner, "maxMainModeSteps", cfg->max_main_mode_steps);
> + dict_append_byte(&inner, "mainModeRepetition", cfg->main_mode_rep);
> + dict_append_byte(&inner, "mode0Steps", cfg->mode_0_steps);
> + dict_append_byte(&inner, "role", cfg->role);
> + dict_append_byte(&inner, "csSyncPhyType", cfg->cs_sync_phy);
> + dict_append_byte(&inner, "channelSelectionType", cfg->channel_sel_type);
> + dict_append_byte(&inner, "ch3cShapeType", cfg->ch3c_shape);
> + dict_append_byte(&inner, "ch3cJump", cfg->ch3c_jump);
> + dict_append_byte(&inner, "channelMapRepetition", cfg->channel_map_rep);
> + dict_append_byte(&inner, "tIp1TimeUs", cfg->t_ip1_time);
> + dict_append_byte(&inner, "tIp2TimeUs", cfg->t_ip2_time);
> + dict_append_byte(&inner, "tFcsTimeUs", cfg->t_fcs_time);
> + dict_append_byte(&inner, "tPmTimeUs", cfg->t_pm_time);
> + dict_append_byte(&inner, "tSwTimeUsSupportedByLocal",
> + bcs->t_sw_time_us_supported_by_local);
> + dict_append_byte(&inner, "tSwTimeUsSupportedByRemote",
> + bcs->t_sw_time_us_supported_by_remote);
> + dict_append_uint32(&inner, "bleConnInterval", bcs->ble_conn_interval);
> +
> + dbus_message_iter_close_container(&variant, &inner);
> + dbus_message_iter_close_container(&entry, &variant);
> + dbus_message_iter_close_container(outer_dict, &entry);
> +}
> +
> +static void append_step_to_dict(DBusMessageIter *dict,
> + const struct cs_step_data *step,
> + uint8_t num_ant_paths)
> +{
> + DBusMessageIter entry, variant, inner;
> + const char *mode_key;
> +
> + dict_append_byte(dict, "stepMode", step->step_mode);
> + dict_append_byte(dict, "stepChannel", step->step_chnl);
> +
> + switch (step->step_mode) {
> + case CS_MODE_ZERO:
> + mode_key = "modeZeroData";
> + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
> + NULL, &entry);
> + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
> + &mode_key);
> + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
> + "a{sv}", &variant);
> + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
> + "{sv}", &inner);
> + append_mode_zero(&inner,
> + &step->step_mode_data.mode_zero_data);
> + dbus_message_iter_close_container(&variant, &inner);
> + dbus_message_iter_close_container(&entry, &variant);
> + dbus_message_iter_close_container(dict, &entry);
> + break;
> +
> + case CS_MODE_ONE:
> + mode_key = "modeOneData";
> + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
> + NULL, &entry);
> + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
> + &mode_key);
> + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
> + "a{sv}", &variant);
> + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
> + "{sv}", &inner);
> + append_mode_one(&inner,
> + &step->step_mode_data.mode_one_data);
> + dbus_message_iter_close_container(&variant, &inner);
> + dbus_message_iter_close_container(&entry, &variant);
> + dbus_message_iter_close_container(dict, &entry);
> + break;
> +
> + case CS_MODE_TWO:
> + mode_key = "modeTwoData";
> + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
> + NULL, &entry);
> + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
> + &mode_key);
> + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
> + "a{sv}", &variant);
> + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
> + "{sv}", &inner);
> + append_mode_two(&inner,
> + &step->step_mode_data.mode_two_data,
> + num_ant_paths);
> + dbus_message_iter_close_container(&variant, &inner);
> + dbus_message_iter_close_container(&entry, &variant);
> + dbus_message_iter_close_container(dict, &entry);
> + break;
> +
> + case CS_MODE_THREE:
> + mode_key = "modeThreeData";
> + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
> + NULL, &entry);
> + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
> + &mode_key);
> + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
> + "a{sv}", &variant);
> + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
> + "{sv}", &inner);
> + append_mode_one(&inner,
> + &step->step_mode_data.mode_three_data.mode_one_data);
> + append_mode_two(&inner,
> + &step->step_mode_data.mode_three_data.mode_two_data,
> + num_ant_paths);
> + dbus_message_iter_close_container(&variant, &inner);
> + dbus_message_iter_close_container(&entry, &variant);
> + dbus_message_iter_close_container(dict, &entry);
> + break;
> +
> + default:
> + break;
> + }
> +}
> +
> +static void append_subevent_to_dict(DBusMessageIter *dict,
> + const struct cs_subevent_result_data *sub)
> +{
> + DBusMessageIter entry, variant, arr;
> + const char *key;
> + uint32_t i;
> +
> + dict_append_int32(dict, "startAclConnEvtCounter",
> + (dbus_int32_t)sub->start_acl_conn_evt_counter);
> + dict_append_int32(dict, "freqComp", (dbus_int32_t)sub->freq_comp);
> + dict_append_byte(dict, "refPwrLvl", (uint8_t)sub->ref_pwr_lvl);
> + dict_append_byte(dict, "numAntPaths", sub->num_ant_paths);
> + dict_append_byte(dict, "subeventAbortReason",
> + sub->subevent_abort_reason);
> + dict_append_uint64(dict, "timestampNanos", sub->timestamp_nanos);
> + dict_append_uint32(dict, "numSteps", sub->num_steps);
> +
> + /* stepData: av (each element is a{sv}) */
> + key = "stepData";
> + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
> + &entry);
> + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "av",
> + &variant);
> + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "v", &arr);
> + if (sub->step_data) {
> + for (i = 0; i < sub->num_steps; i++) {
> + DBusMessageIter inner, step_dict;
> +
> + dbus_message_iter_open_container(&arr,
> + DBUS_TYPE_VARIANT, "a{sv}", &inner);
> + dbus_message_iter_open_container(&inner,
> + DBUS_TYPE_ARRAY, "{sv}", &step_dict);
> + append_step_to_dict(&step_dict, &sub->step_data[i],
> + sub->num_ant_paths);
> + dbus_message_iter_close_container(&inner, &step_dict);
> + dbus_message_iter_close_container(&arr, &inner);
> + }
> + }
> + dbus_message_iter_close_container(&variant, &arr);
> + dbus_message_iter_close_container(&entry, &variant);
> + dbus_message_iter_close_container(dict, &entry);
> +}
> +
> +static void append_subevent_array(DBusMessageIter *outer_dict,
> + const char *key,
> + const struct cs_subevent_result_data *subevents,
> + uint32_t count)
> +{
> + DBusMessageIter entry, variant, arr;
> + uint32_t i;
> +
> + dbus_message_iter_open_container(outer_dict, DBUS_TYPE_DICT_ENTRY,
> + NULL, &entry);
> + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "av",
> + &variant);
> + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "v", &arr);
> + for (i = 0; i < count; i++) {
> + DBusMessageIter inner, sub_dict;
> +
> + dbus_message_iter_open_container(&arr, DBUS_TYPE_VARIANT,
> + "a{sv}", &inner);
> + dbus_message_iter_open_container(&inner, DBUS_TYPE_ARRAY,
> + "{sv}", &sub_dict);
> + append_subevent_to_dict(&sub_dict, &subevents[i]);
> + dbus_message_iter_close_container(&inner, &sub_dict);
> + dbus_message_iter_close_container(&arr, &inner);
> + }
> + dbus_message_iter_close_container(&variant, &arr);
> + dbus_message_iter_close_container(&entry, &variant);
> + dbus_message_iter_close_container(outer_dict, &entry);
> +}
> +
> +static void rap_emit_procedure_data(struct rap_data *data,
> + const struct bcs_procedure_data *bcs)
> +{
> + DBusMessage *signal;
> + DBusMessageIter iter, dict;
> +
> + signal = dbus_message_new_signal(device_get_path(data->device),
> + CS_INTERFACE, "ProcedureData");
> + if (!signal) {
> + error("Failed to allocate ProcedureData signal");
> + return;
> + }
> +
> + dbus_message_iter_init_append(signal, &iter);
> + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
> +
> + dict_append_int32(&dict, "procedureCounter",
> + (dbus_int32_t)bcs->procedure_counter);
> + dict_append_int32(&dict, "procedureSequence",
> + (dbus_int32_t)bcs->procedure_sequence);
> + dict_append_byte(&dict, "initiatorSelectedTxPower",
> + (uint8_t)bcs->initiator_selected_tx_power);
> + dict_append_byte(&dict, "reflectorSelectedTxPower",
> + (uint8_t)bcs->reflector_selected_tx_power);
> +
> + dict_append_uint32(&dict, "initiatorSubeventCount",
> + bcs->initiator_subevent_count);
> + if (bcs->initiator_subevent_results &&
> + bcs->initiator_subevent_count > 0)
> + append_subevent_array(&dict, "initiatorSubeventResults",
> + bcs->initiator_subevent_results,
> + bcs->initiator_subevent_count);
> +
> + dict_append_byte(&dict, "initiatorProcedureAbortReason",
> + bcs->initiator_procedure_abort_reason);
> +
> + dict_append_uint32(&dict, "reflectorSubeventCount",
> + bcs->reflector_subevent_count);
> + if (bcs->reflector_subevent_results &&
> + bcs->reflector_subevent_count > 0)
> + append_subevent_array(&dict, "reflectorSubeventResults",
> + bcs->reflector_subevent_results,
> + bcs->reflector_subevent_count);
> +
> + dict_append_byte(&dict, "reflectorProcedureAbortReason",
> + bcs->reflector_procedure_abort_reason);
> +
> + append_proc_enable_config(&dict, &bcs->proc_enable_config);
> + append_cs_config_param(&dict, bcs);
> +
> + dbus_message_iter_close_container(&iter, &dict);
> +
> + g_dbus_send_message(btd_get_dbus_connection(), signal);
> +}
> +
> +static void rap_procedure_data(struct bt_rap *rap,
> + struct bcs_procedure_data *bcs,
> + void *user_data)
> +{
> + struct rap_data *data = user_data;
> +
> + DBG("procedure_counter=%u", bcs->procedure_counter);
> + rap_emit_procedure_data(data, bcs);
> +}
> +
> static DBusMessage *start_measurement(DBusConnection *conn,
> DBusMessage *msg, void *user_data)
> {
> @@ -534,6 +1020,9 @@ bad_type:
> data->active_session.cfg = cfg;
> data->active_session.freq = freq;
>
> + bt_rap_hci_set_procedure_data_cb(data->hci_sm, rap_procedure_data,
> + data, NULL);
> +
> return dbus_message_new_method_return(msg);
> }
>
> @@ -588,6 +1077,11 @@ static const GDBusPropertyTable cs_dbus_properties[] = {
> { }
> };
>
> +static const GDBusSignalTable cs_dbus_signals[] = {
> + { GDBUS_SIGNAL("ProcedureData", GDBUS_ARGS({ "data", "a{sv}" })) },
> + { }
> +};
> +
> static void rap_measurement_timeout_cb(void *user_data)
> {
> struct rap_data *data = user_data;
> @@ -752,7 +1246,8 @@ static int rap_accept(struct btd_service *service)
> g_dbus_register_interface(btd_get_dbus_connection(),
> device_get_path(data->device),
> CS_INTERFACE, cs_dbus_methods,
> - NULL, cs_dbus_properties, data, NULL);
> + cs_dbus_signals, cs_dbus_properties,
> + data, NULL);
>
> return 0;
> }
> diff --git a/profiles/ranging/rap_hci.c b/profiles/ranging/rap_hci.c
> index e57f967a2..3da98972e 100644
> --- a/profiles/ranging/rap_hci.c
> +++ b/profiles/ranging/rap_hci.c
> @@ -442,6 +442,8 @@ static void rap_rd_loc_supp_cap_done_cb(const void *data, uint8_t size,
> DBG("Sending read remote capabilities for handle 0x%04X",
> sm->active_conn_handle);
> bt_rap_read_remote_supported_capabilities(sm, sm->active_conn_handle);
> +
> + bt_rap_set_local_sw_time(sm->rap, rsp->t_sw_time_supported);
> }
>
> static void rap_send_hci_cs_create_config_command(struct cs_state_machine *sm,
> @@ -873,6 +875,8 @@ static void rap_rd_rmt_supp_cap_cmplt_evt(const void *data, uint8_t size,
> cs_set_state(sm, CS_STATE_INIT);
> rap_send_hci_def_settings_command(sm, evt);
> }
> +
> + bt_rap_set_remote_sw_time(sm->rap, evt->t_sw_time_supported);
> }
>
> static void rap_cs_config_cmplt_evt(const void *data, uint8_t size,
> @@ -1162,6 +1166,46 @@ static void rap_cs_proc_enable_cmplt_evt(const void *data, uint8_t size,
> &rap_ev, sm->rap);
> }
>
> +static void rap_le_conn_update_complete_evt(const void *data, uint8_t size,
> + void *user_data)
> +{
> + struct cs_state_machine *sm = user_data;
> + const struct bt_hci_evt_le_conn_update_complete *evt;
> + struct rap_conn_mapping *mapping;
> + struct bt_rap *rap;
> + struct iovec iov;
> +
> + if (!sm || !data ||
> + size < sizeof(struct bt_hci_evt_le_conn_update_complete))
> + return;
> +
> + iov.iov_base = (void *) data;
> + iov.iov_len = size;
> +
> + evt = util_iov_pull_mem(&iov, sizeof(*evt));
> + if (!evt) {
> + error("Failed to pull LE conn update complete struct");
> + return;
> + }
> +
> + DBG("status=0x%02X handle=0x%04X interval=%u",
> + evt->status, evt->handle, evt->interval);
> +
> + if (evt->status != 0)
> + return;
> +
> + mapping = find_mapping_by_handle(sm, evt->handle);
> + if (mapping && mapping->rap) {
> + DBG("Found handle 0x%04X in mapping cache", evt->handle);
> + rap = mapping->rap;
> + } else {
> + error("No mapping found for handle 0x%04X", evt->handle);
> + return;
> + }
> +
> + bt_rap_set_conn_interval(rap, evt->interval);
> +}
> +
> static void parse_i_q_sample(struct iovec *iov, int16_t *i_sample,
> int16_t *q_sample)
> {
> @@ -1662,6 +1706,8 @@ void *bt_rap_attach_hci(struct bt_rap *rap, struct bt_hci *hci,
> rap_cs_subevt_result_evt },
> { BT_HCI_EVT_LE_CS_SUBEVENT_RESULT_CONTINUE,
> rap_cs_subevt_result_cont_evt },
> + { BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE,
> + rap_le_conn_update_complete_evt },
> };
> struct cs_state_machine *sm;
> unsigned int i;
> @@ -1781,6 +1827,19 @@ bool bt_rap_stop_measurement(void *hci_sm)
> false);
> }
>
> +bool bt_rap_hci_set_procedure_data_cb(void *hci_sm,
> + bt_rap_procedure_data_func_t cb,
> + void *user_data,
> + bt_rap_destroy_func_t destroy)
> +{
> + struct cs_state_machine *sm = hci_sm;
> +
> + if (!sm || !sm->rap)
> + return false;
> +
> + return bt_rap_set_procedure_data_cb(sm->rap, cb, user_data, destroy);
> +}
> +
> bool bt_rap_set_conn_hndl(void *hci_sm, struct bt_rap *rap,
> uint16_t handle, const uint8_t *bdaddr, uint8_t bdaddr_type,
> bool is_central)
> --
> 2.34.1
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* RE: CS: Add create_context support
From: bluez.test.bot @ 2026-07-17 15:06 UTC (permalink / raw)
To: linux-bluetooth, naga.akella
In-Reply-To: <20260717133503.3711396-2-naga.akella@oss.qualcomm.com>
[-- Attachment #1: Type: text/plain, Size: 1282 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=1129618
---Test result---
Test Summary:
CheckPatch PASS 1.93 seconds
GitLint FAIL 1.31 seconds
BuildEll PASS 20.56 seconds
BluezMake PASS 539.63 seconds
MakeCheck PASS 18.60 seconds
MakeDistcheck PASS 159.70 seconds
CheckValgrind PASS 230.06 seconds
CheckSmatch PASS 312.23 seconds
bluezmakeextell PASS 102.37 seconds
IncrementalBuild PASS 557.25 seconds
ScanBuild PASS 974.91 seconds
Details
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[BlueZ,v1,2/4] profiles: Add create_context param as part of CS Create Config cmd
1: T1 Title exceeds max length (81>80): "[BlueZ,v1,2/4] profiles: Add create_context param as part of CS Create Config cmd"
https://github.com/bluez/bluez/pull/2329
---
Regards,
Linux Bluetooth
^ permalink raw reply
* Re: [PATCH v4 03/11] power: sequencing: Add pwrseq_is_controllable() API
From: Loic Poulain @ 2026-07-17 14:45 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: linux-pci, linux-pm, linux-kernel, linux-arm-msm, linux-bluetooth,
devicetree, Manivannan Sadhasivam, Manivannan Sadhasivam,
Marcel Holtmann, Luiz Augusto von Dentz, Bjorn Andersson,
Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley
In-Reply-To: <CAMRc=Md8mLgYRsLd-KhwVV8X9AcYbHf--RB_pf0xFBP_P_DvCQ@mail.gmail.com>
Hi Bartosz,
On Fri, Jul 17, 2026 at 11:29 AM Bartosz Golaszewski <brgl@kernel.org> wrote:
>
> On Thu, 16 Jul 2026 18:18:20 +0200, Loic Poulain
> <loic.poulain@oss.qualcomm.com> said:
> > On some boards a power sequencing target has no host-controllable enable
> > for its function, for instance when the enable line is not wired up to a
> > GPIO and is hardwired to an always-on level. The pcie-m2 "uart" target is
> > one such example: when the M.2 connector does not route the W_DISABLE2#
> > signal to a host GPIO, its enable/disable are no-ops and the consumer
> > cannot gate the Bluetooth function at all or exclusively.
> >
> > Add a generic pwrseq_is_controllable() helper. It reports whether the
> > target's final unit provides a host-controllable dedicated power actuator.
> > The target can implement a new optional is_controllable() callback,
> > reporting whether that actuator is effective on this target (for example
> > depending on GPIO presence). If the target does not provide the callback,
> > it is assumed to be controllable.
> >
> > Note this only describes the target's own enable actuator. It does not
> > imply that a power-off reaches an electrical OFF state, since a target may
> > have multiple consumers. It also does not mean that power is uncontrolled
> > for the target's dependencies: those may still be gated on their own. And
> > it does not restrict consumers from calling pwrseq_power_off() either,
> > which remains valid to drop this consumer's vote on the (possibly shared)
> > resources and dependencies of the target.
> >
> > Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> > ---
>
> Thanks, this looks good to me now. This series is a bit all over the place,
> what is the merge strategy?
Since the entire series ultimately depends/touch on the pwrseq topic,
the simplest approach may be to take it all through your pwrseq
branch, with the possible exception of the DTS patches (through
Bjorn)?
Regards,
Loic
^ permalink raw reply
* [bluez/bluez] 7059a2: shared: Add create_context CS config parameter
From: Bhavani @ 2026-07-17 14:17 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1129618
Home: https://github.com/bluez/bluez
Commit: 7059a2547f09eb71e3fe0faf597918d9e658ed73
https://github.com/bluez/bluez/commit/7059a2547f09eb71e3fe0faf597918d9e658ed73
Author: Naga Bhavani Akella <naga.akella@oss.qualcomm.com>
Date: 2026-07-17 (Fri, 17 Jul 2026)
Changed paths:
M src/shared/cs-types.h
Log Message:
-----------
shared: Add create_context CS config parameter
Add create_context in bt_rap_le_cs_config structure
Commit: ee37dfde9ccfd98fd8ac9d19065d10b654c6db0b
https://github.com/bluez/bluez/commit/ee37dfde9ccfd98fd8ac9d19065d10b654c6db0b
Author: Naga Bhavani Akella <naga.akella@oss.qualcomm.com>
Date: 2026-07-17 (Fri, 17 Jul 2026)
Changed paths:
M profiles/ranging/rap.c
M profiles/ranging/rap_hci.c
Log Message:
-----------
profiles: Add create_context param as part of CS Create Config cmd
- Add the create_context field to the CS Create Config command.
- Route HCI command-send failures and non-zero-status completion
events to CS_STATE_HOLD instead of CS_STATE_STOPPED.
reserving CS_STATE_STOPPED for the clean/expected
stop (Procedure Enable Complete with state == 0x00)
Commit: 54de92d0bf259b924f89566ab777043fa467d900
https://github.com/bluez/bluez/commit/54de92d0bf259b924f89566ab777043fa467d900
Author: Naga Bhavani Akella <naga.akella@oss.qualcomm.com>
Date: 2026-07-17 (Fri, 17 Jul 2026)
Changed paths:
M client/cs.c
M client/cs.h
Log Message:
-----------
client: Add create_context CS config parameter
- Add the create_context field to the CS config parameter table so
bluetoothctl can control whether cs.start writes the CS configuration
to the local Controller only (0x00) or to both local and remote
Controllers via the CS Configuration procedure (0x01), matching the
Create_Context field of the LE CS Create Config HCI command
- Change the license in cs.c and cs.h.
- Drop RangingInterface support for now,
as it is still under discussion.
Commit: 9efbc3b2c56a230045209606316e6bcb3dee6f5e
https://github.com/bluez/bluez/commit/9efbc3b2c56a230045209606316e6bcb3dee6f5e
Author: Naga Bhavani Akella <naga.akella@oss.qualcomm.com>
Date: 2026-07-17 (Fri, 17 Jul 2026)
Changed paths:
M doc/bluetoothctl-cs.rst
Log Message:
-----------
doc: Document create_context in bluetoothctl-cs.rst
Document the new create_context parameter introduced in client/cs.c.
Compare: https://github.com/bluez/bluez/compare/7059a2547f09%5E...9efbc3b2c56a
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox