* Re: [PATCH v4] Bluetooth: hci_conn: fix potential UAF in create_big_sync
From: patchwork-bot+bluetooth @ 2026-04-13 18:20 UTC (permalink / raw)
To: David Carlier
Cc: marcel, luiz.dentz, pav, linux-bluetooth, linux-kernel, stable,
luiz.von.dentz
In-Reply-To: <20260412202916.196282-1-devnexen@gmail.com>
Hello:
This patch was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Sun, 12 Apr 2026 21:29:16 +0100 you wrote:
> Add hci_conn_valid() check in create_big_sync() to detect stale
> connections before proceeding with BIG creation. Handle the
> resulting -ECANCELED in create_big_complete() and re-validate the
> connection under hci_dev_lock() before dereferencing, matching the
> pattern used by create_le_conn_complete() and create_pa_complete().
>
> Keep the hci_conn object alive across the async boundary by taking
> a reference via hci_conn_get() when queueing create_big_sync(), and
> dropping it in the completion callback. The refcount and the lock
> are complementary: the refcount keeps the object allocated, while
> hci_dev_lock() serializes hci_conn_hash_del()'s list_del_rcu() on
> hdev->conn_hash, as required by hci_conn_del().
>
> [...]
Here is the summary with links:
- [v4] Bluetooth: hci_conn: fix potential UAF in create_big_sync
https://git.kernel.org/bluetooth/bluetooth-next/c/d55d107b6fa6
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH] Bluetooth: RFCOMM: validate skb length in MCC handlers
From: Luiz Augusto von Dentz @ 2026-04-13 18:19 UTC (permalink / raw)
To: SeungJu Cheon
Cc: linux-bluetooth, marcel, kees, kuba, me, shuah,
linux-kernel-mentees, linux-kernel
In-Reply-To: <20260412045457.53100-1-suunj1331@gmail.com>
Hi,
On Sun, Apr 12, 2026 at 12:55 AM SeungJu Cheon <suunj1331@gmail.com> wrote:
>
> rfcomm_recv_pn(), rfcomm_recv_rpn(), rfcomm_recv_rls(), and
> rfcomm_recv_msc() cast skb->data to their respective structs
> without first checking skb->len. A remote device can send a
> short MCC frame, causing out-of-bounds reads from the skb buffer.
>
> For rfcomm_recv_pn(), the uninitialized pn->mtu value is stored
> in d->mtu via rfcomm_apply_pn(), then echoed back to the remote
> device in the PN response, leaking kernel heap data.
>
> This results in use of uninitialized memory, as reported by KMSAN.
>
> Add explicit skb->len checks against the expected structure size
> at the start of each handler before accessing the payload.
>
> =====================================================
> BUG: KMSAN: uninit-value in rfcomm_run+0x7eae/0xee90
> rfcomm_run+0x7eae/0xee90
> kthread+0x53f/0x600
> ret_from_fork+0x20f/0x910
> ret_from_fork_asm+0x1a/0x30
>
> Uninit was created at:
> kmem_cache_alloc_node_noprof+0x3cd/0x12d0
> __alloc_skb+0x855/0x1190
> vhci_write+0x125/0x960
> vfs_write+0xbe1/0x15c0
> ksys_write+0x1d9/0x470
> __x64_sys_write+0x97/0xf0
> x64_sys_call+0x2ff0/0x3ea0
> do_syscall_64+0x134/0xf80
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
>
> CPU: 0 UID: 0 PID: 3374 Comm: krfcommd Tainted: G W 7.0.0-rc7
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996)
> Kernel panic - not syncing: kmsan.panic set ...
> =====================================================
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Signed-off-by: SeungJu Cheon <suunj1331@gmail.com>
> ---
> net/bluetooth/rfcomm/core.c | 40 +++++++++++++++++++++++++++++--------
> 1 file changed, 32 insertions(+), 8 deletions(-)
>
> diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
> index 611a9a94151e..daeba71a1514 100644
> --- a/net/bluetooth/rfcomm/core.c
> +++ b/net/bluetooth/rfcomm/core.c
> @@ -1431,9 +1431,15 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
>
> static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb)
> {
> - struct rfcomm_pn *pn = (void *) skb->data;
> + struct rfcomm_pn *pn;
> struct rfcomm_dlc *d;
> - u8 dlci = pn->dlci;
> + u8 dlci;
> +
> + if (skb->len < sizeof(*pn))
> + return -EINVAL;
> +
> + pn = (void *) skb->data;
> + dlci = pn->dlci;
How about using skb_pull_data?
> BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
>
> @@ -1483,8 +1489,8 @@ static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb)
>
> static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb)
> {
> - struct rfcomm_rpn *rpn = (void *) skb->data;
> - u8 dlci = __get_dlci(rpn->dlci);
> + struct rfcomm_rpn *rpn;
> + u8 dlci;
>
> u8 bit_rate = 0;
> u8 data_bits = 0;
> @@ -1495,6 +1501,12 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
> u8 xoff_char = 0;
> u16 rpn_mask = RFCOMM_RPN_PM_ALL;
>
> + if (skb->len < sizeof(*rpn))
> + return -EINVAL;
> +
> + rpn = (void *) skb->data;
> + dlci = __get_dlci(rpn->dlci);
Ditto
> BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x",
> dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl,
> rpn->xon_char, rpn->xoff_char, rpn->param_mask);
> @@ -1589,8 +1601,14 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
>
> static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb)
> {
> - struct rfcomm_rls *rls = (void *) skb->data;
> - u8 dlci = __get_dlci(rls->dlci);
> + struct rfcomm_rls *rls;
> + u8 dlci;
> +
> + if (skb->len < sizeof(*rls))
> + return -EINVAL;
> +
> + rls = (void *) skb->data;
> + dlci = __get_dlci(rls->dlci);
Ditto
> BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status);
>
> @@ -1608,9 +1626,15 @@ static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb
>
> static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb)
> {
> - struct rfcomm_msc *msc = (void *) skb->data;
> + struct rfcomm_msc *msc;
> struct rfcomm_dlc *d;
> - u8 dlci = __get_dlci(msc->dlci);
> + u8 dlci;
> +
> + if (skb->len < sizeof(*msc))
> + return -EINVAL;
> +
> + msc = (void *) skb->data;
> + dlci = __get_dlci(msc->dlci);
Ditto.
> BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig);
>
> --
> 2.52.0
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH] Bluetooth: l2cap: Fix MPS check in l2cap_ecred_reconf_req
From: Luiz Augusto von Dentz @ 2026-04-13 17:16 UTC (permalink / raw)
To: Dudu Lu; +Cc: linux-bluetooth, marcel
In-Reply-To: <20260413085600.75248-1-phx0fer@gmail.com>
Hi Dudu,
On Mon, Apr 13, 2026 at 4:56 AM Dudu Lu <phx0fer@gmail.com> wrote:
>
> The L2CAP Enhanced Credit Based Flow Control specification (Core Spec
> 5.4, Vol 3, Part A, Section 7.11) states that if more than one channel
> is being reconfigured, the MPS shall not be decreased. The current code
> uses `&& i` (loop index) to approximate "more than one channel", but
> this incorrectly allows MPS decrease for the first channel (i==0) even
> when multiple channels are being reconfigured, and incorrectly blocks
> MPS decrease for subsequent channels even when only that single channel
> is being reconfigured via index > 0.
>
> Replace `&& i` with `&& num_scid > 1` which correctly checks whether
> the reconfiguration request covers more than one channel, matching the
> specification intent.
>
> Signed-off-by: Dudu Lu <phx0fer@gmail.com>
> ---
> net/bluetooth/l2cap_core.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index 95c65fece39b..b069f965a339 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -5428,7 +5428,7 @@ static inline int l2cap_ecred_reconf_req(struct l2cap_conn *conn,
> * configured, the MPS field may be less than the current MPS
> * of that channel.
> */
> - if (chan[i]->remote_mps >= mps && i) {
> + if (chan[i]->remote_mps >= mps && num_scid > 1) {
Still seem to be wrong, this should detect decreases but instead it
still flag as an error if reconfiguration has req->mps == mps:
https://sashiko.dev/#/patchset/20260413085600.75248-1-phx0fer%40gmail.com
> BT_ERR("chan %p decreased MPS %u -> %u", chan[i],
> chan[i]->remote_mps, mps);
> result = L2CAP_RECONF_INVALID_MPS;
> --
> 2.39.3 (Apple Git-145)
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH] Bluetooth: hci_conn: Use disable_delayed_work_sync for le_conn_timeout
From: Luiz Augusto von Dentz @ 2026-04-13 16:56 UTC (permalink / raw)
To: Dudu Lu; +Cc: linux-bluetooth, marcel
In-Reply-To: <20260413085455.74585-1-phx0fer@gmail.com>
Hi Dudu,
On Mon, Apr 13, 2026 at 4:55 AM Dudu Lu <phx0fer@gmail.com> wrote:
>
> In hci_conn_del(), the LE_LINK case cancels le_conn_timeout using
> cancel_delayed_work(), which is non-synchronous. This means the timeout
> handler could still be running after the connection is freed, leading to
> a use-after-free.
>
> The other three delayed works in the same function (disc_work,
> auto_accept_work, idle_work) already use disable_delayed_work_sync().
> Change le_conn_timeout to use disable_delayed_work_sync() as well for
> consistency and correctness.
>
> Signed-off-by: Dudu Lu <phx0fer@gmail.com>
> ---
> net/bluetooth/hci_conn.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index e6393f17576b..6e96a8aeebd3 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -1201,7 +1201,7 @@ void hci_conn_del(struct hci_conn *conn)
> hdev->acl_cnt += conn->sent;
> break;
> case LE_LINK:
> - cancel_delayed_work(&conn->le_conn_timeout);
> + disable_delayed_work_sync(&conn->le_conn_timeout);
Why the change to use _sync though, afaik that can cause problems as
pointed by sashiko:
https://sashiko.dev/#/patchset/20260413085455.74585-1-phx0fer%40gmail.com
>
> if (hdev->le_pkts) {
> if (!hci_conn_num(hdev, LE_LINK) ||
> --
> 2.39.3 (Apple Git-145)
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH] Bluetooth: bnep: Fix endianness in bnep_rx_frame() extension parsing
From: Luiz Augusto von Dentz @ 2026-04-13 16:54 UTC (permalink / raw)
To: Dudu Lu; +Cc: linux-bluetooth, marcel
In-Reply-To: <20260413084442.68604-1-phx0fer@gmail.com>
Hi Dudu,
On Mon, Apr 13, 2026 at 4:44 AM Dudu Lu <phx0fer@gmail.com> wrote:
>
> In bnep_rx_frame(), the extension header parsing for
> BNEP_FILTER_NET_TYPE_SET and BNEP_FILTER_MULTI_ADDR_SET uses
> *(u16 *)(skb->data + 1) to read the 2-byte length field. This
> performs a native-endian read, but the BNEP protocol specifies this
> field in big-endian (network byte order).
>
> On little-endian architectures (x86, ARM), the bytes are swapped,
> causing the length to be wildly incorrect. For example, a length
> of 3 (0x00 0x03) is read as 768 (0x0300). This causes either:
> - skb_pull failure (length too large) -> frame dropped
> - Insufficient pull (length too small) -> frame parsing corruption
>
> The same file correctly uses get_unaligned_be16() for identical
> fields in bnep_ctrl_set_netfilter() (line 110) and
> bnep_ctrl_set_mcfilter() (line 156), confirming the inconsistency.
>
> Replace *(u16 *)(skb->data + 1) with get_unaligned_be16(skb->data + 1).
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Signed-off-by: Dudu Lu <phx0fer@gmail.com>
> ---
> net/bluetooth/bnep/core.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
> index d44987d4515c..2d1cb2061045 100644
> --- a/net/bluetooth/bnep/core.c
> +++ b/net/bluetooth/bnep/core.c
> @@ -332,7 +332,7 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
> case BNEP_FILTER_MULTI_ADDR_SET:
> case BNEP_FILTER_NET_TYPE_SET:
> /* Pull: ctrl type (1 b), len (2 b), data (len bytes) */
> - if (!skb_pull(skb, 3 + *(u16 *)(skb->data + 1) * 2))
> + if (!skb_pull(skb, 3 + get_unaligned_be16(skb->data + 1) * 2))
This change seems wrong, it should probably drop the * 2:
https://sashiko.dev/#/patchset/20260413084442.68604-1-phx0fer%40gmail.com
We should probably use `skb_pull_data`, assign it to an `hdr`
variable, and then add a check for if (!skb_pull(skb, hdr->len)).
> goto badframe;
> break;
> default:
> --
> 2.39.3 (Apple Git-145)
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH v7 0/8] Add support for handling PCIe M.2 Key E connectors in devicetree
From: Manivannan Sadhasivam @ 2026-04-13 16:08 UTC (permalink / raw)
To: Chen-Yu Tsai, Manivannan Sadhasivam
Cc: Rob Herring, Greg Kroah-Hartman, Jiri Slaby, Nathan Chancellor,
Nicolas Schier, Hans de Goede, Ilpo Järvinen, Mark Pearson,
Derek J. Clark, Krzysztof Kozlowski, Conor Dooley,
Marcel Holtmann, Luiz Augusto von Dentz, Bartosz Golaszewski,
Andy Shevchenko, Bartosz Golaszewski, linux-serial, linux-kernel,
linux-kbuild, platform-driver-x86, linux-pci, devicetree,
linux-arm-msm, linux-bluetooth, linux-pm, Stephan Gerhold,
Dmitry Baryshkov, linux-acpi, Hans de Goede, Bartosz Golaszewski
In-Reply-To: <fpcs4p62f35a5qyqwgm5ysa73stbysxcr62tkmmkrrcvsuf4t4@4ivukyqjey57>
[Resending as my previous reply got bounced]
On Mon, Apr 13, 2026 at 07:33:12PM +0530, Manivannan Sadhasivam wrote:
> On Mon, Apr 13, 2026 at 03:54:59PM +0800, Chen-Yu Tsai wrote:
> > Hi,
> >
> > On Thu, Mar 26, 2026 at 01:36:28PM +0530, Manivannan Sadhasivam wrote:
> > > Hi,
> > >
> > > This series is the continuation of the series [1] that added the initial support
> > > for the PCIe M.2 connectors. This series extends it by adding support for Key E
> > > connectors. These connectors are used to connect the Wireless Connectivity
> > > devices such as WiFi, BT, NFC and GNSS devices to the host machine over
> > > interfaces such as PCIe/SDIO, USB/UART and NFC. This series adds support for
> > > connectors that expose PCIe interface for WiFi and UART interface for BT. Other
> > > interfaces are left for future improvements.
> >
> > Thanks for working on this. I started playing with it now that it is in
> > -next. The PCIe part works fine. I'm looking into how to fit the pwrseq
> >
> > A couple questions:
> >
> > - Given that this connector actually represents two devices, how do I
> > say I want the BT part to be a wakeup source, but not the WiFi part?
> > Does wakeup-source even work at this point?
> >
>
> You can't use the DT property since the devices are not described in DT
> statically. But you can still use the per-device 'wakeup' sysfs knob to enable
> wakeup.
>
> > - Are there plans to do the SDIO part?
> >
>
> No, not at the moment. Feel free to take it up if you have the hardware and
> motivation :)
>
> > - The matching done in the M.2 connector driver for pwrseq_get() seems a
> > bit naive. It simply checks if the remote device in the OF graph is
> > the same as the requesting device.
> >
> > I think this would run into issues with USB hubs. If I have a USB hub
> > and two M.2 connectors, with both connectors connected to the same
> > hub, pwrseq_get() is going to always return only one of the instances.
> > This is because the USB hub has one device node with multiple OF graph
> > ports.
> >
>
> Yeah, this is a known limitation. I'm trying to improve this part now and have
> the WIP commits here: https://github.com/Mani-Sadhasivam/linux/tree/pwrseq-bt-en-fixes
>
> Once the merge window closes, I'll submit these.
>
> - Mani
>
> --
> மணிவண்ணன் சதாசிவம்
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [GIT PULL] bluetooth-next 2026-04-13
From: Paolo Abeni @ 2026-04-13 14:56 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: davem, kuba, linux-bluetooth, netdev
In-Reply-To: <CABBYNZ+7zr1jQ7a-2p88zNqMdvn6MAB5NAZ7b4OW=P56DcMT5g@mail.gmail.com>
On 4/13/26 4:17 PM, Luiz Augusto von Dentz wrote:
> On Mon, Apr 13, 2026 at 10:11 AM Luiz Augusto von Dentz
> <luiz.dentz@gmail.com> wrote:
>> On Mon, Apr 13, 2026 at 9:41 AM Paolo Abeni <pabeni@redhat.com> wrote:
>>>
>>> On 4/13/26 3:22 PM, Luiz Augusto von Dentz wrote:
>>>> The following changes since commit 42f9b4c6ef19e71d2c7d9bfd3c5037d4fe434ad7:
>>>>
>>>> tools: ynl: tests: fix leading space on Makefile target (2026-04-09 20:41:40 -0700)
>>>>
>>>> are available in the Git repository at:
>>>>
>>>> git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git tags/for-net-next-2026-04-13
>>>>
>>>> for you to fetch changes up to c347ca17d62a32c25564fee0ca3a2a7bc2d5fd6f:
>>>>
>>>> Bluetooth: hci_qca: Fix missing wakeup during SSR memdump handling (2026-04-13 09:19:42 -0400)
>>>>
>>>> ----------------------------------------------------------------
>>>> bluetooth-next pull request for net-next:
>>>
>>> Net-next is closed for the merge window. I guess Jakub could still
>>> consider merging this, but unless you want it very, very badly, I hope
>>> it can just be postponed, as the PW queue is already long.
>>
>> This update includes quite a few new hardware supports. This is a
>> resend because the last one was dropped due to an invalid 'Fixes' tag.
>>
>> Btw, I don't know why the entire PR needs to be dropped if only a few
>> items have invalid tags? Can't we just dropped those?
>
> Maybe Im doing something wrong in my side, the issue with the Fixes
> that is that sometimes they become invalid once I rebase on top of
> net-next, which, afaik, is necessary to detect already applied
> patches. Or is rebasing is not really necessary and should only be
> done once when rc1 is tagged?
AFAICT, rebasing is needed if you have local patches not present in the
tree that you are pulling from.
If you e.g. send a PR to net-next, including all the patches present in
your devel tree ATM, you could avoid the later rebase not applying any
patch in your tree until you merge net-next back.
Would that doable for you?
Thanks,
Paolo
^ permalink raw reply
* Re: [PATCH 5.10.y] Bluetooth: SCO: Fix use-after-free in sco_recv_frame() due to missing sock_hold
From: Greg KH @ 2026-04-13 14:43 UTC (permalink / raw)
To: Jianqiang kang
Cc: stable, imv4bel, patches, linux-kernel, marcel, johan.hedberg,
luiz.dentz, davem, kuba, linux-bluetooth, netdev, luiz.von.dentz
In-Reply-To: <20260409074429.740279-1-jianqkang@sina.cn>
On Thu, Apr 09, 2026 at 03:44:29PM +0800, Jianqiang kang wrote:
> From: Hyunwoo Kim <imv4bel@gmail.com>
>
> [ Upstream commit 598dbba9919c5e36c54fe1709b557d64120cb94b ]
>
> sco_recv_frame() reads conn->sk under sco_conn_lock() but immediately
> releases the lock without holding a reference to the socket. A concurrent
> close() can free the socket between the lock release and the subsequent
> sk->sk_state access, resulting in a use-after-free.
>
> Other functions in the same file (sco_sock_timeout(), sco_conn_del())
> correctly use sco_sock_hold() to safely hold a reference under the lock.
>
> Fix by using sco_sock_hold() to take a reference before releasing the
> lock, and adding sock_put() on all exit paths.
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> Signed-off-by: Jianqiang kang <jianqkang@sina.cn>
> ---
> net/bluetooth/sco.c | 10 +++++++---
> 1 file changed, 7 insertions(+), 3 deletions(-)
This breaks the build, how was it tested?
confused,
greg k-h
^ permalink raw reply
* Re: [GIT PULL] bluetooth-next 2026-04-13
From: Paolo Abeni @ 2026-04-13 14:34 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: davem, kuba, linux-bluetooth, netdev
In-Reply-To: <CABBYNZK5mMbuzvjAquy49vSk0pLRnk_s8oqEut1se4DToURn9A@mail.gmail.com>
On 4/13/26 4:11 PM, Luiz Augusto von Dentz wrote:
> On Mon, Apr 13, 2026 at 9:41 AM Paolo Abeni <pabeni@redhat.com> wrote:
>> On 4/13/26 3:22 PM, Luiz Augusto von Dentz wrote:
>>> The following changes since commit 42f9b4c6ef19e71d2c7d9bfd3c5037d4fe434ad7:
>>>
>>> tools: ynl: tests: fix leading space on Makefile target (2026-04-09 20:41:40 -0700)
>>>
>>> are available in the Git repository at:
>>>
>>> git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git tags/for-net-next-2026-04-13
>>>
>>> for you to fetch changes up to c347ca17d62a32c25564fee0ca3a2a7bc2d5fd6f:
>>>
>>> Bluetooth: hci_qca: Fix missing wakeup during SSR memdump handling (2026-04-13 09:19:42 -0400)
>>>
>>> ----------------------------------------------------------------
>>> bluetooth-next pull request for net-next:
>>
>> Net-next is closed for the merge window. I guess Jakub could still
>> consider merging this, but unless you want it very, very badly, I hope
>> it can just be postponed, as the PW queue is already long.
>
> This update includes quite a few new hardware supports. This is a
> resend because the last one was dropped due to an invalid 'Fixes' tag.
>
> Btw, I don't know why the entire PR needs to be dropped if only a few
> items have invalid tags? Can't we just dropped those?
That's the problem with PR: AFAIK we can just pull whatever the
submitter published. To do any edit, including dropping patches, we must
not do a git pull, and instead applying the patches individually
(meaning they will get the net maintainer SoB, too, which in turn will
make little sense).
/P
^ permalink raw reply
* Re: [GIT PULL] bluetooth-next 2026-04-13
From: Luiz Augusto von Dentz @ 2026-04-13 14:17 UTC (permalink / raw)
To: Paolo Abeni; +Cc: davem, kuba, linux-bluetooth, netdev
In-Reply-To: <CABBYNZK5mMbuzvjAquy49vSk0pLRnk_s8oqEut1se4DToURn9A@mail.gmail.com>
Hi,
On Mon, Apr 13, 2026 at 10:11 AM Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
>
> Hi Paolo,
>
> On Mon, Apr 13, 2026 at 9:41 AM Paolo Abeni <pabeni@redhat.com> wrote:
> >
> > On 4/13/26 3:22 PM, Luiz Augusto von Dentz wrote:
> > > The following changes since commit 42f9b4c6ef19e71d2c7d9bfd3c5037d4fe434ad7:
> > >
> > > tools: ynl: tests: fix leading space on Makefile target (2026-04-09 20:41:40 -0700)
> > >
> > > are available in the Git repository at:
> > >
> > > git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git tags/for-net-next-2026-04-13
> > >
> > > for you to fetch changes up to c347ca17d62a32c25564fee0ca3a2a7bc2d5fd6f:
> > >
> > > Bluetooth: hci_qca: Fix missing wakeup during SSR memdump handling (2026-04-13 09:19:42 -0400)
> > >
> > > ----------------------------------------------------------------
> > > bluetooth-next pull request for net-next:
> >
> > Net-next is closed for the merge window. I guess Jakub could still
> > consider merging this, but unless you want it very, very badly, I hope
> > it can just be postponed, as the PW queue is already long.
>
> This update includes quite a few new hardware supports. This is a
> resend because the last one was dropped due to an invalid 'Fixes' tag.
>
> Btw, I don't know why the entire PR needs to be dropped if only a few
> items have invalid tags? Can't we just dropped those?
Maybe Im doing something wrong in my side, the issue with the Fixes
that is that sometimes they become invalid once I rebase on top of
net-next, which, afaik, is necessary to detect already applied
patches. Or is rebasing is not really necessary and should only be
done once when rc1 is tagged?
> > Thanks,
> >
> > /P
> >
>
>
> --
> Luiz Augusto von Dentz
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [GIT PULL] bluetooth-next 2026-04-13
From: Luiz Augusto von Dentz @ 2026-04-13 14:11 UTC (permalink / raw)
To: Paolo Abeni; +Cc: davem, kuba, linux-bluetooth, netdev
In-Reply-To: <580f7972-56d5-4968-9dcc-32adc31e0673@redhat.com>
Hi Paolo,
On Mon, Apr 13, 2026 at 9:41 AM Paolo Abeni <pabeni@redhat.com> wrote:
>
> On 4/13/26 3:22 PM, Luiz Augusto von Dentz wrote:
> > The following changes since commit 42f9b4c6ef19e71d2c7d9bfd3c5037d4fe434ad7:
> >
> > tools: ynl: tests: fix leading space on Makefile target (2026-04-09 20:41:40 -0700)
> >
> > are available in the Git repository at:
> >
> > git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git tags/for-net-next-2026-04-13
> >
> > for you to fetch changes up to c347ca17d62a32c25564fee0ca3a2a7bc2d5fd6f:
> >
> > Bluetooth: hci_qca: Fix missing wakeup during SSR memdump handling (2026-04-13 09:19:42 -0400)
> >
> > ----------------------------------------------------------------
> > bluetooth-next pull request for net-next:
>
> Net-next is closed for the merge window. I guess Jakub could still
> consider merging this, but unless you want it very, very badly, I hope
> it can just be postponed, as the PW queue is already long.
This update includes quite a few new hardware supports. This is a
resend because the last one was dropped due to an invalid 'Fixes' tag.
Btw, I don't know why the entire PR needs to be dropped if only a few
items have invalid tags? Can't we just dropped those?
> Thanks,
>
> /P
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH BlueZ v4 3/3] profiles: ranging: Add HCI LE Event Handling in Reflector role
From: Luiz Augusto von Dentz @ 2026-04-13 14:08 UTC (permalink / raw)
To: Naga Bhavani Akella
Cc: linux-bluetooth, quic_mohamull, quic_hbandi, quic_anubhavg,
prathibha.madugonde
In-Reply-To: <20260413104116.1605357-4-naga.akella@oss.qualcomm.com>
Hi Naga,
On Mon, Apr 13, 2026 at 6:41 AM Naga Bhavani Akella
<naga.akella@oss.qualcomm.com> wrote:
>
> Open RAW HCI Channel for CS Event Handling
> Parse the following HCI LE CS Events in reflector role
> and route the events to RAP Profile.
> 1. HCI_EVT_LE_CS_READ_RMT_SUPP_CAP_COMPLETE
> 2. HCI_EVT_LE_CS_CONFIG_COMPLETE
> 3. HCI_EVT_LE_CS_SECURITY_ENABLE_COMPLETE
> 4. HCI_EVT_LE_CS_PROCEDURE_ENABLE_COMPLETE
> 5. HCI_EVT_LE_CS_SUBEVENT_RESULT
> 6. HCI_EVT_LE_CS_SUBEVENT_RESULT_CONTINUE
> Send HCI_OP_LE_CS_SET_DEFAULT_SETTINGS to the controller
> with default settings selected by the user.
> Map connection handle received to device connection
> ---
> Makefile.plugins | 3 +-
> profiles/ranging/rap.c | 83 ++-
> profiles/ranging/rap_hci.c | 1288 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 1367 insertions(+), 7 deletions(-)
> create mode 100644 profiles/ranging/rap_hci.c
>
> diff --git a/Makefile.plugins b/Makefile.plugins
> index c9efadb45..ac667beda 100644
> --- a/Makefile.plugins
> +++ b/Makefile.plugins
> @@ -89,7 +89,8 @@ builtin_modules += battery
> builtin_sources += profiles/battery/battery.c
>
> builtin_modules += rap
> -builtin_sources += profiles/ranging/rap.c
> +builtin_sources += profiles/ranging/rap.c \
> + profiles/ranging/rap_hci.c
>
> if SIXAXIS
> builtin_modules += sixaxis
> diff --git a/profiles/ranging/rap.c b/profiles/ranging/rap.c
> index f03454c72..63682e318 100644
> --- a/profiles/ranging/rap.c
> +++ b/profiles/ranging/rap.c
> @@ -17,6 +17,7 @@
> #include "gdbus/gdbus.h"
>
> #include "bluetooth/bluetooth.h"
> +#include "bluetooth/l2cap.h"
> #include "bluetooth/uuid.h"
>
> #include "src/plugin.h"
> @@ -34,12 +35,17 @@
> #include "src/shared/rap.h"
> #include "attrib/att.h"
> #include "src/log.h"
> +#include "src/btd.h"
>
> +#define USE_BT_HCI_RAW_CHANNEL 1
Didn't I already comment that we shouldn't use the likes of if
USE_BT_HCI_RAW_CHANNEL?
> struct rap_data {
> struct btd_device *device;
> struct btd_service *service;
> struct bt_rap *rap;
> unsigned int ready_id;
> +#if USE_BT_HCI_RAW_CHANNEL
> + struct bt_hci *hci;
> +#endif
> };
>
> static struct queue *sessions;
> @@ -61,10 +67,10 @@ static void rap_debug(const char *str, void *user_data)
>
> static void rap_data_add(struct rap_data *data)
> {
> - DBG("%p", data);
> + DBG("%p", (void *)data);
>
> if (queue_find(sessions, NULL, data)) {
> - error("data %p already added", data);
> + error("data %p already added", (void *)data);
No idea why you are casting to void * on %p?
> return;
> }
>
> @@ -95,13 +101,21 @@ static void rap_data_free(struct rap_data *data)
> }
>
> bt_rap_ready_unregister(data->rap, data->ready_id);
> +#if USE_BT_HCI_RAW_CHANNEL
> + if (data->hci) {
> + bt_rap_hci_sm_cleanup();
> + bt_hci_unref(data->hci);
> + }
> +#endif
> + /* Clean up HCI connection mappings */
> + bt_rap_detach_hci(data->rap);
> bt_rap_unref(data->rap);
> free(data);
> }
>
> static void rap_data_remove(struct rap_data *data)
> {
> - DBG("%p", data);
> + DBG("%p", (void *)data);
>
> if (!queue_remove(sessions, data))
> return;
> @@ -118,7 +132,7 @@ static void rap_detached(struct bt_rap *rap, void *user_data)
> {
> struct rap_data *data;
>
> - DBG("%p", rap);
> + DBG("%p", (void *)rap);
>
> data = queue_find(sessions, match_data, rap);
> if (!data) {
> @@ -131,7 +145,7 @@ static void rap_detached(struct bt_rap *rap, void *user_data)
>
> static void rap_ready(struct bt_rap *rap, void *user_data)
> {
> - DBG("%p", rap);
> + DBG("%p", (void *)rap);
> }
>
> static void rap_attached(struct bt_rap *rap, void *user_data)
> @@ -140,7 +154,7 @@ static void rap_attached(struct bt_rap *rap, void *user_data)
> struct bt_att *att;
> struct btd_device *device;
>
> - DBG("%p", rap);
> + DBG("%p", (void *)rap);
>
> data = queue_find(sessions, match_data, rap);
> if (data) {
> @@ -194,6 +208,22 @@ static int rap_probe(struct btd_service *service)
> free(data);
> return -EINVAL;
> }
> +#if USE_BT_HCI_RAW_CHANNEL
> + int16_t hci_index = btd_adapter_get_index(adapter);
> +
> + data->hci = bt_hci_new_raw_device(hci_index);
> + if (bt_rap_attach_hci(data->rap, data->hci)) {
> + DBG("HCI raw channel initialized, hci%d", hci_index);
> + bt_rap_hci_set_le_bcs_options(
> + btd_opts.defaults.bcs.role,
> + btd_opts.defaults.bcs.cs_sync_ant_sel,
> + btd_opts.defaults.bcs.max_tx_power);
BCS? Id called just bt_rap_set_options
> + } else {
> + error("HCI raw channel not available (may be in use)");
> + }
> +#else /* USE_BT_HCI_RAW_CHANNEL */
> + DBG("MGMT Events");
> +#endif /* USE_BT_HCI_RAW_CHANNEL */
>
> rap_data_add(data);
>
> @@ -228,6 +258,10 @@ static int rap_accept(struct btd_service *service)
> struct btd_device *device = btd_service_get_device(service);
> struct bt_gatt_client *client = btd_device_get_gatt_client(device);
> struct rap_data *data = btd_service_get_user_data(service);
> + struct bt_att *att;
> + const bdaddr_t *bdaddr;
> + uint8_t bdaddr_type;
> + uint16_t handle;
> char addr[18];
>
> ba2str(device_get_address(device), addr);
> @@ -243,6 +277,43 @@ static int rap_accept(struct btd_service *service)
> return -EINVAL;
> }
>
> + /* Set up connection handle mapping for CS event routing */
> + att = bt_rap_get_att(data->rap);
> + bdaddr = device_get_address(device);
> + bdaddr_type = device_get_le_address_type(device);
> +
> + if (att && data->hci) {
> + /* Use bt_hci_get_conn_info to find the connection handle
> + * by iterating through all connections and matching bdaddr
> + */
> + struct bt_hci_conn_info conn_info;
> + bool found = false;
> +
> + /* Try handles from 0x0001 to 0x0EFF
> + * (valid LE connection handle range)
> + */
> + for (handle = 0x0001; handle <= 0x0EFF; handle++) {
> + if (bt_hci_get_conn_info(data->hci, handle,
> + &conn_info)) {
> + /* Check if bdaddr matches */
> + if (memcmp(conn_info.bdaddr, bdaddr, 6) == 0) {
> + found = true;
> + DBG("Found conn handle 0x%04X", handle);
> + break;
> + }
> + }
> + }
Please no, we should use something like HCIGETCONNLIST, not mindlessly
iterate through all handles to check the connection handle.
> +
> + if (found) {
> + DBG("Setting up handle mapping: handle=0x%04X", handle);
> + bt_rap_set_conn_handle(data->rap, handle,
> + (const uint8_t *)bdaddr,
> + bdaddr_type);
> + } else {
> + error("Failed to find connection handle for device");
> + }
> + }
> +
> btd_service_connecting_complete(service, 0);
>
> return 0;
> diff --git a/profiles/ranging/rap_hci.c b/profiles/ranging/rap_hci.c
> new file mode 100644
> index 000000000..b00719ae2
> --- /dev/null
> +++ b/profiles/ranging/rap_hci.c
> @@ -0,0 +1,1288 @@
> +// SPDX-License-Identifier: LGPL-2.1-or-later
> +/*
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <stddef.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <endian.h>
> +
> +#include "lib/bluetooth/bluetooth.h"
> +#include "src/shared/util.h"
> +#include "src/shared/queue.h"
> +#include "src/shared/rap.h"
> +#include "src/log.h"
> +#include "monitor/bt.h"
> +
> +#ifndef MIN
> +#define MIN(a, b) ((a) < (b) ? (a) : (b))
> +#endif
> +
> +/* CS State Definitions */
> +enum cs_state_t {
> + CS_INIT,
> + CS_STOPPED,
> + CS_STARTED,
> + CS_WAIT_CONFIG_CMPLT,
> + CS_WAIT_SEC_CMPLT,
> + CS_WAIT_PROC_CMPLT,
> + CS_HOLD,
> + CS_UNSPECIFIED
> +};
> +
> +const char *state_names[] = {
> + "CS_INIT",
> + "CS_STOPPED",
> + "CS_STARTED",
> + "CS_WAIT_CONFIG_CMPLT",
> + "CS_WAIT_SEC_CMPLT",
> + "CS_WAIT_PROC_CMPLT",
> + "CS_HOLD",
> + "CS_UNSPECIFIED"
> +};
> +
> +/* Callback Function Type */
> +typedef void (*cs_callback_t)(uint16_t length,
> + const void *param, void *user_data);
> +
> +/* State Machine Context */
> +struct cs_state_machine_t {
> + enum cs_state_t current_state;
> + enum cs_state_t old_state;
> + struct bt_hci *hci;
> + struct bt_rap *rap;
> + unsigned int event_id;
> + bool initiator;
> + bool procedure_active;
> +};
> +
> +struct cs_callback_map_t {
> + enum cs_state_t state;
> + cs_callback_t callback;
> +};
> +
> +struct cs_callback_map_t cs_callback_map[] = {
> + { CS_WAIT_CONFIG_CMPLT, bt_rap_hci_cs_config_complete_callback },
> + { CS_WAIT_SEC_CMPLT, bt_rap_hci_cs_sec_enable_complete_callback },
> + { CS_WAIT_PROC_CMPLT, bt_rap_hci_cs_procedure_enable_complete_callback }
> +};
> +
> +#define CS_CALLBACK_MAP_SIZE ARRAY_SIZE(cs_callback_map)
> +
> +struct bt_rap_hci_cs_options cs_opt;
> +struct cs_state_machine_t *sm;
> +
> +/* Connection Handle Mapping */
> +struct rap_conn_mapping {
> + uint16_t handle;
> + uint8_t bdaddr[6];
> + uint8_t bdaddr_type;
> + struct bt_att *att;
> + struct bt_rap *rap;
> +};
> +
> +static struct queue *conn_mappings;
> +
> +/* Connection Mapping Helper Functions */
> +static void mapping_free(void *data)
> +{
> + struct rap_conn_mapping *mapping = data;
> +
> + if (!mapping)
> + return;
> +
> + free(mapping);
> +}
> +
> +static bool match_mapping_handle(const void *a, const void *b)
> +{
> + const struct rap_conn_mapping *mapping = a;
> + uint16_t handle = PTR_TO_UINT(b);
> +
> + return mapping->handle == handle;
> +}
> +
> +static bool match_mapping_rap(const void *a, const void *b)
> +{
> + const struct rap_conn_mapping *mapping = a;
> + const struct bt_rap *rap = b;
> +
> + return mapping->rap == rap;
> +}
> +
> +static struct rap_conn_mapping *find_mapping_by_handle(uint16_t handle)
> +{
> + if (!conn_mappings)
> + return NULL;
> +
> + return queue_find(conn_mappings, match_mapping_handle,
> + UINT_TO_PTR(handle));
> +}
> +
> +static bool add_conn_mapping(uint16_t handle, const uint8_t *bdaddr,
> + uint8_t bdaddr_type, struct bt_att *att,
> + struct bt_rap *rap)
> +{
> + struct rap_conn_mapping *mapping;
> +
> + if (!conn_mappings) {
> + conn_mappings = queue_new();
> + if (!conn_mappings)
> + return false;
> + }
> +
> + /* Check if mapping already exists */
> + mapping = find_mapping_by_handle(handle);
> + if (mapping) {
> + /* Update existing mapping */
> + if (bdaddr)
> + memcpy(mapping->bdaddr, bdaddr, 6);
> + mapping->bdaddr_type = bdaddr_type;
> + mapping->att = att;
> + mapping->rap = rap;
> + return true;
> + }
> +
> + /* Create new mapping */
> + mapping = new0(struct rap_conn_mapping, 1);
> + if (!mapping)
> + return false;
> +
> + mapping->handle = handle;
> + if (bdaddr)
> + memcpy(mapping->bdaddr, bdaddr, 6);
> + mapping->bdaddr_type = bdaddr_type;
> + mapping->att = att;
> + mapping->rap = rap;
> +
> + return queue_push_tail(conn_mappings, mapping);
> +}
> +
> +static void remove_conn_mapping(uint16_t handle)
> +{
> + struct rap_conn_mapping *mapping;
> +
> + if (!conn_mappings)
> + return;
> +
> + mapping = queue_remove_if(conn_mappings, match_mapping_handle,
> + UINT_TO_PTR(handle));
> + if (mapping)
> + mapping_free(mapping);
> +}
> +
> +static void remove_rap_mappings(struct bt_rap *rap)
> +{
> + if (!conn_mappings)
> + return;
> +
> + queue_remove_all(conn_mappings, match_mapping_rap, rap,
> + mapping_free);
> +}
> +
> +static struct bt_rap *resolve_handle_to_rap(uint16_t handle,
> + struct bt_hci *hci)
> +{
> + struct rap_conn_mapping *mapping;
> + struct bt_hci_conn_info conn_info;
> +
> + /* First try to find in mapping cache */
> + mapping = find_mapping_by_handle(handle);
> + if (mapping && mapping->rap) {
> + DBG("Found handle 0x%04X in mapping cache", handle);
> + return mapping->rap;
> + }
> +
> + /* Fallback: Try to get connection info via ioctl */
> + if (hci && bt_hci_get_conn_info(hci, handle, &conn_info)) {
> + DBG("Got connection info via ioctl for handle 0x%04X:", handle);
> + DBG(" bdaddr=%02x:%02x:%02x:%02x:%02x:%02x link_type=0x%02x",
> + conn_info.bdaddr[5], conn_info.bdaddr[4],
> + conn_info.bdaddr[3], conn_info.bdaddr[2],
> + conn_info.bdaddr[1], conn_info.bdaddr[0],
> + conn_info.type);
> + DBG(" Note: Cannot determine RAP instance from ioctl alone");
Not sure what this is for? If it cannot be resolved with just the
handle then why are you doing it?
> + }
> +
> + /* Profile layer should have called bt_rap_set_conn_handle() during
> + * connection establishment. If we reach here, the mapping was not set.
> + */
> + DBG("No mapping found for handle 0x%04X", handle);
> + DBG("Profile layer should call bt_rap_set_conn_handle() on connect");
> +
> + return NULL;
> +}
> +
> +/* State Machine Functions */
> +void cs_state_machine_init(struct cs_state_machine_t *sm, struct bt_rap *rap,
> + struct bt_hci *hci)
> +{
> + if (!sm)
> + return;
> +
> + memset(sm, 0, sizeof(struct cs_state_machine_t));
> + sm->current_state = CS_UNSPECIFIED;
> + sm->rap = rap;
> + sm->hci = hci;
> + sm->initiator = false;
> + sm->procedure_active = false;
> +}
> +
> +void bt_rap_hci_sm_cleanup(void)
> +{
> + if (!sm)
> + return;
> +
> + if (sm->event_id)
> + bt_hci_unregister(sm->hci, sm->event_id);
> +
> + sm->current_state = CS_UNSPECIFIED;
> + sm->rap = NULL;
> + sm->hci = NULL;
> + sm->procedure_active = false;
> +
> + free(sm);
> +}
> +
> +void bt_rap_hci_set_le_bcs_options(uint8_t role, uint8_t cs_sync_ant_sel,
> + int8_t max_tx_power)
> +{
> + cs_opt.role = role;
> + cs_opt.cs_sync_ant_sel = cs_sync_ant_sel;
> + cs_opt.max_tx_power = max_tx_power;
> +}
> +
> +/* State Transition Logic */
> +void cs_set_state(struct cs_state_machine_t *sm, enum cs_state_t new_state)
> +{
> + if (!sm)
> + return;
> +
> + if (sm->current_state == new_state)
> + return;
> +
> + /* Validate state values before array access */
> + if (sm->current_state > CS_UNSPECIFIED || new_state > CS_UNSPECIFIED) {
> + DBG("[ERROR] Invalid state transition attempted\n");
There is a error function to print errors.
> + return;
> + }
> +
> + DBG("[STATE] Transition: %s → %s\n",
> + state_names[sm->current_state],
> + state_names[new_state]);
> +
> + sm->old_state = sm->current_state;
> + sm->current_state = new_state;
> +}
> +
> +enum cs_state_t cs_get_current_state(struct cs_state_machine_t *sm)
> +{
> + return sm ? sm->current_state : CS_UNSPECIFIED;
> +}
> +
> +bool cs_is_procedure_active(const struct cs_state_machine_t *sm)
> +{
> + return sm ? sm->procedure_active : false;
> +}
> +
> +/* HCI Event Callbacks */
> +static void rap_def_settings_done_cb(const void *data, uint8_t size,
> + void *user_data)
> +{
> + struct bt_hci_rsp_le_cs_set_def_settings *rp;
> + struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
> +
> + if (!sm || !data ||
> + size < sizeof(struct bt_hci_rsp_le_cs_set_def_settings))
> + return;
> +
> + DBG("[EVENT] CS default Setting Complete (size=0x%02X)\n", size);
> +
> + rp = (struct bt_hci_rsp_le_cs_set_def_settings *)data;
> +
> + if (cs_get_current_state(sm) != CS_INIT) {
> + DBG("Event received in Wrong State!! Expected : CS_INIT");
> + return;
> + }
> +
> + if (rp->status == 0) {
> + /* Success - proceed to configuration */
> + cs_set_state(sm, CS_WAIT_CONFIG_CMPLT);
> +
> + /* Reflector role */
> + DBG("Waiting for CS Config Completed event...\n");
> + /* TODO: Initiator role - Send CS Config complete cmd */
> + } else {
> + /* Error - transition to stopped */
> + DBG("[ERROR]CS Set default setting failed with status 0x%02X\n",
> + rp->status);
User error
> + cs_set_state(sm, CS_STOPPED);
> + }
> +}
> +
> +void rap_send_hci_def_settings_command(struct cs_state_machine_t *sm,
> + struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete *ev)
> +{
> + struct bt_hci_cmd_le_cs_set_def_settings cp;
> + unsigned int status;
> +
> + memset(&cp, 0, sizeof(cp));
> +
> + if (ev->handle)
> + cp.handle = ev->handle;
> + cp.role_enable = cs_opt.role;
> + cp.cs_sync_antenna_selection = cs_opt.cs_sync_ant_sel;
> + cp.max_tx_power = cs_opt.max_tx_power;
> +
> + if (!sm || !sm->hci) {
> + DBG("[ERR] Set Def Settings: sm or hci is null");
> + return;
> + }
> +
> + status = bt_hci_send(sm->hci, BT_HCI_CMD_LE_CS_SET_DEF_SETTINGS,
> + &cp, sizeof(cp), rap_def_settings_done_cb,
> + sm, NULL);
> +
> + DBG("sending set default settings case, status : %d", status);
> + if (!status)
> + DBG("Failed to send default settings cmd");
> +}
> +
> +static void rap_rd_rmt_supp_cap_cmplt_evt(const uint8_t *data, uint8_t size,
> + void *user_data)
> +{
> + struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
> + const struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete *evt;
> + struct bt_rap *rap;
> + struct iovec iov;
> +
> + if (!sm || !data ||
> + size < sizeof(struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete))
> + return;
> +
> + /* Initialize iovec with the event data */
> + iov.iov_base = (void *)data;
> + iov.iov_len = size;
> +
> + /* Pull the entire structure at once */
> + evt = util_iov_pull_mem(&iov, sizeof(*evt));
> + if (!evt) {
> + DBG("[ERROR] Failed to pull remote cap complete struct\n");
> + return;
> + }
> +
> + DBG("[EVENT] Remote Capabilities Complete\n");
> + DBG("status=0x%02X, handle=0x%04X\n", evt->status, evt->handle);
> +
> + /* Check status */
> + if (evt->status != 0) {
> + DBG("[ERROR] Remote capabilities failed with status 0x%02X\n",
> + evt->status);
> + cs_set_state(sm, CS_STOPPED);
> + return;
> + }
> +
> + /* Resolve handle to RAP instance */
> + rap = resolve_handle_to_rap(evt->handle, sm->hci);
> + if (!rap) {
> + DBG("[WARN] Could not resolve handle 0x%04X to RAP instance\n",
> + evt->handle);
> + /* Continue with state machine RAP for now */
> + rap = sm->rap;
> + }
> +
> + DBG("[EVENT] Remote Capabilities: num_config=%u, ",
> + evt->num_config_supported);
> + DBG("max_consecutive_proc=%u, num_antennas=%u, ",
> + evt->max_consecutive_procedures_supported,
> + evt->num_antennas_supported);
> + DBG("max_antenna_paths=%u, roles=0x%02X, modes=0x%02X\n",
> + evt->max_antenna_paths_supported,
> + evt->roles_supported,
> + evt->modes_supported);
> +
> + rap_send_hci_def_settings_command(sm,
> + (struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete *)evt);
> + cs_set_state(sm, CS_INIT);
> +}
> +
> +static void rap_cs_config_cmplt_evt(const uint8_t *data, uint8_t size,
> + void *user_data)
> +{
> + struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
> + const struct bt_hci_evt_le_cs_config_complete *evt;
> + struct rap_ev_cs_config_cmplt rap_ev;
> + struct iovec iov;
> +
> + if (!sm || !data ||
> + size < sizeof(struct bt_hci_evt_le_cs_config_complete))
> + return;
> +
> + /* Initialize iovec with the event data */
> + iov.iov_base = (void *)data;
> + iov.iov_len = size;
> +
> + DBG("[EVENT] Configuration Complete (size=0x%02X)\n", size);
> +
> + /* State Check */
> + if (cs_get_current_state(sm) != CS_WAIT_CONFIG_CMPLT) {
> + DBG("Event received in Wrong State!! ");
> + DBG("Expected : CS_WAIT_CONFIG_CMPLT");
> + return;
> + }
> +
> + /* Pull the entire structure at once */
> + evt = util_iov_pull_mem(&iov, sizeof(*evt));
> + if (!evt) {
> + DBG("[ERROR] Failed to pull config complete struct\n");
> + return;
> + }
> +
> + DBG("status=0x%02X, handle=0x%04X\n", evt->status, evt->handle);
> +
> + /* Check status */
> + if (evt->status != 0) {
> + DBG("[ERROR] Configuration failed with status 0x%02X\n",
> + evt->status);
> + cs_set_state(sm, CS_STOPPED);
> + return;
> + }
> +
> + /* Copy fields to rap_ev structure */
> + rap_ev.status = evt->status;
> + rap_ev.conn_hdl = cpu_to_le16(evt->handle);
> + rap_ev.config_id = evt->config_id;
> + rap_ev.action = evt->action;
> + rap_ev.main_mode_type = evt->main_mode_type;
> + rap_ev.sub_mode_type = evt->sub_mode_type;
> + rap_ev.min_main_mode_steps = evt->min_main_mode_steps;
> + rap_ev.max_main_mode_steps = evt->max_main_mode_steps;
> + rap_ev.main_mode_rep = evt->main_mode_repetition;
> + rap_ev.mode_0_steps = evt->mode_0_steps;
> + rap_ev.role = evt->role;
> + rap_ev.rtt_type = evt->rtt_type;
> + rap_ev.cs_sync_phy = evt->cs_sync_phy;
> + memcpy(rap_ev.channel_map, evt->channel_map, 10);
> + rap_ev.channel_map_rep = evt->channel_map_repetition;
> + rap_ev.channel_sel_type = evt->channel_selection_type;
> + rap_ev.ch3c_shape = evt->ch3c_shape;
> + rap_ev.ch3c_jump = evt->ch3c_jump;
> + rap_ev.reserved = evt->reserved;
> + rap_ev.t_ip1_time = evt->t_ip1_time;
> + rap_ev.t_ip2_time = evt->t_ip2_time;
> + rap_ev.t_fcs_time = evt->t_fcs_time;
> + rap_ev.t_pm_time = evt->t_pm_time;
> +
> + /* Store rtt_type in global options */
> + cs_opt.rtt_type = rap_ev.rtt_type;
> +
> + DBG("[EVENT] Config Complete: config_id=%u, action=%u, ",
> + rap_ev.config_id, rap_ev.action);
> + DBG("main_mode=%u, sub_mode=%u, role=%u, rtt_type=%u\n",
> + rap_ev.main_mode_type, rap_ev.sub_mode_type,
> + rap_ev.role, rap_ev.rtt_type);
> +
> + /* Success - proceed to Security enable complete */
> + cs_set_state(sm, CS_WAIT_SEC_CMPLT);
> +
> + /* Reflector role */
> + DBG("Waiting for security enable event...\n");
> + /* TODO: Initiator role - Send CS Security enable cmd */
> +
> + /* Send Callback to RAP Profile */
> + for (size_t i = 0; i < CS_CALLBACK_MAP_SIZE; i++) {
> + if (cs_callback_map[i].state == sm->old_state) {
> + cs_callback_map[i].callback(size, &rap_ev, sm->rap);
> + return;
> + }
> + }
> +}
> +
> +static void rap_cs_sec_enable_cmplt_evt(const uint8_t *data, uint8_t size,
> + void *user_data)
> +{
> + struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
> + struct rap_ev_cs_sec_enable_cmplt rap_ev;
> + struct iovec iov;
> + uint8_t status;
> + uint16_t handle;
> +
> + if (!sm || !data ||
> + size < sizeof(struct bt_hci_evt_le_cs_sec_enable_complete))
> + return;
> +
> + /* Initialize iovec with the event data */
> + iov.iov_base = (void *)data;
> + iov.iov_len = size;
> +
> + DBG("[EVENT] Security Enable Complete (size=0x%02X)\n", size);
> +
> + /* State Check */
> + if (cs_get_current_state(sm) != CS_WAIT_SEC_CMPLT) {
> + DBG("Event received in Wrong State!! ");
> + DBG("Expected : CS_WAIT_SEC_CMPLT");
> + return;
> + }
> +
> + /* Parse all fields in order using iovec */
> + if (!util_iov_pull_u8(&iov, &status)) {
> + DBG("[ERROR] Failed to parse Status\n");
> + return;
> + }
> +
> + if (!util_iov_pull_le16(&iov, &handle)) {
> + DBG("[ERROR] Failed to parse Connection_Handle\n");
> + return;
> + }
> +
> + rap_ev.status = status;
> + rap_ev.conn_hdl = cpu_to_le16(handle);
> +
> + DBG("[EVENT] Security Enable: status=0x%02X, handle=0x%04X\n",
> + rap_ev.status, handle);
> +
> + if (rap_ev.status == 0) {
> + /* Success - proceed to configuration */
> + cs_set_state(sm, CS_WAIT_PROC_CMPLT);
> +
> + /* Reflector role */
> + DBG("Waiting for CS Proc complete event...\n");
> + /* TODO: Initiator - Send CS Proc Set Parameter and enable */
> + } else {
> + /* Error - transition to stopped */
> + DBG("[ERROR] Security enable failed with status 0x%02X\n",
> + rap_ev.status);
> + cs_set_state(sm, CS_STOPPED);
> + }
> +
> + /* Send Callback to RAP Profile */
> + for (size_t i = 0; i < CS_CALLBACK_MAP_SIZE; i++) {
> + if (cs_callback_map[i].state == sm->old_state) {
> + cs_callback_map[i].callback(size, &rap_ev, sm->rap);
> + return;
> + }
> + }
> +}
> +
> +static void rap_cs_proc_enable_cmplt_evt(const uint8_t *data, uint8_t size,
> + void *user_data)
> +{
> + struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
> + const struct bt_hci_evt_le_cs_proc_enable_complete *evt;
> + struct rap_ev_cs_proc_enable_cmplt rap_ev;
> + struct iovec iov;
> +
> + if (!sm || !data ||
> + size < sizeof(struct bt_hci_evt_le_cs_proc_enable_complete))
> + return;
> +
> + /* Initialize iovec with the event data */
> + iov.iov_base = (void *)data;
> + iov.iov_len = size;
> +
> + DBG("[EVENT] Procedure Enable Complete (size=0x%02X)\n", size);
DBG already prints the function name, so printing the event name again
sounds repetitive.
> +
> + /* State Check */
> + if (cs_get_current_state(sm) != CS_WAIT_PROC_CMPLT) {
> + DBG("Event received in Wrong State!! ");
> + DBG("Expected : CS_WAIT_PROC_CMPLT");
> + return;
> + }
> +
> + /* Pull the entire structure at once */
> + evt = util_iov_pull_mem(&iov, sizeof(*evt));
> + if (!evt) {
> + DBG("[ERROR] Failed to pull proc enable complete struct\n");
> + return;
> + }
> +
> + DBG("status=0x%02X, handle=0x%04X\n", evt->status, evt->handle);
> +
> + /* Check status */
> + if (evt->status != 0) {
> + DBG("[ERROR] Procedure enable failed with status 0x%02X\n",
> + evt->status);
> + cs_set_state(sm, CS_STOPPED);
> + sm->procedure_active = false;
> + return;
> + }
> +
> + /* Copy fields to rap_ev structure */
> + rap_ev.status = evt->status;
> + rap_ev.conn_hdl = cpu_to_le16(evt->handle);
> + rap_ev.config_id = evt->config_id;
> + rap_ev.state = evt->state;
> + rap_ev.tone_ant_config_sel = evt->tone_antenna_config_selection;
> + rap_ev.sel_tx_pwr = evt->selected_tx_power;
> + memcpy(rap_ev.sub_evt_len, evt->subevent_len, 3);
> + rap_ev.sub_evts_per_evt = evt->subevents_per_event;
> + rap_ev.sub_evt_intrvl = evt->subevent_interval;
> + rap_ev.evt_intrvl = evt->event_interval;
> + rap_ev.proc_intrvl = evt->procedure_interval;
> + rap_ev.proc_counter = evt->procedure_count;
> + rap_ev.max_proc_len = evt->max_procedure_len;
> +
> + DBG("[EVENT] Procedure Enable: config_id=%u, state=%u, ",
> + rap_ev.config_id, rap_ev.state);
> + DBG("sub_evts_per_evt=%u, evt_intrvl=%u, proc_intrvl=%u\n",
> + rap_ev.sub_evts_per_evt, rap_ev.evt_intrvl,
> + rap_ev.proc_intrvl);
> +
> + /* Success - procedure started */
> + cs_set_state(sm, CS_STARTED);
> + sm->procedure_active = true;
> +
> + /* Send Callback to RAP Profile */
> + for (size_t i = 0; i < CS_CALLBACK_MAP_SIZE; i++) {
> + if (cs_callback_map[i].state == sm->old_state) {
> + cs_callback_map[i].callback(size, &rap_ev, sm->rap);
> + return;
> + }
> + }
> +}
> +
> +static void parse_i_q_sample(struct iovec *iov, int16_t *i_sample,
> + int16_t *q_sample)
> +{
> + uint8_t bytes[3];
> + uint32_t buffer;
> + uint32_t i12;
> + uint32_t q12;
> +
> + /* Pull 3 bytes from iovec */
> + if (!util_iov_pull_u8(iov, &bytes[0]) ||
> + !util_iov_pull_u8(iov, &bytes[1]) ||
> + !util_iov_pull_u8(iov, &bytes[2])) {
> + *i_sample = 0;
> + *q_sample = 0;
> + return;
> + }
Oh please, use util_iov_pull_le24
> +
> + /* Reconstruct 24-bit buffer from 3 bytes */
> + buffer = (uint32_t)bytes[0] | ((uint32_t)bytes[1] << 8) |
> + ((uint32_t)bytes[2] << 16);
No need to do this; just use util_iov_pull_le24
> + i12 = buffer & 0x0FFFU; /* bits 0..11 */
> + q12 = (buffer >> 12) & 0x0FFFU; /* bits 12..23 */
>
> + /* Sign-extend 12-bit values to 16-bit */
> + *i_sample = (int16_t)((int32_t)(i12 << 20) >> 20);
> + *q_sample = (int16_t)((int32_t)(q12 << 20) >> 20);
This sound a little too complicated, please quote the spec why this
needs to be done this way, also this should have a pack/unpack macro
helps for bit manipulation.
> +}
> +
> +/* Parse CS Mode 0 step data */
> +static void parse_mode_zero_data(struct iovec *iov,
> + struct cs_mode_zero_data *mode_data,
> + uint8_t cs_role)
> +{
> + uint32_t freq_offset;
> +
> + if (iov->iov_len < 3) {
> + DBG("Mode 0: too short (<3)");
> + return;
> + }
> +
> + util_iov_pull_u8(iov, &mode_data->packet_quality);
> + util_iov_pull_u8(iov, &mode_data->packet_rssi_dbm);
> + util_iov_pull_u8(iov, &mode_data->packet_ant);
> + DBG("CS Step mode 0");
> +
> + if (cs_role == CS_INITIATOR && iov->iov_len >= 4) {
> + util_iov_pull_le32(iov, &freq_offset);
> + mode_data->init_measured_freq_offset = freq_offset;
> + }
> +}
> +
> +/* Parse CS Mode 1 step data */
> +static void parse_mode_one_data(struct iovec *iov,
> + struct cs_mode_one_data *mode_data,
> + uint8_t cs_role, uint8_t cs_rtt_type)
> +{
> + uint16_t time_val;
> +
> + if (iov->iov_len < 4) {
> + DBG("Mode 1: too short (<4)");
> + return;
> + }
> +
> + DBG("CS Step mode 1");
> + util_iov_pull_u8(iov, &mode_data->packet_quality);
> + util_iov_pull_u8(iov, &mode_data->packet_rssi_dbm);
> + util_iov_pull_u8(iov, &mode_data->packet_ant);
> + util_iov_pull_u8(iov, &mode_data->packet_nadm);
> +
> + if (iov->iov_len >= 2) {
> + util_iov_pull_le16(iov, &time_val);
> + if (cs_role == CS_REFLECTOR)
> + mode_data->tod_toa_refl = time_val;
> + else
> + mode_data->toa_tod_init = time_val;
> + }
> +
> + if ((cs_rtt_type == 0x01 || cs_rtt_type == 0x02) &&
> + iov->iov_len >= 6) {
> + int16_t i_val, q_val;
> +
> + parse_i_q_sample(iov, &i_val, &q_val);
> + mode_data->packet_pct1.i_sample = i_val;
> + mode_data->packet_pct1.q_sample = q_val;
> +
> + parse_i_q_sample(iov, &i_val, &q_val);
> + mode_data->packet_pct2.i_sample = i_val;
> + mode_data->packet_pct2.q_sample = q_val;
> + }
> +}
> +
> +/* Parse CS Mode 2 step data */
> +static void parse_mode_two_data(struct iovec *iov,
> + struct cs_mode_two_data *mode_data,
> + uint8_t max_paths)
> +{
> + uint8_t k;
> +
> + if (iov->iov_len < 1) {
> + DBG("Mode 2: too short (<1)");
> + return;
> + }
> +
> + util_iov_pull_u8(iov, &mode_data->ant_perm_index);
> + DBG("CS Step mode 2, max paths : %d", max_paths);
> +
> + for (k = 0; k < max_paths; k++) {
> + int16_t i_val, q_val;
> +
> + if (iov->iov_len < 4) {
> + DBG("Mode 2: insufficient PCT for path %u (rem=%zu)",
> + k, iov->iov_len);
> + break;
> + }
> + parse_i_q_sample(iov, &i_val, &q_val);
> + mode_data->tone_pct[k].i_sample = i_val;
> + mode_data->tone_pct[k].q_sample = q_val;
> +
> + util_iov_pull_u8(iov, &mode_data->tone_quality_indicator[k]);
> + DBG("tone_quality_indicator : %d",
> + mode_data->tone_quality_indicator[k]);
> + DBG("[i, q] : %d, %d",
> + mode_data->tone_pct[k].i_sample,
> + mode_data->tone_pct[k].q_sample);
> + }
> +}
> +
> +/* Parse CS Mode 3 step data */
> +static void parse_mode_three_data(struct iovec *iov,
> + struct cs_mode_three_data *mode_data,
> + uint8_t cs_role, uint8_t cs_rtt_type,
> + uint8_t max_paths)
> +{
> + uint8_t k;
> + struct cs_mode_one_data *mode_one = &mode_data->mode_one_data;
> + struct cs_mode_two_data *mode_two = &mode_data->mode_two_data;
> +
> + if (iov->iov_len < 4) {
> + DBG("Mode 3: mode1 too short (<4)");
> + return;
> + }
> +
> + DBG("CS Step mode 3");
> +
> + /* Parse Mode 1 portion */
> + parse_mode_one_data(iov, mode_one, cs_role, cs_rtt_type);
> +
> + /* Parse Mode 2 portion */
> + if (iov->iov_len >= 1) {
> + util_iov_pull_u8(iov, &mode_two->ant_perm_index);
> + for (k = 0; k < max_paths; k++) {
> + int16_t i_val, q_val;
> +
> + if (iov->iov_len < 4)
> + break;
> + parse_i_q_sample(iov, &i_val, &q_val);
> + mode_two->tone_pct[k].i_sample = i_val;
> + mode_two->tone_pct[k].q_sample = q_val;
> +
> + util_iov_pull_u8(iov,
> + &mode_two->tone_quality_indicator[k]);
> + }
> + }
> +}
> +
> +/* Parse a single CS step */
> +static void parse_cs_step(struct iovec *iov, struct cs_step_data *step,
> + uint8_t cs_role, uint8_t cs_rtt_type,
> + uint8_t max_paths)
> +{
> + uint8_t mode;
> + uint8_t chnl;
> + uint8_t length;
> +
> + /* Check if we have enough data for the 3-byte header */
> + if (iov->iov_len < 3) {
> + DBG("Truncated header for step");
> + return;
> + }
> +
> + /* Read mode, channel, and length (3-byte header) */
> + if (!util_iov_pull_u8(iov, &mode) ||
> + !util_iov_pull_u8(iov, &chnl) ||
> + !util_iov_pull_u8(iov, &length)) {
> + DBG("Failed to read header for step");
> + return;
> + }
> +
> + DBG("event->step_data_len : %d", length);
> +
> + step->step_mode = mode;
> + step->step_chnl = chnl;
> + step->step_data_length = length;
> +
> + DBG("Step: mode=%u chnl=%u data_len=%u", mode, chnl, length);
> +
> + if (iov->iov_len < length) {
> + DBG("Truncated payload for step (need %u, have %zu)",
> + length, iov->iov_len);
> + return;
> + }
> +
> + /* Parse step data based on mode */
> + switch (mode) {
> + case CS_MODE_ZERO:
> + parse_mode_zero_data(iov, &step->step_mode_data.mode_zero_data,
> + cs_role);
> + break;
> + case CS_MODE_ONE:
> + parse_mode_one_data(iov, &step->step_mode_data.mode_one_data,
> + cs_role, cs_rtt_type);
> + break;
> + case CS_MODE_TWO:
> + parse_mode_two_data(iov, &step->step_mode_data.mode_two_data,
> + max_paths);
> + break;
> + case CS_MODE_THREE:
> + parse_mode_three_data(iov,
> + &step->step_mode_data.mode_three_data,
> + cs_role, cs_rtt_type, max_paths);
> + break;
> + default:
> + DBG("Unknown step mode %d", mode);
> + /* Skip the entire step data */
> + util_iov_pull(iov, length);
> + break;
> + }
> +}
> +
> +static void rap_cs_subevt_result_evt(const uint8_t *data, uint8_t size,
> + void *user_data)
> +{
> + struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
> + struct rap_ev_cs_subevent_result *rap_ev;
> + struct iovec iov;
> + uint8_t cs_role;
> + uint8_t cs_rtt_type;
> + uint8_t max_paths;
> + uint8_t steps;
> + size_t send_len = 0;
> + uint16_t handle;
> + uint8_t config_id;
> + uint16_t start_acl_conn_evt_counter;
> + uint16_t proc_counter;
> + uint16_t freq_comp;
> + uint8_t ref_pwr_lvl;
> + uint8_t proc_done_status;
> + uint8_t subevt_done_status;
> + uint8_t abort_reason;
> + uint8_t num_ant_paths;
> + uint8_t num_steps_reported;
> + uint8_t i;
> +
> + if (!sm || !data ||
> + size < sizeof(struct bt_hci_evt_le_cs_subevent_result))
> + return;
> +
> + /* Initialize iovec with the event data */
> + iov.iov_base = (void *)data;
> + iov.iov_len = size;
> +
> + /* Check if Procedure is active or not */
> + if (!sm->procedure_active) {
> + DBG("Received Subevent event when Procedure is inactive!");
> + return;
> + }
> +
> + /* Parse header fields using iovec */
> + if (!util_iov_pull_le16(&iov, &handle)) {
> + DBG("[ERROR] Failed to parse Connection_Handle\n");
> + return;
> + }
> +
> + if (!util_iov_pull_u8(&iov, &config_id) ||
> + !util_iov_pull_le16(&iov, &start_acl_conn_evt_counter) ||
> + !util_iov_pull_le16(&iov, &proc_counter) ||
> + !util_iov_pull_le16(&iov, &freq_comp) ||
> + !util_iov_pull_u8(&iov, &ref_pwr_lvl) ||
> + !util_iov_pull_u8(&iov, &proc_done_status) ||
> + !util_iov_pull_u8(&iov, &subevt_done_status) ||
> + !util_iov_pull_u8(&iov, &abort_reason) ||
> + !util_iov_pull_u8(&iov, &num_ant_paths) ||
> + !util_iov_pull_u8(&iov, &num_steps_reported)) {
> + DBG("[ERROR] Failed to parse subevent fields\n");
> + return;
> + }
> +
> + cs_role = cs_opt.role;
> + cs_rtt_type = cs_opt.rtt_type;
> + max_paths = MIN((num_ant_paths + 1), CS_MAX_ANT_PATHS);
> + steps = MIN(num_steps_reported, CS_MAX_STEPS);
> + send_len = offsetof(struct rap_ev_cs_subevent_result, step_data) +
> + steps * sizeof(struct cs_step_data);
> + rap_ev = (struct rap_ev_cs_subevent_result *)malloc(send_len);
> + if (!rap_ev) {
> + DBG("[ERROR] Failed to allocate memory for subevent result\n");
> + return;
> + }
> +
> + DBG("[EVENT] Subevent Result (length=%u)\n", size);
> + rap_ev->conn_hdl = le16_to_cpu(handle);
> + rap_ev->config_id = config_id;
> + rap_ev->start_acl_conn_evt_counter = start_acl_conn_evt_counter;
> + rap_ev->proc_counter = proc_counter;
> + rap_ev->freq_comp = freq_comp;
> + rap_ev->ref_pwr_lvl = ref_pwr_lvl;
> + rap_ev->proc_done_status = proc_done_status;
> + rap_ev->subevt_done_status = subevt_done_status;
> + rap_ev->abort_reason = abort_reason;
> + rap_ev->num_ant_paths = num_ant_paths;
> + rap_ev->num_steps_reported = steps;
> +
> + if (num_steps_reported > CS_MAX_STEPS) {
> + DBG("Too many steps reported: %u (max %u)",
> + num_steps_reported, CS_MAX_STEPS);
> + goto send_event;
> + }
> +
> + /* Early exit for error conditions */
> + if (rap_ev->subevt_done_status == 0xF ||
> + rap_ev->proc_done_status == 0xF) {
> + DBG("CS Procedure/Subevent aborted: ");
> + DBG("sub evt status = %d, proc status = %d, reason = %d",
> + rap_ev->subevt_done_status, rap_ev->proc_done_status,
> + rap_ev->abort_reason);
> + goto send_event;
> + }
> +
> + /* Parse interleaved step data from remaining iovec data */
> + for (i = 0; i < steps; i++)
> + parse_cs_step(&iov, &rap_ev->step_data[i], cs_role, cs_rtt_type,
> + max_paths);
> +
> +send_event:
> + DBG("CS subevent result processed: %zu bytes, ", send_len);
> + bt_rap_hci_cs_subevent_result_callback(send_len, rap_ev, sm->rap);
> + free(rap_ev);
> +}
> +
> +static void rap_cs_subevt_result_cont_evt(const uint8_t *data, uint8_t size,
> + void *user_data)
> +{
> + struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
> + struct rap_ev_cs_subevent_result_cont *rap_ev;
> + struct iovec iov;
> + uint8_t cs_role;
> + uint8_t cs_rtt_type;
> + uint8_t max_paths;
> + uint8_t steps;
> + size_t send_len = 0;
> + uint16_t handle;
> + uint8_t config_id;
> + uint8_t proc_done_status;
> + uint8_t subevt_done_status;
> + uint8_t abort_reason;
> + uint8_t num_ant_paths;
> + uint8_t num_steps_reported;
> + uint8_t i;
> +
> + if (!sm || !data ||
> + size < sizeof(struct bt_hci_evt_le_cs_subevent_result_continue))
> + return;
> +
> + /* Initialize iovec with the event data */
> + iov.iov_base = (void *)data;
> + iov.iov_len = size;
> +
> + /* Check if Procedure is active or not */
> + if (!sm->procedure_active) {
> + DBG("Received Subevent when CS Procedure is inactive!");
> + return;
> + }
> +
> + /* Parse header fields using iovec */
> + if (!util_iov_pull_le16(&iov, &handle)) {
> + DBG("[ERROR] Failed to parse Connection_Handle\n");
> + return;
> + }
> +
> + if (!util_iov_pull_u8(&iov, &config_id) ||
> + !util_iov_pull_u8(&iov, &proc_done_status) ||
> + !util_iov_pull_u8(&iov, &subevt_done_status) ||
> + !util_iov_pull_u8(&iov, &abort_reason) ||
> + !util_iov_pull_u8(&iov, &num_ant_paths) ||
> + !util_iov_pull_u8(&iov, &num_steps_reported)) {
> + DBG("[ERROR] Failed to parse subevent continue fields ");
> + return;
> + }
> +
> + cs_role = cs_opt.role;
> + cs_rtt_type = cs_opt.rtt_type;
> + max_paths = MIN((num_ant_paths + 1), CS_MAX_ANT_PATHS);
> + steps = MIN(num_steps_reported, CS_MAX_STEPS);
> + send_len = offsetof(struct rap_ev_cs_subevent_result_cont, step_data) +
> + steps * sizeof(struct cs_step_data);
> + rap_ev = (struct rap_ev_cs_subevent_result_cont *)malloc(send_len);
> + if (!rap_ev) {
> + DBG("[ERROR] Failed to allocate memory for subevent result\n");
> + return;
> + }
> +
> + DBG("[EVENT] Subevent Result Cont (length=%u)\n", size);
> + rap_ev->conn_hdl = le16_to_cpu(handle);
> + rap_ev->config_id = config_id;
> + rap_ev->proc_done_status = proc_done_status;
> + rap_ev->subevt_done_status = subevt_done_status;
> + rap_ev->abort_reason = abort_reason;
> + rap_ev->num_ant_paths = num_ant_paths;
> + rap_ev->num_steps_reported = steps;
> +
> + if (num_steps_reported > CS_MAX_STEPS) {
> + DBG("Too many steps reported: %u (max %u)",
> + num_steps_reported, CS_MAX_STEPS);
> + goto send_event;
> + }
> +
> + /* Early exit for error conditions */
> + if (rap_ev->subevt_done_status == 0xF ||
> + rap_ev->proc_done_status == 0xF) {
> + DBG("CS Procedure/Subevent aborted: ");
> + DBG("sub evt status = %d, proc status = %d, reason = %d",
> + rap_ev->subevt_done_status, rap_ev->proc_done_status,
> + rap_ev->abort_reason);
> + goto send_event;
> + }
> +
> + /* Parse interleaved step data from remaining iovec data */
> + for (i = 0; i < steps; i++)
> + parse_cs_step(&iov, &rap_ev->step_data[i], cs_role, cs_rtt_type,
> + max_paths);
> +
> +send_event:
> + DBG("CS subevent result cont processed: %zu bytes, ", send_len);
> + bt_rap_hci_cs_subevent_result_cont_callback(send_len, rap_ev, sm->rap);
> + free(rap_ev);
> +}
> +
> +/* Subevent handler function type */
> +typedef void (*subevent_handler_t)(const uint8_t *data, uint8_t size,
> + void *user_data);
> +
> +/* Subevent table entry */
> +struct subevent_entry {
> + uint8_t opcode;
> + uint8_t min_len;
> + uint8_t max_len;
> + subevent_handler_t handler;
> + const char *name;
> +};
> +
> +/* Subevent dispatch table */
> +static const struct subevent_entry subevent_table[] = {
> + {
> + .opcode = BT_HCI_EVT_LE_CS_RD_REM_SUPP_CAP_COMPLETE,
> + .min_len = sizeof(
> + struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete),
> + .max_len = 0xFF,
> + .handler = rap_rd_rmt_supp_cap_cmplt_evt,
> + .name = "CS Read Remote Supported Capabilities Complete"
> + },
Have a macro to define each entry, HCI_EVT(...), that way we don't
need to enter the struct field names.
> + {
> + .opcode = BT_HCI_EVT_LE_CS_CONFIG_COMPLETE,
> + .min_len = sizeof(struct bt_hci_evt_le_cs_config_complete),
> + .max_len = 0xFF,
> + .handler = rap_cs_config_cmplt_evt,
> + .name = "CS Config Complete"
> + },
> + {
> + .opcode = BT_HCI_EVT_LE_CS_SEC_ENABLE_COMPLETE,
> + .min_len = sizeof(struct bt_hci_evt_le_cs_sec_enable_complete),
> + .max_len = 0xFF,
> + .handler = rap_cs_sec_enable_cmplt_evt,
> + .name = "CS Security Enable Complete"
> + },
> + {
> + .opcode = BT_HCI_EVT_LE_CS_PROC_ENABLE_COMPLETE,
> + .min_len = sizeof(struct bt_hci_evt_le_cs_proc_enable_complete),
> + .max_len = 0xFF,
> + .handler = rap_cs_proc_enable_cmplt_evt,
> + .name = "CS Procedure Enable Complete"
> + },
> + {
> + .opcode = BT_HCI_EVT_LE_CS_SUBEVENT_RESULT,
> + .min_len = sizeof(struct bt_hci_evt_le_cs_subevent_result),
> + .max_len = 0xFF,
> + .handler = rap_cs_subevt_result_evt,
> + .name = "CS Subevent Result"
> + },
> + {
> + .opcode = BT_HCI_EVT_LE_CS_SUBEVENT_RESULT_CONTINUE,
> + .min_len = sizeof(
> + struct bt_hci_evt_le_cs_subevent_result_continue),
> + .max_len = 0xFF,
> + .handler = rap_cs_subevt_result_cont_evt,
> + .name = "CS Subevent Result Continue"
> + }
> +};
> +
> +#define SUBEVENT_TABLE_SIZE ARRAY_SIZE(subevent_table)
> +
> +/* HCI Event Registration */
> +static void rap_handle_hci_events(const void *data, uint8_t size,
> + void *user_data)
> +{
> + struct iovec iov;
> + uint8_t subevent;
> + const struct subevent_entry *entry = NULL;
> + size_t i;
> +
> + /* Initialize iovec with the event data */
> + iov.iov_base = (void *)data;
> + iov.iov_len = size;
> +
> + /* Pull the subevent code */
> + if (!util_iov_pull_u8(&iov, &subevent)) {
> + DBG("Failed to parse subevent code");
> + return;
> + }
> +
> + /* Find the subevent in the table */
> + for (i = 0; i < SUBEVENT_TABLE_SIZE; i++) {
> + if (subevent_table[i].opcode == subevent) {
> + entry = &subevent_table[i];
> + break;
> + }
> + }
> +
> + /* Check if subevent is supported */
> + if (!entry) {
> + DBG("Unknown subevent: 0x%02X", subevent);
> + return;
> + }
> +
> + /* Validate payload length */
> + if (iov.iov_len < entry->min_len) {
> + DBG("%s: payload too short (%zu < %u)",
> + entry->name, iov.iov_len, entry->min_len);
> + return;
> + }
> +
> + if (entry->max_len != 0xFF && iov.iov_len > entry->max_len) {
> + DBG("%s: payload too long (%zu > %u)",
> + entry->name, iov.iov_len, entry->max_len);
> + return;
> + }
> +
> + /* Call the handler */
> + DBG("Handling %s (opcode=0x%02X, len=%zu)",
> + entry->name, subevent, iov.iov_len);
> +
> + entry->handler(iov.iov_base, iov.iov_len, user_data);
> +}
> +
> +void bt_rap_hci_register_events(struct bt_rap *rap, struct bt_hci *hci)
> +{
> + if (!rap || !hci)
> + return;
> +
> + sm = new0(struct cs_state_machine_t, 1);
> + if (!sm) {
> + DBG("[ERROR] Failed to allocate state machine\n");
> + return;
> + }
> +
> + cs_state_machine_init(sm, rap, hci);
> + sm->event_id = bt_hci_register(hci, BT_HCI_EVT_LE_META_EVENT,
> + rap_handle_hci_events, sm, NULL);
> +
> + DBG("bt_hci_register done, event_id : %d", sm->event_id);
> +
> + if (!sm->event_id) {
> + DBG("Error: Failed to register hci le meta events ");
> + DBG("event_id=0x%02X\n", sm->event_id);
> + free(sm);
> + return;
> + }
> +}
> +
> +bool bt_rap_attach_hci(struct bt_rap *rap, struct bt_hci *hci)
> +{
> + if (!rap)
> + return false;
> +
> + if (!hci) {
> + DBG("Failed to create HCI RAW channel ");
> + bt_hci_unref(hci);
> + return false;
> + }
> +
> + bt_rap_hci_register_events(rap, hci);
> +
> + return true;
> +}
> +
> +bool bt_rap_set_conn_handle(struct bt_rap *rap, uint16_t handle,
> + const uint8_t *bdaddr, uint8_t bdaddr_type)
> +{
> + struct bt_att *att;
> +
> + if (!rap)
> + return false;
> +
> + att = bt_rap_get_att(rap);
> + if (!att)
> + return false;
> +
> + DBG("Setting connection mapping: handle=0x%04X, ", handle);
> + if (bdaddr) {
> + DBG("bdaddr=%02x:%02x:%02x:%02x:%02x:%02x type=%u",
> + bdaddr[5], bdaddr[4], bdaddr[3],
> + bdaddr[2], bdaddr[1], bdaddr[0], bdaddr_type);
> + }
> +
> + return add_conn_mapping(handle, bdaddr, bdaddr_type, att, rap);
> +}
> +
> +void bt_rap_clear_conn_handle(struct bt_rap *rap, uint16_t handle)
> +{
> + if (!rap)
> + return;
> +
> + DBG("Clearing connection mapping: handle=0x%04X", handle);
> + remove_conn_mapping(handle);
> +}
> +
> +void bt_rap_detach_hci(struct bt_rap *rap)
> +{
> + if (!rap)
> + return;
> +
> + DBG("Detaching RAP from HCI, cleaning up mappings");
> +
> + /* Remove all mappings associated with this RAP instance */
> + remove_rap_mappings(rap);
> +}
> --
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH v7 0/8] Add support for handling PCIe M.2 Key E connectors in devicetree
From: Manivannan Sadhasivam @ 2026-04-13 14:02 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Rob Herring, Greg Kroah-Hartman, Jiri Slaby, Nathan Chancellor,
Nicolas Schier, Hans de Goede, Ilpo Järvinen, Mark Pearson,
Derek J. Clark, Manivannan Sadhasivam, Krzysztof Kozlowski,
Conor Dooley, Marcel Holtmann, Luiz Augusto von Dentz,
Bartosz Golaszewski, Andy Shevchenko, Bartosz Golaszewski,
linux-serial, linux-kernel, linux-kbuild, platform-driver-x86,
linux-pci, devicetree, linux-arm-msm, linux-bluetooth, linux-pm,
Stephan Gerhold, Dmitry Baryshkov, linux-acpi, Hans de Goede,
Bartosz Golaszewski
In-Reply-To: <20260413075459.GA2626902@google.com>
On Mon, Apr 13, 2026 at 03:54:59PM +0800, Chen-Yu Tsai wrote:
> Hi,
>
> On Thu, Mar 26, 2026 at 01:36:28PM +0530, Manivannan Sadhasivam wrote:
> > Hi,
> >
> > This series is the continuation of the series [1] that added the initial support
> > for the PCIe M.2 connectors. This series extends it by adding support for Key E
> > connectors. These connectors are used to connect the Wireless Connectivity
> > devices such as WiFi, BT, NFC and GNSS devices to the host machine over
> > interfaces such as PCIe/SDIO, USB/UART and NFC. This series adds support for
> > connectors that expose PCIe interface for WiFi and UART interface for BT. Other
> > interfaces are left for future improvements.
>
> Thanks for working on this. I started playing with it now that it is in
> -next. The PCIe part works fine. I'm looking into how to fit the pwrseq
>
> A couple questions:
>
> - Given that this connector actually represents two devices, how do I
> say I want the BT part to be a wakeup source, but not the WiFi part?
> Does wakeup-source even work at this point?
>
You can't use the DT property since the devices are not described in DT
statically. But you can still use the per-device 'wakeup' sysfs knob to enable
wakeup.
> - Are there plans to do the SDIO part?
>
No, not at the moment. Feel free to take it up if you have the hardware and
motivation :)
> - The matching done in the M.2 connector driver for pwrseq_get() seems a
> bit naive. It simply checks if the remote device in the OF graph is
> the same as the requesting device.
>
> I think this would run into issues with USB hubs. If I have a USB hub
> and two M.2 connectors, with both connectors connected to the same
> hub, pwrseq_get() is going to always return only one of the instances.
> This is because the USB hub has one device node with multiple OF graph
> ports.
>
Yeah, this is a known limitation. I'm trying to improve this part now and have
the WIP commits here: https://github.com/Mani-Sadhasivam/linux/tree/pwrseq-bt-en-fixes
Once the merge window closes, I'll submit these.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [GIT PULL] bluetooth-next 2026-04-13
From: Paolo Abeni @ 2026-04-13 13:41 UTC (permalink / raw)
To: Luiz Augusto von Dentz, davem, kuba; +Cc: linux-bluetooth, netdev
In-Reply-To: <20260413132247.320961-1-luiz.dentz@gmail.com>
On 4/13/26 3:22 PM, Luiz Augusto von Dentz wrote:
> The following changes since commit 42f9b4c6ef19e71d2c7d9bfd3c5037d4fe434ad7:
>
> tools: ynl: tests: fix leading space on Makefile target (2026-04-09 20:41:40 -0700)
>
> are available in the Git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git tags/for-net-next-2026-04-13
>
> for you to fetch changes up to c347ca17d62a32c25564fee0ca3a2a7bc2d5fd6f:
>
> Bluetooth: hci_qca: Fix missing wakeup during SSR memdump handling (2026-04-13 09:19:42 -0400)
>
> ----------------------------------------------------------------
> bluetooth-next pull request for net-next:
Net-next is closed for the merge window. I guess Jakub could still
consider merging this, but unless you want it very, very badly, I hope
it can just be postponed, as the PW queue is already long.
Thanks,
/P
^ permalink raw reply
* [GIT PULL] bluetooth-next 2026-04-13
From: Luiz Augusto von Dentz @ 2026-04-13 13:22 UTC (permalink / raw)
To: davem, kuba; +Cc: linux-bluetooth, netdev
The following changes since commit 42f9b4c6ef19e71d2c7d9bfd3c5037d4fe434ad7:
tools: ynl: tests: fix leading space on Makefile target (2026-04-09 20:41:40 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git tags/for-net-next-2026-04-13
for you to fetch changes up to c347ca17d62a32c25564fee0ca3a2a7bc2d5fd6f:
Bluetooth: hci_qca: Fix missing wakeup during SSR memdump handling (2026-04-13 09:19:42 -0400)
----------------------------------------------------------------
bluetooth-next pull request for net-next:
core:
- hci_core: Rate limit the logging of invalid ISO handle
- hci_sync: make hci_cmd_sync_run_once return -EEXIST if exists
- hci_event: fix locking in hci_conn_request_evt() with HCI_PROTO_DEFER
- hci_event: fix potential UAF in SSP passkey handlers
- HCI: Avoid a couple -Wflex-array-member-not-at-end warnings
- L2CAP: CoC: Disconnect if received packet size exceeds MPS
- L2CAP: Add missing chan lock in l2cap_ecred_reconf_rsp
- L2CAP: Fix printing wrong information if SDU length exceeds MTU
- SCO: check for codecs->num_codecs == 1 before assigning to sco_pi(sk)->codec
drivers:
- btusb: MT7922: Add VID/PID 0489/e174
- btusb: Add Lite-On 04ca:3807 for MediaTek MT7921
- btusb: Add MT7927 IDs ASUS ROG Crosshair X870E Hero, Lenovo Legion Pro 7
16ARX9, Gigabyte Z790 AORUS MASTER X, MSI X870E Ace Max, TP-Link
Archer TBE550E, ASUS X870E / ProArt X870E-Creator.
- btusb: Add MT7902 IDs 13d3/3579, 13d3/3580, 13d3/3594, 13d3/3596, 0e8d/1ede
- btusb: Add MT7902 IDs 13d3/3579, 13d3/3580, 13d3/3594, 13d3/3596, 0e8d/1ede
- btusb: MediaTek MT7922: Add VID 0489 & PID e11d
- btintel: Add support for Scorpious Peak2 support
- btintel: Add support for Scorpious Peak2F support
- btintel_pcie: Add device id of Scorpius Peak2, Nova Lake-PCD-H
- btintel_pcie: Add device id of Scorpious2, Nova Lake-PCD-S
- btmtk: Add reset mechanism if downloading firmware failed
- btmtk: Add MT6639 (MT7927) Bluetooth support
- btmtk: fix ISO interface setup for single alt setting
- btmtk: add MT7902 SDIO support
- Bluetooth: btmtk: add MT7902 MCU support
- btbcm: Add entry for BCM4343A2 UART Bluetooth
- qca: enable pwrseq support for wcn39xx devices
- hci_qca: Fix BT not getting powered-off on rmmod
- hci_qca: disable power control for WCN7850 when bt_en is not defined
- hci_qca: Fix missing wakeup during SSR memdump handling
- hci_ldisc: Clear HCI_UART_PROTO_INIT on error
- mmc: sdio: add MediaTek MT7902 SDIO device ID
- hci_ll: Enable BROKEN_ENHANCED_SETUP_SYNC_CONN for WL183x
----------------------------------------------------------------
Arnd Bergmann (1):
Bluetooth: btmtk: hide unused btmtk_mt6639_devs[] array
Chris Lu (4):
Bluetooth: btusb: MT7922: Add VID/PID 0489/e174
Bluetooth: btmtk: improve mt79xx firmware setup retry flow
Bluetooth: btmtk: add status check in mt79xx firmware setup
Bluetooth: btmtk: Add reset mechanism if downloading firmware failed
Christian Eggers (1):
Bluetooth: L2CAP: CoC: Disconnect if received packet size exceeds MPS
Dmitry Baryshkov (1):
Bluetooth: qca: enable pwrseq support for WCN39xx devices
Dongyang Jin (1):
Bluetooth: btbcm: remove done label in btbcm_patchram
Dudu Lu (1):
Bluetooth: l2cap: Add missing chan lock in l2cap_ecred_reconf_rsp
Dylan Eray (1):
Bluetooth: btusb: Add Lite-On 04ca:3807 for MediaTek MT7921
Gustavo A. R. Silva (1):
Bluetooth: hci.h: Avoid a couple -Wflex-array-member-not-at-end warnings
Hans de Goede (2):
Bluetooth: hci_qca: Fix confusing shutdown() and power_off() naming
Bluetooth: hci_qca: Fix BT not getting powered-off on rmmod
Javier Tia (8):
Bluetooth: btmtk: Add MT6639 (MT7927) Bluetooth support
Bluetooth: btmtk: fix ISO interface setup for single alt setting
Bluetooth: btusb: Add MT7927 ID for ASUS ROG Crosshair X870E Hero
Bluetooth: btusb: Add MT7927 ID for Lenovo Legion Pro 7 16ARX9
Bluetooth: btusb: Add MT7927 ID for Gigabyte Z790 AORUS MASTER X
Bluetooth: btusb: Add MT7927 ID for MSI X870E Ace Max
Bluetooth: btusb: Add MT7927 ID for TP-Link Archer TBE550E
Bluetooth: btusb: Add MT7927 ID for ASUS X870E / ProArt X870E-Creator
Johan Hovold (2):
Bluetooth: btusb: refactor endpoint lookup
Bluetooth: btmtk: refactor endpoint lookup
Jonathan Rissanen (1):
Bluetooth: hci_ldisc: Clear HCI_UART_PROTO_INIT on error
Kamiyama Chiaki (1):
Bluetooth: btusb: MediaTek MT7922: Add VID 0489 & PID e11d
Kiran K (10):
Bluetooth: btintel: Add support for hybrid signature for ScP2 onwards
Bluetooth: btintel: Replace CNVi id with hardware variant
Bluetooth: btintel: Add support for Scorpious Peak2 support
Bluetooth: btintel: Add DSBR support for ScP2 onwards
Bluetooth: btintel_pcie: Add support for exception dump for ScP2
Bluetooth: btintel: Add support for Scorpious Peak2F support
Bluetooth: btintel_pcie: Add support for exception dump for ScP2F
Bluetooth: btintel_pcie: Add device id of Scorpius Peak2, Nova Lake-PCD-H
Bluetooth: btintel_pcie: Add device id of Scorpious2, Nova Lake-PCD-S
Bluetooth: btintel_pcie: Align shared DMA memory to 128 bytes
Luiz Augusto von Dentz (2):
Bluetooth: btintel_pci: Fix btintel_pcie_read_hwexp code style
Bluetooth: L2CAP: Fix printing wrong information if SDU length exceeds MTU
Lukas Kraft (1):
bluetooth: btusb: Fix whitespace in btusb.c
Marek Vasut (1):
Bluetooth: btbcm: Add entry for BCM4343A2 UART Bluetooth
Pauli Virtanen (3):
Bluetooth: hci_core: Rate limit the logging of invalid ISO handle
Bluetooth: hci_sync: make hci_cmd_sync_run_once return -EEXIST if exists
Bluetooth: fix locking in hci_conn_request_evt() with HCI_PROTO_DEFER
Sean Wang (8):
mmc: sdio: add MediaTek MT7902 SDIO device ID
Bluetooth: btmtk: add MT7902 MCU support
Bluetooth: btusb: Add new VID/PID 13d3/3579 for MT7902
Bluetooth: btusb: Add new VID/PID 13d3/3580 for MT7902
Bluetooth: btusb: Add new VID/PID 13d3/3594 for MT7902
Bluetooth: btusb: Add new VID/PID 13d3/3596 for MT7902
Bluetooth: btusb: Add new VID/PID 0e8d/1ede for MT7902
Bluetooth: btmtk: add MT7902 SDIO support
Shuai Zhang (2):
Bluetooth: hci_qca: disable power control for WCN7850 when bt_en is not defined
Bluetooth: hci_qca: Fix missing wakeup during SSR memdump handling
Shuvam Pandey (1):
Bluetooth: hci_event: fix potential UAF in SSP passkey handlers
Stefan Metzmacher (1):
Bluetooth: SCO: check for codecs->num_codecs == 1 before assigning to sco_pi(sk)->codec
Stefano Radaelli (1):
Bluetooth: hci_ll: Enable BROKEN_ENHANCED_SETUP_SYNC_CONN for WL183x
Thorsten Blum (3):
Bluetooth: btintel_pcie: Replace snprintf("%s") with strscpy
Bluetooth: btintel_pcie: Use struct_size to improve hci_drv_read_info
Bluetooth: btintel_pcie: use strscpy to copy plain strings
Vivek Sahu (1):
Bluetooth: qca: Refactor code on the basis of chipset names
drivers/bluetooth/btbcm.c | 11 ++--
drivers/bluetooth/btintel.c | 109 ++++++++++++++++++++++++++++------
drivers/bluetooth/btintel.h | 20 +++++--
drivers/bluetooth/btintel_pcie.c | 122 ++++++++++++++++++++++++---------------
drivers/bluetooth/btintel_pcie.h | 3 -
drivers/bluetooth/btmtk.c | 115 ++++++++++++++++++++++++++----------
drivers/bluetooth/btmtk.h | 9 ++-
drivers/bluetooth/btmtksdio.c | 44 +++++++++-----
drivers/bluetooth/btqca.c | 37 ++++++------
drivers/bluetooth/btusb.c | 84 +++++++++++++--------------
drivers/bluetooth/hci_ldisc.c | 3 +
drivers/bluetooth/hci_ll.c | 10 ++++
drivers/bluetooth/hci_qca.c | 84 ++++++++++++++++-----------
include/linux/mmc/sdio_ids.h | 1 +
include/net/bluetooth/hci.h | 16 +++--
net/bluetooth/hci_conn.c | 4 +-
net/bluetooth/hci_core.c | 4 +-
net/bluetooth/hci_event.c | 21 ++++---
net/bluetooth/hci_sync.c | 2 +-
net/bluetooth/l2cap_core.c | 15 ++++-
net/bluetooth/sco.c | 3 +-
21 files changed, 476 insertions(+), 241 deletions(-)
^ permalink raw reply
* RE: Bluetooth: Add initial Channel Sounding
From: bluez.test.bot @ 2026-04-13 11:01 UTC (permalink / raw)
To: linux-bluetooth, naga.akella
In-Reply-To: <20260413104116.1605357-2-naga.akella@oss.qualcomm.com>
[-- Attachment #1: Type: text/plain, Size: 642 bytes --]
This is an automated email and please do not reply to this email.
Dear Submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
While preparing the CI tests, the patches you submitted couldn't be applied to the current HEAD of the repository.
----- Output -----
error: src/shared/hci.c: does not exist in index
error: src/shared/hci.h: does not exist in index
error: src/shared/rap.c: does not exist in index
error: src/shared/rap.h: does not exist in index
hint: Use 'git am --show-current-patch' to see the failed patch
Please resolve the issue and submit the patches again.
---
Regards,
Linux Bluetooth
^ permalink raw reply
* [PATCH BlueZ v4 3/3] profiles: ranging: Add HCI LE Event Handling in Reflector role
From: Naga Bhavani Akella @ 2026-04-13 10:41 UTC (permalink / raw)
To: linux-bluetooth
Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
prathibha.madugonde, Naga Bhavani Akella
In-Reply-To: <20260413104116.1605357-1-naga.akella@oss.qualcomm.com>
Open RAW HCI Channel for CS Event Handling
Parse the following HCI LE CS Events in reflector role
and route the events to RAP Profile.
1. HCI_EVT_LE_CS_READ_RMT_SUPP_CAP_COMPLETE
2. HCI_EVT_LE_CS_CONFIG_COMPLETE
3. HCI_EVT_LE_CS_SECURITY_ENABLE_COMPLETE
4. HCI_EVT_LE_CS_PROCEDURE_ENABLE_COMPLETE
5. HCI_EVT_LE_CS_SUBEVENT_RESULT
6. HCI_EVT_LE_CS_SUBEVENT_RESULT_CONTINUE
Send HCI_OP_LE_CS_SET_DEFAULT_SETTINGS to the controller
with default settings selected by the user.
Map connection handle received to device connection
---
Makefile.plugins | 3 +-
profiles/ranging/rap.c | 83 ++-
profiles/ranging/rap_hci.c | 1288 ++++++++++++++++++++++++++++++++++++
3 files changed, 1367 insertions(+), 7 deletions(-)
create mode 100644 profiles/ranging/rap_hci.c
diff --git a/Makefile.plugins b/Makefile.plugins
index c9efadb45..ac667beda 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -89,7 +89,8 @@ builtin_modules += battery
builtin_sources += profiles/battery/battery.c
builtin_modules += rap
-builtin_sources += profiles/ranging/rap.c
+builtin_sources += profiles/ranging/rap.c \
+ profiles/ranging/rap_hci.c
if SIXAXIS
builtin_modules += sixaxis
diff --git a/profiles/ranging/rap.c b/profiles/ranging/rap.c
index f03454c72..63682e318 100644
--- a/profiles/ranging/rap.c
+++ b/profiles/ranging/rap.c
@@ -17,6 +17,7 @@
#include "gdbus/gdbus.h"
#include "bluetooth/bluetooth.h"
+#include "bluetooth/l2cap.h"
#include "bluetooth/uuid.h"
#include "src/plugin.h"
@@ -34,12 +35,17 @@
#include "src/shared/rap.h"
#include "attrib/att.h"
#include "src/log.h"
+#include "src/btd.h"
+#define USE_BT_HCI_RAW_CHANNEL 1
struct rap_data {
struct btd_device *device;
struct btd_service *service;
struct bt_rap *rap;
unsigned int ready_id;
+#if USE_BT_HCI_RAW_CHANNEL
+ struct bt_hci *hci;
+#endif
};
static struct queue *sessions;
@@ -61,10 +67,10 @@ static void rap_debug(const char *str, void *user_data)
static void rap_data_add(struct rap_data *data)
{
- DBG("%p", data);
+ DBG("%p", (void *)data);
if (queue_find(sessions, NULL, data)) {
- error("data %p already added", data);
+ error("data %p already added", (void *)data);
return;
}
@@ -95,13 +101,21 @@ static void rap_data_free(struct rap_data *data)
}
bt_rap_ready_unregister(data->rap, data->ready_id);
+#if USE_BT_HCI_RAW_CHANNEL
+ if (data->hci) {
+ bt_rap_hci_sm_cleanup();
+ bt_hci_unref(data->hci);
+ }
+#endif
+ /* Clean up HCI connection mappings */
+ bt_rap_detach_hci(data->rap);
bt_rap_unref(data->rap);
free(data);
}
static void rap_data_remove(struct rap_data *data)
{
- DBG("%p", data);
+ DBG("%p", (void *)data);
if (!queue_remove(sessions, data))
return;
@@ -118,7 +132,7 @@ static void rap_detached(struct bt_rap *rap, void *user_data)
{
struct rap_data *data;
- DBG("%p", rap);
+ DBG("%p", (void *)rap);
data = queue_find(sessions, match_data, rap);
if (!data) {
@@ -131,7 +145,7 @@ static void rap_detached(struct bt_rap *rap, void *user_data)
static void rap_ready(struct bt_rap *rap, void *user_data)
{
- DBG("%p", rap);
+ DBG("%p", (void *)rap);
}
static void rap_attached(struct bt_rap *rap, void *user_data)
@@ -140,7 +154,7 @@ static void rap_attached(struct bt_rap *rap, void *user_data)
struct bt_att *att;
struct btd_device *device;
- DBG("%p", rap);
+ DBG("%p", (void *)rap);
data = queue_find(sessions, match_data, rap);
if (data) {
@@ -194,6 +208,22 @@ static int rap_probe(struct btd_service *service)
free(data);
return -EINVAL;
}
+#if USE_BT_HCI_RAW_CHANNEL
+ int16_t hci_index = btd_adapter_get_index(adapter);
+
+ data->hci = bt_hci_new_raw_device(hci_index);
+ if (bt_rap_attach_hci(data->rap, data->hci)) {
+ DBG("HCI raw channel initialized, hci%d", hci_index);
+ bt_rap_hci_set_le_bcs_options(
+ btd_opts.defaults.bcs.role,
+ btd_opts.defaults.bcs.cs_sync_ant_sel,
+ btd_opts.defaults.bcs.max_tx_power);
+ } else {
+ error("HCI raw channel not available (may be in use)");
+ }
+#else /* USE_BT_HCI_RAW_CHANNEL */
+ DBG("MGMT Events");
+#endif /* USE_BT_HCI_RAW_CHANNEL */
rap_data_add(data);
@@ -228,6 +258,10 @@ static int rap_accept(struct btd_service *service)
struct btd_device *device = btd_service_get_device(service);
struct bt_gatt_client *client = btd_device_get_gatt_client(device);
struct rap_data *data = btd_service_get_user_data(service);
+ struct bt_att *att;
+ const bdaddr_t *bdaddr;
+ uint8_t bdaddr_type;
+ uint16_t handle;
char addr[18];
ba2str(device_get_address(device), addr);
@@ -243,6 +277,43 @@ static int rap_accept(struct btd_service *service)
return -EINVAL;
}
+ /* Set up connection handle mapping for CS event routing */
+ att = bt_rap_get_att(data->rap);
+ bdaddr = device_get_address(device);
+ bdaddr_type = device_get_le_address_type(device);
+
+ if (att && data->hci) {
+ /* Use bt_hci_get_conn_info to find the connection handle
+ * by iterating through all connections and matching bdaddr
+ */
+ struct bt_hci_conn_info conn_info;
+ bool found = false;
+
+ /* Try handles from 0x0001 to 0x0EFF
+ * (valid LE connection handle range)
+ */
+ for (handle = 0x0001; handle <= 0x0EFF; handle++) {
+ if (bt_hci_get_conn_info(data->hci, handle,
+ &conn_info)) {
+ /* Check if bdaddr matches */
+ if (memcmp(conn_info.bdaddr, bdaddr, 6) == 0) {
+ found = true;
+ DBG("Found conn handle 0x%04X", handle);
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ DBG("Setting up handle mapping: handle=0x%04X", handle);
+ bt_rap_set_conn_handle(data->rap, handle,
+ (const uint8_t *)bdaddr,
+ bdaddr_type);
+ } else {
+ error("Failed to find connection handle for device");
+ }
+ }
+
btd_service_connecting_complete(service, 0);
return 0;
diff --git a/profiles/ranging/rap_hci.c b/profiles/ranging/rap_hci.c
new file mode 100644
index 000000000..b00719ae2
--- /dev/null
+++ b/profiles/ranging/rap_hci.c
@@ -0,0 +1,1288 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <string.h>
+#include <endian.h>
+
+#include "lib/bluetooth/bluetooth.h"
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
+#include "src/shared/rap.h"
+#include "src/log.h"
+#include "monitor/bt.h"
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+/* CS State Definitions */
+enum cs_state_t {
+ CS_INIT,
+ CS_STOPPED,
+ CS_STARTED,
+ CS_WAIT_CONFIG_CMPLT,
+ CS_WAIT_SEC_CMPLT,
+ CS_WAIT_PROC_CMPLT,
+ CS_HOLD,
+ CS_UNSPECIFIED
+};
+
+const char *state_names[] = {
+ "CS_INIT",
+ "CS_STOPPED",
+ "CS_STARTED",
+ "CS_WAIT_CONFIG_CMPLT",
+ "CS_WAIT_SEC_CMPLT",
+ "CS_WAIT_PROC_CMPLT",
+ "CS_HOLD",
+ "CS_UNSPECIFIED"
+};
+
+/* Callback Function Type */
+typedef void (*cs_callback_t)(uint16_t length,
+ const void *param, void *user_data);
+
+/* State Machine Context */
+struct cs_state_machine_t {
+ enum cs_state_t current_state;
+ enum cs_state_t old_state;
+ struct bt_hci *hci;
+ struct bt_rap *rap;
+ unsigned int event_id;
+ bool initiator;
+ bool procedure_active;
+};
+
+struct cs_callback_map_t {
+ enum cs_state_t state;
+ cs_callback_t callback;
+};
+
+struct cs_callback_map_t cs_callback_map[] = {
+ { CS_WAIT_CONFIG_CMPLT, bt_rap_hci_cs_config_complete_callback },
+ { CS_WAIT_SEC_CMPLT, bt_rap_hci_cs_sec_enable_complete_callback },
+ { CS_WAIT_PROC_CMPLT, bt_rap_hci_cs_procedure_enable_complete_callback }
+};
+
+#define CS_CALLBACK_MAP_SIZE ARRAY_SIZE(cs_callback_map)
+
+struct bt_rap_hci_cs_options cs_opt;
+struct cs_state_machine_t *sm;
+
+/* Connection Handle Mapping */
+struct rap_conn_mapping {
+ uint16_t handle;
+ uint8_t bdaddr[6];
+ uint8_t bdaddr_type;
+ struct bt_att *att;
+ struct bt_rap *rap;
+};
+
+static struct queue *conn_mappings;
+
+/* Connection Mapping Helper Functions */
+static void mapping_free(void *data)
+{
+ struct rap_conn_mapping *mapping = data;
+
+ if (!mapping)
+ return;
+
+ free(mapping);
+}
+
+static bool match_mapping_handle(const void *a, const void *b)
+{
+ const struct rap_conn_mapping *mapping = a;
+ uint16_t handle = PTR_TO_UINT(b);
+
+ return mapping->handle == handle;
+}
+
+static bool match_mapping_rap(const void *a, const void *b)
+{
+ const struct rap_conn_mapping *mapping = a;
+ const struct bt_rap *rap = b;
+
+ return mapping->rap == rap;
+}
+
+static struct rap_conn_mapping *find_mapping_by_handle(uint16_t handle)
+{
+ if (!conn_mappings)
+ return NULL;
+
+ return queue_find(conn_mappings, match_mapping_handle,
+ UINT_TO_PTR(handle));
+}
+
+static bool add_conn_mapping(uint16_t handle, const uint8_t *bdaddr,
+ uint8_t bdaddr_type, struct bt_att *att,
+ struct bt_rap *rap)
+{
+ struct rap_conn_mapping *mapping;
+
+ if (!conn_mappings) {
+ conn_mappings = queue_new();
+ if (!conn_mappings)
+ return false;
+ }
+
+ /* Check if mapping already exists */
+ mapping = find_mapping_by_handle(handle);
+ if (mapping) {
+ /* Update existing mapping */
+ if (bdaddr)
+ memcpy(mapping->bdaddr, bdaddr, 6);
+ mapping->bdaddr_type = bdaddr_type;
+ mapping->att = att;
+ mapping->rap = rap;
+ return true;
+ }
+
+ /* Create new mapping */
+ mapping = new0(struct rap_conn_mapping, 1);
+ if (!mapping)
+ return false;
+
+ mapping->handle = handle;
+ if (bdaddr)
+ memcpy(mapping->bdaddr, bdaddr, 6);
+ mapping->bdaddr_type = bdaddr_type;
+ mapping->att = att;
+ mapping->rap = rap;
+
+ return queue_push_tail(conn_mappings, mapping);
+}
+
+static void remove_conn_mapping(uint16_t handle)
+{
+ struct rap_conn_mapping *mapping;
+
+ if (!conn_mappings)
+ return;
+
+ mapping = queue_remove_if(conn_mappings, match_mapping_handle,
+ UINT_TO_PTR(handle));
+ if (mapping)
+ mapping_free(mapping);
+}
+
+static void remove_rap_mappings(struct bt_rap *rap)
+{
+ if (!conn_mappings)
+ return;
+
+ queue_remove_all(conn_mappings, match_mapping_rap, rap,
+ mapping_free);
+}
+
+static struct bt_rap *resolve_handle_to_rap(uint16_t handle,
+ struct bt_hci *hci)
+{
+ struct rap_conn_mapping *mapping;
+ struct bt_hci_conn_info conn_info;
+
+ /* First try to find in mapping cache */
+ mapping = find_mapping_by_handle(handle);
+ if (mapping && mapping->rap) {
+ DBG("Found handle 0x%04X in mapping cache", handle);
+ return mapping->rap;
+ }
+
+ /* Fallback: Try to get connection info via ioctl */
+ if (hci && bt_hci_get_conn_info(hci, handle, &conn_info)) {
+ DBG("Got connection info via ioctl for handle 0x%04X:", handle);
+ DBG(" bdaddr=%02x:%02x:%02x:%02x:%02x:%02x link_type=0x%02x",
+ conn_info.bdaddr[5], conn_info.bdaddr[4],
+ conn_info.bdaddr[3], conn_info.bdaddr[2],
+ conn_info.bdaddr[1], conn_info.bdaddr[0],
+ conn_info.type);
+ DBG(" Note: Cannot determine RAP instance from ioctl alone");
+ }
+
+ /* Profile layer should have called bt_rap_set_conn_handle() during
+ * connection establishment. If we reach here, the mapping was not set.
+ */
+ DBG("No mapping found for handle 0x%04X", handle);
+ DBG("Profile layer should call bt_rap_set_conn_handle() on connect");
+
+ return NULL;
+}
+
+/* State Machine Functions */
+void cs_state_machine_init(struct cs_state_machine_t *sm, struct bt_rap *rap,
+ struct bt_hci *hci)
+{
+ if (!sm)
+ return;
+
+ memset(sm, 0, sizeof(struct cs_state_machine_t));
+ sm->current_state = CS_UNSPECIFIED;
+ sm->rap = rap;
+ sm->hci = hci;
+ sm->initiator = false;
+ sm->procedure_active = false;
+}
+
+void bt_rap_hci_sm_cleanup(void)
+{
+ if (!sm)
+ return;
+
+ if (sm->event_id)
+ bt_hci_unregister(sm->hci, sm->event_id);
+
+ sm->current_state = CS_UNSPECIFIED;
+ sm->rap = NULL;
+ sm->hci = NULL;
+ sm->procedure_active = false;
+
+ free(sm);
+}
+
+void bt_rap_hci_set_le_bcs_options(uint8_t role, uint8_t cs_sync_ant_sel,
+ int8_t max_tx_power)
+{
+ cs_opt.role = role;
+ cs_opt.cs_sync_ant_sel = cs_sync_ant_sel;
+ cs_opt.max_tx_power = max_tx_power;
+}
+
+/* State Transition Logic */
+void cs_set_state(struct cs_state_machine_t *sm, enum cs_state_t new_state)
+{
+ if (!sm)
+ return;
+
+ if (sm->current_state == new_state)
+ return;
+
+ /* Validate state values before array access */
+ if (sm->current_state > CS_UNSPECIFIED || new_state > CS_UNSPECIFIED) {
+ DBG("[ERROR] Invalid state transition attempted\n");
+ return;
+ }
+
+ DBG("[STATE] Transition: %s → %s\n",
+ state_names[sm->current_state],
+ state_names[new_state]);
+
+ sm->old_state = sm->current_state;
+ sm->current_state = new_state;
+}
+
+enum cs_state_t cs_get_current_state(struct cs_state_machine_t *sm)
+{
+ return sm ? sm->current_state : CS_UNSPECIFIED;
+}
+
+bool cs_is_procedure_active(const struct cs_state_machine_t *sm)
+{
+ return sm ? sm->procedure_active : false;
+}
+
+/* HCI Event Callbacks */
+static void rap_def_settings_done_cb(const void *data, uint8_t size,
+ void *user_data)
+{
+ struct bt_hci_rsp_le_cs_set_def_settings *rp;
+ struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
+
+ if (!sm || !data ||
+ size < sizeof(struct bt_hci_rsp_le_cs_set_def_settings))
+ return;
+
+ DBG("[EVENT] CS default Setting Complete (size=0x%02X)\n", size);
+
+ rp = (struct bt_hci_rsp_le_cs_set_def_settings *)data;
+
+ if (cs_get_current_state(sm) != CS_INIT) {
+ DBG("Event received in Wrong State!! Expected : CS_INIT");
+ return;
+ }
+
+ if (rp->status == 0) {
+ /* Success - proceed to configuration */
+ cs_set_state(sm, CS_WAIT_CONFIG_CMPLT);
+
+ /* Reflector role */
+ DBG("Waiting for CS Config Completed event...\n");
+ /* TODO: Initiator role - Send CS Config complete cmd */
+ } else {
+ /* Error - transition to stopped */
+ DBG("[ERROR]CS Set default setting failed with status 0x%02X\n",
+ rp->status);
+ cs_set_state(sm, CS_STOPPED);
+ }
+}
+
+void rap_send_hci_def_settings_command(struct cs_state_machine_t *sm,
+ struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete *ev)
+{
+ struct bt_hci_cmd_le_cs_set_def_settings cp;
+ unsigned int status;
+
+ memset(&cp, 0, sizeof(cp));
+
+ if (ev->handle)
+ cp.handle = ev->handle;
+ cp.role_enable = cs_opt.role;
+ cp.cs_sync_antenna_selection = cs_opt.cs_sync_ant_sel;
+ cp.max_tx_power = cs_opt.max_tx_power;
+
+ if (!sm || !sm->hci) {
+ DBG("[ERR] Set Def Settings: sm or hci is null");
+ return;
+ }
+
+ status = bt_hci_send(sm->hci, BT_HCI_CMD_LE_CS_SET_DEF_SETTINGS,
+ &cp, sizeof(cp), rap_def_settings_done_cb,
+ sm, NULL);
+
+ DBG("sending set default settings case, status : %d", status);
+ if (!status)
+ DBG("Failed to send default settings cmd");
+}
+
+static void rap_rd_rmt_supp_cap_cmplt_evt(const uint8_t *data, uint8_t size,
+ void *user_data)
+{
+ struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
+ const struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete *evt;
+ struct bt_rap *rap;
+ struct iovec iov;
+
+ if (!sm || !data ||
+ size < sizeof(struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete))
+ return;
+
+ /* Initialize iovec with the event data */
+ iov.iov_base = (void *)data;
+ iov.iov_len = size;
+
+ /* Pull the entire structure at once */
+ evt = util_iov_pull_mem(&iov, sizeof(*evt));
+ if (!evt) {
+ DBG("[ERROR] Failed to pull remote cap complete struct\n");
+ return;
+ }
+
+ DBG("[EVENT] Remote Capabilities Complete\n");
+ DBG("status=0x%02X, handle=0x%04X\n", evt->status, evt->handle);
+
+ /* Check status */
+ if (evt->status != 0) {
+ DBG("[ERROR] Remote capabilities failed with status 0x%02X\n",
+ evt->status);
+ cs_set_state(sm, CS_STOPPED);
+ return;
+ }
+
+ /* Resolve handle to RAP instance */
+ rap = resolve_handle_to_rap(evt->handle, sm->hci);
+ if (!rap) {
+ DBG("[WARN] Could not resolve handle 0x%04X to RAP instance\n",
+ evt->handle);
+ /* Continue with state machine RAP for now */
+ rap = sm->rap;
+ }
+
+ DBG("[EVENT] Remote Capabilities: num_config=%u, ",
+ evt->num_config_supported);
+ DBG("max_consecutive_proc=%u, num_antennas=%u, ",
+ evt->max_consecutive_procedures_supported,
+ evt->num_antennas_supported);
+ DBG("max_antenna_paths=%u, roles=0x%02X, modes=0x%02X\n",
+ evt->max_antenna_paths_supported,
+ evt->roles_supported,
+ evt->modes_supported);
+
+ rap_send_hci_def_settings_command(sm,
+ (struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete *)evt);
+ cs_set_state(sm, CS_INIT);
+}
+
+static void rap_cs_config_cmplt_evt(const uint8_t *data, uint8_t size,
+ void *user_data)
+{
+ struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
+ const struct bt_hci_evt_le_cs_config_complete *evt;
+ struct rap_ev_cs_config_cmplt rap_ev;
+ struct iovec iov;
+
+ if (!sm || !data ||
+ size < sizeof(struct bt_hci_evt_le_cs_config_complete))
+ return;
+
+ /* Initialize iovec with the event data */
+ iov.iov_base = (void *)data;
+ iov.iov_len = size;
+
+ DBG("[EVENT] Configuration Complete (size=0x%02X)\n", size);
+
+ /* State Check */
+ if (cs_get_current_state(sm) != CS_WAIT_CONFIG_CMPLT) {
+ DBG("Event received in Wrong State!! ");
+ DBG("Expected : CS_WAIT_CONFIG_CMPLT");
+ return;
+ }
+
+ /* Pull the entire structure at once */
+ evt = util_iov_pull_mem(&iov, sizeof(*evt));
+ if (!evt) {
+ DBG("[ERROR] Failed to pull config complete struct\n");
+ return;
+ }
+
+ DBG("status=0x%02X, handle=0x%04X\n", evt->status, evt->handle);
+
+ /* Check status */
+ if (evt->status != 0) {
+ DBG("[ERROR] Configuration failed with status 0x%02X\n",
+ evt->status);
+ cs_set_state(sm, CS_STOPPED);
+ return;
+ }
+
+ /* Copy fields to rap_ev structure */
+ rap_ev.status = evt->status;
+ rap_ev.conn_hdl = cpu_to_le16(evt->handle);
+ rap_ev.config_id = evt->config_id;
+ rap_ev.action = evt->action;
+ rap_ev.main_mode_type = evt->main_mode_type;
+ rap_ev.sub_mode_type = evt->sub_mode_type;
+ rap_ev.min_main_mode_steps = evt->min_main_mode_steps;
+ rap_ev.max_main_mode_steps = evt->max_main_mode_steps;
+ rap_ev.main_mode_rep = evt->main_mode_repetition;
+ rap_ev.mode_0_steps = evt->mode_0_steps;
+ rap_ev.role = evt->role;
+ rap_ev.rtt_type = evt->rtt_type;
+ rap_ev.cs_sync_phy = evt->cs_sync_phy;
+ memcpy(rap_ev.channel_map, evt->channel_map, 10);
+ rap_ev.channel_map_rep = evt->channel_map_repetition;
+ rap_ev.channel_sel_type = evt->channel_selection_type;
+ rap_ev.ch3c_shape = evt->ch3c_shape;
+ rap_ev.ch3c_jump = evt->ch3c_jump;
+ rap_ev.reserved = evt->reserved;
+ rap_ev.t_ip1_time = evt->t_ip1_time;
+ rap_ev.t_ip2_time = evt->t_ip2_time;
+ rap_ev.t_fcs_time = evt->t_fcs_time;
+ rap_ev.t_pm_time = evt->t_pm_time;
+
+ /* Store rtt_type in global options */
+ cs_opt.rtt_type = rap_ev.rtt_type;
+
+ DBG("[EVENT] Config Complete: config_id=%u, action=%u, ",
+ rap_ev.config_id, rap_ev.action);
+ DBG("main_mode=%u, sub_mode=%u, role=%u, rtt_type=%u\n",
+ rap_ev.main_mode_type, rap_ev.sub_mode_type,
+ rap_ev.role, rap_ev.rtt_type);
+
+ /* Success - proceed to Security enable complete */
+ cs_set_state(sm, CS_WAIT_SEC_CMPLT);
+
+ /* Reflector role */
+ DBG("Waiting for security enable event...\n");
+ /* TODO: Initiator role - Send CS Security enable cmd */
+
+ /* Send Callback to RAP Profile */
+ for (size_t i = 0; i < CS_CALLBACK_MAP_SIZE; i++) {
+ if (cs_callback_map[i].state == sm->old_state) {
+ cs_callback_map[i].callback(size, &rap_ev, sm->rap);
+ return;
+ }
+ }
+}
+
+static void rap_cs_sec_enable_cmplt_evt(const uint8_t *data, uint8_t size,
+ void *user_data)
+{
+ struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
+ struct rap_ev_cs_sec_enable_cmplt rap_ev;
+ struct iovec iov;
+ uint8_t status;
+ uint16_t handle;
+
+ if (!sm || !data ||
+ size < sizeof(struct bt_hci_evt_le_cs_sec_enable_complete))
+ return;
+
+ /* Initialize iovec with the event data */
+ iov.iov_base = (void *)data;
+ iov.iov_len = size;
+
+ DBG("[EVENT] Security Enable Complete (size=0x%02X)\n", size);
+
+ /* State Check */
+ if (cs_get_current_state(sm) != CS_WAIT_SEC_CMPLT) {
+ DBG("Event received in Wrong State!! ");
+ DBG("Expected : CS_WAIT_SEC_CMPLT");
+ return;
+ }
+
+ /* Parse all fields in order using iovec */
+ if (!util_iov_pull_u8(&iov, &status)) {
+ DBG("[ERROR] Failed to parse Status\n");
+ return;
+ }
+
+ if (!util_iov_pull_le16(&iov, &handle)) {
+ DBG("[ERROR] Failed to parse Connection_Handle\n");
+ return;
+ }
+
+ rap_ev.status = status;
+ rap_ev.conn_hdl = cpu_to_le16(handle);
+
+ DBG("[EVENT] Security Enable: status=0x%02X, handle=0x%04X\n",
+ rap_ev.status, handle);
+
+ if (rap_ev.status == 0) {
+ /* Success - proceed to configuration */
+ cs_set_state(sm, CS_WAIT_PROC_CMPLT);
+
+ /* Reflector role */
+ DBG("Waiting for CS Proc complete event...\n");
+ /* TODO: Initiator - Send CS Proc Set Parameter and enable */
+ } else {
+ /* Error - transition to stopped */
+ DBG("[ERROR] Security enable failed with status 0x%02X\n",
+ rap_ev.status);
+ cs_set_state(sm, CS_STOPPED);
+ }
+
+ /* Send Callback to RAP Profile */
+ for (size_t i = 0; i < CS_CALLBACK_MAP_SIZE; i++) {
+ if (cs_callback_map[i].state == sm->old_state) {
+ cs_callback_map[i].callback(size, &rap_ev, sm->rap);
+ return;
+ }
+ }
+}
+
+static void rap_cs_proc_enable_cmplt_evt(const uint8_t *data, uint8_t size,
+ void *user_data)
+{
+ struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
+ const struct bt_hci_evt_le_cs_proc_enable_complete *evt;
+ struct rap_ev_cs_proc_enable_cmplt rap_ev;
+ struct iovec iov;
+
+ if (!sm || !data ||
+ size < sizeof(struct bt_hci_evt_le_cs_proc_enable_complete))
+ return;
+
+ /* Initialize iovec with the event data */
+ iov.iov_base = (void *)data;
+ iov.iov_len = size;
+
+ DBG("[EVENT] Procedure Enable Complete (size=0x%02X)\n", size);
+
+ /* State Check */
+ if (cs_get_current_state(sm) != CS_WAIT_PROC_CMPLT) {
+ DBG("Event received in Wrong State!! ");
+ DBG("Expected : CS_WAIT_PROC_CMPLT");
+ return;
+ }
+
+ /* Pull the entire structure at once */
+ evt = util_iov_pull_mem(&iov, sizeof(*evt));
+ if (!evt) {
+ DBG("[ERROR] Failed to pull proc enable complete struct\n");
+ return;
+ }
+
+ DBG("status=0x%02X, handle=0x%04X\n", evt->status, evt->handle);
+
+ /* Check status */
+ if (evt->status != 0) {
+ DBG("[ERROR] Procedure enable failed with status 0x%02X\n",
+ evt->status);
+ cs_set_state(sm, CS_STOPPED);
+ sm->procedure_active = false;
+ return;
+ }
+
+ /* Copy fields to rap_ev structure */
+ rap_ev.status = evt->status;
+ rap_ev.conn_hdl = cpu_to_le16(evt->handle);
+ rap_ev.config_id = evt->config_id;
+ rap_ev.state = evt->state;
+ rap_ev.tone_ant_config_sel = evt->tone_antenna_config_selection;
+ rap_ev.sel_tx_pwr = evt->selected_tx_power;
+ memcpy(rap_ev.sub_evt_len, evt->subevent_len, 3);
+ rap_ev.sub_evts_per_evt = evt->subevents_per_event;
+ rap_ev.sub_evt_intrvl = evt->subevent_interval;
+ rap_ev.evt_intrvl = evt->event_interval;
+ rap_ev.proc_intrvl = evt->procedure_interval;
+ rap_ev.proc_counter = evt->procedure_count;
+ rap_ev.max_proc_len = evt->max_procedure_len;
+
+ DBG("[EVENT] Procedure Enable: config_id=%u, state=%u, ",
+ rap_ev.config_id, rap_ev.state);
+ DBG("sub_evts_per_evt=%u, evt_intrvl=%u, proc_intrvl=%u\n",
+ rap_ev.sub_evts_per_evt, rap_ev.evt_intrvl,
+ rap_ev.proc_intrvl);
+
+ /* Success - procedure started */
+ cs_set_state(sm, CS_STARTED);
+ sm->procedure_active = true;
+
+ /* Send Callback to RAP Profile */
+ for (size_t i = 0; i < CS_CALLBACK_MAP_SIZE; i++) {
+ if (cs_callback_map[i].state == sm->old_state) {
+ cs_callback_map[i].callback(size, &rap_ev, sm->rap);
+ return;
+ }
+ }
+}
+
+static void parse_i_q_sample(struct iovec *iov, int16_t *i_sample,
+ int16_t *q_sample)
+{
+ uint8_t bytes[3];
+ uint32_t buffer;
+ uint32_t i12;
+ uint32_t q12;
+
+ /* Pull 3 bytes from iovec */
+ if (!util_iov_pull_u8(iov, &bytes[0]) ||
+ !util_iov_pull_u8(iov, &bytes[1]) ||
+ !util_iov_pull_u8(iov, &bytes[2])) {
+ *i_sample = 0;
+ *q_sample = 0;
+ return;
+ }
+
+ /* Reconstruct 24-bit buffer from 3 bytes */
+ buffer = (uint32_t)bytes[0] | ((uint32_t)bytes[1] << 8) |
+ ((uint32_t)bytes[2] << 16);
+ i12 = buffer & 0x0FFFU; /* bits 0..11 */
+ q12 = (buffer >> 12) & 0x0FFFU; /* bits 12..23 */
+
+ /* Sign-extend 12-bit values to 16-bit */
+ *i_sample = (int16_t)((int32_t)(i12 << 20) >> 20);
+ *q_sample = (int16_t)((int32_t)(q12 << 20) >> 20);
+}
+
+/* Parse CS Mode 0 step data */
+static void parse_mode_zero_data(struct iovec *iov,
+ struct cs_mode_zero_data *mode_data,
+ uint8_t cs_role)
+{
+ uint32_t freq_offset;
+
+ if (iov->iov_len < 3) {
+ DBG("Mode 0: too short (<3)");
+ return;
+ }
+
+ util_iov_pull_u8(iov, &mode_data->packet_quality);
+ util_iov_pull_u8(iov, &mode_data->packet_rssi_dbm);
+ util_iov_pull_u8(iov, &mode_data->packet_ant);
+ DBG("CS Step mode 0");
+
+ if (cs_role == CS_INITIATOR && iov->iov_len >= 4) {
+ util_iov_pull_le32(iov, &freq_offset);
+ mode_data->init_measured_freq_offset = freq_offset;
+ }
+}
+
+/* Parse CS Mode 1 step data */
+static void parse_mode_one_data(struct iovec *iov,
+ struct cs_mode_one_data *mode_data,
+ uint8_t cs_role, uint8_t cs_rtt_type)
+{
+ uint16_t time_val;
+
+ if (iov->iov_len < 4) {
+ DBG("Mode 1: too short (<4)");
+ return;
+ }
+
+ DBG("CS Step mode 1");
+ util_iov_pull_u8(iov, &mode_data->packet_quality);
+ util_iov_pull_u8(iov, &mode_data->packet_rssi_dbm);
+ util_iov_pull_u8(iov, &mode_data->packet_ant);
+ util_iov_pull_u8(iov, &mode_data->packet_nadm);
+
+ if (iov->iov_len >= 2) {
+ util_iov_pull_le16(iov, &time_val);
+ if (cs_role == CS_REFLECTOR)
+ mode_data->tod_toa_refl = time_val;
+ else
+ mode_data->toa_tod_init = time_val;
+ }
+
+ if ((cs_rtt_type == 0x01 || cs_rtt_type == 0x02) &&
+ iov->iov_len >= 6) {
+ int16_t i_val, q_val;
+
+ parse_i_q_sample(iov, &i_val, &q_val);
+ mode_data->packet_pct1.i_sample = i_val;
+ mode_data->packet_pct1.q_sample = q_val;
+
+ parse_i_q_sample(iov, &i_val, &q_val);
+ mode_data->packet_pct2.i_sample = i_val;
+ mode_data->packet_pct2.q_sample = q_val;
+ }
+}
+
+/* Parse CS Mode 2 step data */
+static void parse_mode_two_data(struct iovec *iov,
+ struct cs_mode_two_data *mode_data,
+ uint8_t max_paths)
+{
+ uint8_t k;
+
+ if (iov->iov_len < 1) {
+ DBG("Mode 2: too short (<1)");
+ return;
+ }
+
+ util_iov_pull_u8(iov, &mode_data->ant_perm_index);
+ DBG("CS Step mode 2, max paths : %d", max_paths);
+
+ for (k = 0; k < max_paths; k++) {
+ int16_t i_val, q_val;
+
+ if (iov->iov_len < 4) {
+ DBG("Mode 2: insufficient PCT for path %u (rem=%zu)",
+ k, iov->iov_len);
+ break;
+ }
+ parse_i_q_sample(iov, &i_val, &q_val);
+ mode_data->tone_pct[k].i_sample = i_val;
+ mode_data->tone_pct[k].q_sample = q_val;
+
+ util_iov_pull_u8(iov, &mode_data->tone_quality_indicator[k]);
+ DBG("tone_quality_indicator : %d",
+ mode_data->tone_quality_indicator[k]);
+ DBG("[i, q] : %d, %d",
+ mode_data->tone_pct[k].i_sample,
+ mode_data->tone_pct[k].q_sample);
+ }
+}
+
+/* Parse CS Mode 3 step data */
+static void parse_mode_three_data(struct iovec *iov,
+ struct cs_mode_three_data *mode_data,
+ uint8_t cs_role, uint8_t cs_rtt_type,
+ uint8_t max_paths)
+{
+ uint8_t k;
+ struct cs_mode_one_data *mode_one = &mode_data->mode_one_data;
+ struct cs_mode_two_data *mode_two = &mode_data->mode_two_data;
+
+ if (iov->iov_len < 4) {
+ DBG("Mode 3: mode1 too short (<4)");
+ return;
+ }
+
+ DBG("CS Step mode 3");
+
+ /* Parse Mode 1 portion */
+ parse_mode_one_data(iov, mode_one, cs_role, cs_rtt_type);
+
+ /* Parse Mode 2 portion */
+ if (iov->iov_len >= 1) {
+ util_iov_pull_u8(iov, &mode_two->ant_perm_index);
+ for (k = 0; k < max_paths; k++) {
+ int16_t i_val, q_val;
+
+ if (iov->iov_len < 4)
+ break;
+ parse_i_q_sample(iov, &i_val, &q_val);
+ mode_two->tone_pct[k].i_sample = i_val;
+ mode_two->tone_pct[k].q_sample = q_val;
+
+ util_iov_pull_u8(iov,
+ &mode_two->tone_quality_indicator[k]);
+ }
+ }
+}
+
+/* Parse a single CS step */
+static void parse_cs_step(struct iovec *iov, struct cs_step_data *step,
+ uint8_t cs_role, uint8_t cs_rtt_type,
+ uint8_t max_paths)
+{
+ uint8_t mode;
+ uint8_t chnl;
+ uint8_t length;
+
+ /* Check if we have enough data for the 3-byte header */
+ if (iov->iov_len < 3) {
+ DBG("Truncated header for step");
+ return;
+ }
+
+ /* Read mode, channel, and length (3-byte header) */
+ if (!util_iov_pull_u8(iov, &mode) ||
+ !util_iov_pull_u8(iov, &chnl) ||
+ !util_iov_pull_u8(iov, &length)) {
+ DBG("Failed to read header for step");
+ return;
+ }
+
+ DBG("event->step_data_len : %d", length);
+
+ step->step_mode = mode;
+ step->step_chnl = chnl;
+ step->step_data_length = length;
+
+ DBG("Step: mode=%u chnl=%u data_len=%u", mode, chnl, length);
+
+ if (iov->iov_len < length) {
+ DBG("Truncated payload for step (need %u, have %zu)",
+ length, iov->iov_len);
+ return;
+ }
+
+ /* Parse step data based on mode */
+ switch (mode) {
+ case CS_MODE_ZERO:
+ parse_mode_zero_data(iov, &step->step_mode_data.mode_zero_data,
+ cs_role);
+ break;
+ case CS_MODE_ONE:
+ parse_mode_one_data(iov, &step->step_mode_data.mode_one_data,
+ cs_role, cs_rtt_type);
+ break;
+ case CS_MODE_TWO:
+ parse_mode_two_data(iov, &step->step_mode_data.mode_two_data,
+ max_paths);
+ break;
+ case CS_MODE_THREE:
+ parse_mode_three_data(iov,
+ &step->step_mode_data.mode_three_data,
+ cs_role, cs_rtt_type, max_paths);
+ break;
+ default:
+ DBG("Unknown step mode %d", mode);
+ /* Skip the entire step data */
+ util_iov_pull(iov, length);
+ break;
+ }
+}
+
+static void rap_cs_subevt_result_evt(const uint8_t *data, uint8_t size,
+ void *user_data)
+{
+ struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
+ struct rap_ev_cs_subevent_result *rap_ev;
+ struct iovec iov;
+ uint8_t cs_role;
+ uint8_t cs_rtt_type;
+ uint8_t max_paths;
+ uint8_t steps;
+ size_t send_len = 0;
+ uint16_t handle;
+ uint8_t config_id;
+ uint16_t start_acl_conn_evt_counter;
+ uint16_t proc_counter;
+ uint16_t freq_comp;
+ uint8_t ref_pwr_lvl;
+ uint8_t proc_done_status;
+ uint8_t subevt_done_status;
+ uint8_t abort_reason;
+ uint8_t num_ant_paths;
+ uint8_t num_steps_reported;
+ uint8_t i;
+
+ if (!sm || !data ||
+ size < sizeof(struct bt_hci_evt_le_cs_subevent_result))
+ return;
+
+ /* Initialize iovec with the event data */
+ iov.iov_base = (void *)data;
+ iov.iov_len = size;
+
+ /* Check if Procedure is active or not */
+ if (!sm->procedure_active) {
+ DBG("Received Subevent event when Procedure is inactive!");
+ return;
+ }
+
+ /* Parse header fields using iovec */
+ if (!util_iov_pull_le16(&iov, &handle)) {
+ DBG("[ERROR] Failed to parse Connection_Handle\n");
+ return;
+ }
+
+ if (!util_iov_pull_u8(&iov, &config_id) ||
+ !util_iov_pull_le16(&iov, &start_acl_conn_evt_counter) ||
+ !util_iov_pull_le16(&iov, &proc_counter) ||
+ !util_iov_pull_le16(&iov, &freq_comp) ||
+ !util_iov_pull_u8(&iov, &ref_pwr_lvl) ||
+ !util_iov_pull_u8(&iov, &proc_done_status) ||
+ !util_iov_pull_u8(&iov, &subevt_done_status) ||
+ !util_iov_pull_u8(&iov, &abort_reason) ||
+ !util_iov_pull_u8(&iov, &num_ant_paths) ||
+ !util_iov_pull_u8(&iov, &num_steps_reported)) {
+ DBG("[ERROR] Failed to parse subevent fields\n");
+ return;
+ }
+
+ cs_role = cs_opt.role;
+ cs_rtt_type = cs_opt.rtt_type;
+ max_paths = MIN((num_ant_paths + 1), CS_MAX_ANT_PATHS);
+ steps = MIN(num_steps_reported, CS_MAX_STEPS);
+ send_len = offsetof(struct rap_ev_cs_subevent_result, step_data) +
+ steps * sizeof(struct cs_step_data);
+ rap_ev = (struct rap_ev_cs_subevent_result *)malloc(send_len);
+ if (!rap_ev) {
+ DBG("[ERROR] Failed to allocate memory for subevent result\n");
+ return;
+ }
+
+ DBG("[EVENT] Subevent Result (length=%u)\n", size);
+ rap_ev->conn_hdl = le16_to_cpu(handle);
+ rap_ev->config_id = config_id;
+ rap_ev->start_acl_conn_evt_counter = start_acl_conn_evt_counter;
+ rap_ev->proc_counter = proc_counter;
+ rap_ev->freq_comp = freq_comp;
+ rap_ev->ref_pwr_lvl = ref_pwr_lvl;
+ rap_ev->proc_done_status = proc_done_status;
+ rap_ev->subevt_done_status = subevt_done_status;
+ rap_ev->abort_reason = abort_reason;
+ rap_ev->num_ant_paths = num_ant_paths;
+ rap_ev->num_steps_reported = steps;
+
+ if (num_steps_reported > CS_MAX_STEPS) {
+ DBG("Too many steps reported: %u (max %u)",
+ num_steps_reported, CS_MAX_STEPS);
+ goto send_event;
+ }
+
+ /* Early exit for error conditions */
+ if (rap_ev->subevt_done_status == 0xF ||
+ rap_ev->proc_done_status == 0xF) {
+ DBG("CS Procedure/Subevent aborted: ");
+ DBG("sub evt status = %d, proc status = %d, reason = %d",
+ rap_ev->subevt_done_status, rap_ev->proc_done_status,
+ rap_ev->abort_reason);
+ goto send_event;
+ }
+
+ /* Parse interleaved step data from remaining iovec data */
+ for (i = 0; i < steps; i++)
+ parse_cs_step(&iov, &rap_ev->step_data[i], cs_role, cs_rtt_type,
+ max_paths);
+
+send_event:
+ DBG("CS subevent result processed: %zu bytes, ", send_len);
+ bt_rap_hci_cs_subevent_result_callback(send_len, rap_ev, sm->rap);
+ free(rap_ev);
+}
+
+static void rap_cs_subevt_result_cont_evt(const uint8_t *data, uint8_t size,
+ void *user_data)
+{
+ struct cs_state_machine_t *sm = (struct cs_state_machine_t *)user_data;
+ struct rap_ev_cs_subevent_result_cont *rap_ev;
+ struct iovec iov;
+ uint8_t cs_role;
+ uint8_t cs_rtt_type;
+ uint8_t max_paths;
+ uint8_t steps;
+ size_t send_len = 0;
+ uint16_t handle;
+ uint8_t config_id;
+ uint8_t proc_done_status;
+ uint8_t subevt_done_status;
+ uint8_t abort_reason;
+ uint8_t num_ant_paths;
+ uint8_t num_steps_reported;
+ uint8_t i;
+
+ if (!sm || !data ||
+ size < sizeof(struct bt_hci_evt_le_cs_subevent_result_continue))
+ return;
+
+ /* Initialize iovec with the event data */
+ iov.iov_base = (void *)data;
+ iov.iov_len = size;
+
+ /* Check if Procedure is active or not */
+ if (!sm->procedure_active) {
+ DBG("Received Subevent when CS Procedure is inactive!");
+ return;
+ }
+
+ /* Parse header fields using iovec */
+ if (!util_iov_pull_le16(&iov, &handle)) {
+ DBG("[ERROR] Failed to parse Connection_Handle\n");
+ return;
+ }
+
+ if (!util_iov_pull_u8(&iov, &config_id) ||
+ !util_iov_pull_u8(&iov, &proc_done_status) ||
+ !util_iov_pull_u8(&iov, &subevt_done_status) ||
+ !util_iov_pull_u8(&iov, &abort_reason) ||
+ !util_iov_pull_u8(&iov, &num_ant_paths) ||
+ !util_iov_pull_u8(&iov, &num_steps_reported)) {
+ DBG("[ERROR] Failed to parse subevent continue fields ");
+ return;
+ }
+
+ cs_role = cs_opt.role;
+ cs_rtt_type = cs_opt.rtt_type;
+ max_paths = MIN((num_ant_paths + 1), CS_MAX_ANT_PATHS);
+ steps = MIN(num_steps_reported, CS_MAX_STEPS);
+ send_len = offsetof(struct rap_ev_cs_subevent_result_cont, step_data) +
+ steps * sizeof(struct cs_step_data);
+ rap_ev = (struct rap_ev_cs_subevent_result_cont *)malloc(send_len);
+ if (!rap_ev) {
+ DBG("[ERROR] Failed to allocate memory for subevent result\n");
+ return;
+ }
+
+ DBG("[EVENT] Subevent Result Cont (length=%u)\n", size);
+ rap_ev->conn_hdl = le16_to_cpu(handle);
+ rap_ev->config_id = config_id;
+ rap_ev->proc_done_status = proc_done_status;
+ rap_ev->subevt_done_status = subevt_done_status;
+ rap_ev->abort_reason = abort_reason;
+ rap_ev->num_ant_paths = num_ant_paths;
+ rap_ev->num_steps_reported = steps;
+
+ if (num_steps_reported > CS_MAX_STEPS) {
+ DBG("Too many steps reported: %u (max %u)",
+ num_steps_reported, CS_MAX_STEPS);
+ goto send_event;
+ }
+
+ /* Early exit for error conditions */
+ if (rap_ev->subevt_done_status == 0xF ||
+ rap_ev->proc_done_status == 0xF) {
+ DBG("CS Procedure/Subevent aborted: ");
+ DBG("sub evt status = %d, proc status = %d, reason = %d",
+ rap_ev->subevt_done_status, rap_ev->proc_done_status,
+ rap_ev->abort_reason);
+ goto send_event;
+ }
+
+ /* Parse interleaved step data from remaining iovec data */
+ for (i = 0; i < steps; i++)
+ parse_cs_step(&iov, &rap_ev->step_data[i], cs_role, cs_rtt_type,
+ max_paths);
+
+send_event:
+ DBG("CS subevent result cont processed: %zu bytes, ", send_len);
+ bt_rap_hci_cs_subevent_result_cont_callback(send_len, rap_ev, sm->rap);
+ free(rap_ev);
+}
+
+/* Subevent handler function type */
+typedef void (*subevent_handler_t)(const uint8_t *data, uint8_t size,
+ void *user_data);
+
+/* Subevent table entry */
+struct subevent_entry {
+ uint8_t opcode;
+ uint8_t min_len;
+ uint8_t max_len;
+ subevent_handler_t handler;
+ const char *name;
+};
+
+/* Subevent dispatch table */
+static const struct subevent_entry subevent_table[] = {
+ {
+ .opcode = BT_HCI_EVT_LE_CS_RD_REM_SUPP_CAP_COMPLETE,
+ .min_len = sizeof(
+ struct bt_hci_evt_le_cs_rd_rem_supp_cap_complete),
+ .max_len = 0xFF,
+ .handler = rap_rd_rmt_supp_cap_cmplt_evt,
+ .name = "CS Read Remote Supported Capabilities Complete"
+ },
+ {
+ .opcode = BT_HCI_EVT_LE_CS_CONFIG_COMPLETE,
+ .min_len = sizeof(struct bt_hci_evt_le_cs_config_complete),
+ .max_len = 0xFF,
+ .handler = rap_cs_config_cmplt_evt,
+ .name = "CS Config Complete"
+ },
+ {
+ .opcode = BT_HCI_EVT_LE_CS_SEC_ENABLE_COMPLETE,
+ .min_len = sizeof(struct bt_hci_evt_le_cs_sec_enable_complete),
+ .max_len = 0xFF,
+ .handler = rap_cs_sec_enable_cmplt_evt,
+ .name = "CS Security Enable Complete"
+ },
+ {
+ .opcode = BT_HCI_EVT_LE_CS_PROC_ENABLE_COMPLETE,
+ .min_len = sizeof(struct bt_hci_evt_le_cs_proc_enable_complete),
+ .max_len = 0xFF,
+ .handler = rap_cs_proc_enable_cmplt_evt,
+ .name = "CS Procedure Enable Complete"
+ },
+ {
+ .opcode = BT_HCI_EVT_LE_CS_SUBEVENT_RESULT,
+ .min_len = sizeof(struct bt_hci_evt_le_cs_subevent_result),
+ .max_len = 0xFF,
+ .handler = rap_cs_subevt_result_evt,
+ .name = "CS Subevent Result"
+ },
+ {
+ .opcode = BT_HCI_EVT_LE_CS_SUBEVENT_RESULT_CONTINUE,
+ .min_len = sizeof(
+ struct bt_hci_evt_le_cs_subevent_result_continue),
+ .max_len = 0xFF,
+ .handler = rap_cs_subevt_result_cont_evt,
+ .name = "CS Subevent Result Continue"
+ }
+};
+
+#define SUBEVENT_TABLE_SIZE ARRAY_SIZE(subevent_table)
+
+/* HCI Event Registration */
+static void rap_handle_hci_events(const void *data, uint8_t size,
+ void *user_data)
+{
+ struct iovec iov;
+ uint8_t subevent;
+ const struct subevent_entry *entry = NULL;
+ size_t i;
+
+ /* Initialize iovec with the event data */
+ iov.iov_base = (void *)data;
+ iov.iov_len = size;
+
+ /* Pull the subevent code */
+ if (!util_iov_pull_u8(&iov, &subevent)) {
+ DBG("Failed to parse subevent code");
+ return;
+ }
+
+ /* Find the subevent in the table */
+ for (i = 0; i < SUBEVENT_TABLE_SIZE; i++) {
+ if (subevent_table[i].opcode == subevent) {
+ entry = &subevent_table[i];
+ break;
+ }
+ }
+
+ /* Check if subevent is supported */
+ if (!entry) {
+ DBG("Unknown subevent: 0x%02X", subevent);
+ return;
+ }
+
+ /* Validate payload length */
+ if (iov.iov_len < entry->min_len) {
+ DBG("%s: payload too short (%zu < %u)",
+ entry->name, iov.iov_len, entry->min_len);
+ return;
+ }
+
+ if (entry->max_len != 0xFF && iov.iov_len > entry->max_len) {
+ DBG("%s: payload too long (%zu > %u)",
+ entry->name, iov.iov_len, entry->max_len);
+ return;
+ }
+
+ /* Call the handler */
+ DBG("Handling %s (opcode=0x%02X, len=%zu)",
+ entry->name, subevent, iov.iov_len);
+
+ entry->handler(iov.iov_base, iov.iov_len, user_data);
+}
+
+void bt_rap_hci_register_events(struct bt_rap *rap, struct bt_hci *hci)
+{
+ if (!rap || !hci)
+ return;
+
+ sm = new0(struct cs_state_machine_t, 1);
+ if (!sm) {
+ DBG("[ERROR] Failed to allocate state machine\n");
+ return;
+ }
+
+ cs_state_machine_init(sm, rap, hci);
+ sm->event_id = bt_hci_register(hci, BT_HCI_EVT_LE_META_EVENT,
+ rap_handle_hci_events, sm, NULL);
+
+ DBG("bt_hci_register done, event_id : %d", sm->event_id);
+
+ if (!sm->event_id) {
+ DBG("Error: Failed to register hci le meta events ");
+ DBG("event_id=0x%02X\n", sm->event_id);
+ free(sm);
+ return;
+ }
+}
+
+bool bt_rap_attach_hci(struct bt_rap *rap, struct bt_hci *hci)
+{
+ if (!rap)
+ return false;
+
+ if (!hci) {
+ DBG("Failed to create HCI RAW channel ");
+ bt_hci_unref(hci);
+ return false;
+ }
+
+ bt_rap_hci_register_events(rap, hci);
+
+ return true;
+}
+
+bool bt_rap_set_conn_handle(struct bt_rap *rap, uint16_t handle,
+ const uint8_t *bdaddr, uint8_t bdaddr_type)
+{
+ struct bt_att *att;
+
+ if (!rap)
+ return false;
+
+ att = bt_rap_get_att(rap);
+ if (!att)
+ return false;
+
+ DBG("Setting connection mapping: handle=0x%04X, ", handle);
+ if (bdaddr) {
+ DBG("bdaddr=%02x:%02x:%02x:%02x:%02x:%02x type=%u",
+ bdaddr[5], bdaddr[4], bdaddr[3],
+ bdaddr[2], bdaddr[1], bdaddr[0], bdaddr_type);
+ }
+
+ return add_conn_mapping(handle, bdaddr, bdaddr_type, att, rap);
+}
+
+void bt_rap_clear_conn_handle(struct bt_rap *rap, uint16_t handle)
+{
+ if (!rap)
+ return;
+
+ DBG("Clearing connection mapping: handle=0x%04X", handle);
+ remove_conn_mapping(handle);
+}
+
+void bt_rap_detach_hci(struct bt_rap *rap)
+{
+ if (!rap)
+ return;
+
+ DBG("Detaching RAP from HCI, cleaning up mappings");
+
+ /* Remove all mappings associated with this RAP instance */
+ remove_rap_mappings(rap);
+}
--
^ permalink raw reply related
* [PATCH BlueZ v4 2/3] bluetooth: Add Channel Sounding config parsing support
From: Naga Bhavani Akella @ 2026-04-13 10:41 UTC (permalink / raw)
To: linux-bluetooth
Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
prathibha.madugonde, Naga Bhavani Akella
In-Reply-To: <20260413104116.1605357-1-naga.akella@oss.qualcomm.com>
Add support for parsing Channel Sounding (CS) configuration options
from the configuration file.
Add CAP_NET_RAW to CapabilityBoundingSet in bluetooth.service.
bluetoothd requires CAP_NET_RAW to receive and process HCI LE events
when running under a constrained systemd capability bounding set
---
src/bluetooth.service.in | 2 +-
src/btd.h | 7 +++
src/main.c | 129 +++++++++++++++++++++++++++++++++++++++
src/main.conf | 24 ++++++++
4 files changed, 161 insertions(+), 1 deletion(-)
diff --git a/src/bluetooth.service.in b/src/bluetooth.service.in
index 8ebe89bec..8dcbde236 100644
--- a/src/bluetooth.service.in
+++ b/src/bluetooth.service.in
@@ -10,7 +10,7 @@ ExecStart=@PKGLIBEXECDIR@/bluetoothd
NotifyAccess=main
#WatchdogSec=10
#Restart=on-failure
-CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
+CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN CAP_NET_BIND_SERVICE
LimitNPROC=1
# Filesystem lockdown
diff --git a/src/btd.h b/src/btd.h
index c84a600d1..db2e81239 100644
--- a/src/btd.h
+++ b/src/btd.h
@@ -94,11 +94,18 @@ struct btd_le_defaults {
uint8_t enable_advmon_interleave_scan;
};
+struct btd_le_bcs {
+ uint8_t role;
+ uint8_t cs_sync_ant_sel;
+ int8_t max_tx_power;
+};
+
struct btd_defaults {
uint16_t num_entries;
struct btd_br_defaults br;
struct btd_le_defaults le;
+ struct btd_le_bcs bcs;
};
struct btd_csis {
diff --git a/src/main.c b/src/main.c
index 818f7c06e..d3a2528e3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -156,6 +156,13 @@ static const char *gatt_options[] = {
NULL
};
+static const char *bcs_options[] = {
+ "Role",
+ "CsSyncAntennaSel",
+ "MaxTxPower",
+ NULL
+};
+
static const char *csip_options[] = {
"SIRK",
"Encryption",
@@ -193,6 +200,7 @@ static const struct group_table {
{ "CSIS", csip_options },
{ "AVDTP", avdtp_options },
{ "AVRCP", avrcp_options },
+ { "ChannelSounding", bcs_options },
{ "AdvMon", advmon_options },
{ }
};
@@ -492,6 +500,46 @@ static bool parse_config_int(GKeyFile *config, const char *group,
return true;
}
+static bool parse_config_signed_int(GKeyFile *config, const char *group,
+ const char *key, int8_t *val,
+ size_t min, size_t max)
+{
+ char *str = NULL;
+ char *endptr = NULL;
+ long tmp;
+ bool result = false;
+
+ str = g_key_file_get_string(config, group, key, NULL);
+ if (!str)
+ return false;
+
+ tmp = strtol(str, &endptr, 0);
+ if (!endptr || *endptr != '\0') {
+ warn("%s.%s = %s is not integer", group, key, str);
+ goto cleanup;
+ }
+
+ if (tmp < (long)min) {
+ warn("%s.%s = %ld is out of range (< %zu)", group, key, tmp,
+ min);
+ goto cleanup;
+ }
+
+ if (tmp > (long)max) {
+ warn("%s.%s = %ld is out of range (> %zu)", group, key, tmp,
+ max);
+ goto cleanup;
+ }
+
+ if (val)
+ *val = (int8_t)tmp;
+ result = true;
+
+cleanup:
+ g_free(str);
+ return result;
+}
+
struct config_param {
const char * const val_name;
void * const val;
@@ -1184,6 +1232,82 @@ static void parse_csis(GKeyFile *config)
0, UINT8_MAX);
}
+static bool parse_cs_role(GKeyFile *config, const char *group,
+ const char *key, uint8_t *val)
+{
+ GError *err = NULL;
+ char *str = NULL;
+ int numeric_val;
+
+ /* Try to read as string first */
+ str = g_key_file_get_string(config, group, key, &err);
+ if (err) {
+ if (err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND)
+ DBG("%s", err->message);
+ g_error_free(err);
+ return false;
+ }
+
+ DBG("%s.%s = %s", group, key, str);
+
+ /* Check if it's a string value */
+ if (!strcmp(str, "Initiator") || !strcmp(str, "initiator")) {
+ if (val)
+ *val = 1;
+ g_free(str);
+ return true;
+ } else if (!strcmp(str, "Reflector") || !strcmp(str, "reflector")) {
+ if (val)
+ *val = 2;
+ g_free(str);
+ return true;
+ } else if (!strcmp(str, "Both") || !strcmp(str, "both")) {
+ if (val)
+ *val = 3;
+ g_free(str);
+ return true;
+ }
+
+ /* Try to parse as numeric value */
+ char *endptr = NULL;
+
+ numeric_val = strtol(str, &endptr, 0);
+
+ if (!endptr || *endptr != '\0') {
+ error("%s.%s = %s is not a valid value. "
+ "Expected: 1/Initiator, 2/Reflector, or 3/Both",
+ group, key, str);
+ g_free(str);
+ return false;
+ }
+
+ if (numeric_val < 1 || numeric_val > 3) {
+ warn("%s.%s = %d is out of range. "
+ "Valid values: 1 (Initiator), 2 (Reflector), 3 (Both)",
+ group, key, numeric_val);
+ g_free(str);
+ return false;
+ }
+
+ if (val)
+ *val = numeric_val;
+
+ g_free(str);
+ return true;
+}
+
+static void parse_le_cs_config(GKeyFile *config)
+{
+ parse_cs_role(config, "ChannelSounding", "Role",
+ &btd_opts.defaults.bcs.role);
+ parse_config_u8(config, "ChannelSounding", "CsSyncAntennaSel",
+ &btd_opts.defaults.bcs.cs_sync_ant_sel,
+ 0x01, 0xFF);
+ parse_config_signed_int(config, "ChannelSounding",
+ "MaxTxPower", &btd_opts.defaults.bcs.max_tx_power,
+ INT8_MIN, INT8_MAX);
+}
+
static void parse_avdtp_session_mode(GKeyFile *config)
{
char *str = NULL;
@@ -1262,6 +1386,7 @@ static void parse_config(GKeyFile *config)
parse_csis(config);
parse_avdtp(config);
parse_avrcp(config);
+ parse_le_cs_config(config);
parse_advmon(config);
}
@@ -1313,6 +1438,10 @@ static void init_defaults(void)
btd_opts.advmon.rssi_sampling_period = 0xFF;
btd_opts.csis.encrypt = true;
+
+ btd_opts.defaults.bcs.role = 0x03;
+ btd_opts.defaults.bcs.cs_sync_ant_sel = 0xFF;
+ btd_opts.defaults.bcs.max_tx_power = 0x14;
}
static void log_handler(const gchar *log_domain, GLogLevelFlags log_level,
diff --git a/src/main.conf b/src/main.conf
index d31dd1b8f..fc0138bbf 100644
--- a/src/main.conf
+++ b/src/main.conf
@@ -299,6 +299,30 @@
# Default = auto
# Security = auto
+[ChannelSounding]
+# Current role of the device
+# Possible values:
+# 1 or "Initiator" - CS Initiator role,
+# Generally, CS Initiator acts as Client (Gatt role) and Central (Gap role)
+# 2 or "Reflector" - CS Reflector role,
+# Generally, CS Reflector acts as Server (Gatt role) and Peripheral (Gap role)
+# 3 or "Both" - Both Initiator and Reflector roles
+# Default: 3 (Both)
+#Role = 3
+
+# Antenna Identifier to be used
+# Possible values:
+# 0x01-0x04 (antenna identifier to be used),
+# 0xFE - Antennas to be used in repetetive order,
+# 0xFF - Host doen't have recommendation
+# Default: 0xFF (Host doesn't have recommendation)
+#CsSyncAntennaSel = 0xFF
+
+# Maximum Transmit power
+# Possible values: 0x7F-0x14 (-127dBm to 20dBm)
+# Default: 0x14 (Max Power possible)
+#MaxTxPower = 0x14
+
[CSIS]
# SIRK - Set Identification Resolution Key which is common for all the
# sets. They SIRK key is used to identify its sets. This can be any
--
^ permalink raw reply related
* [PATCH BlueZ v4 1/3] shared: rap: Introduce Channel Sounding HCI raw interface support
From: Naga Bhavani Akella @ 2026-04-13 10:41 UTC (permalink / raw)
To: linux-bluetooth
Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
prathibha.madugonde, Naga Bhavani Akella
In-Reply-To: <20260413104116.1605357-1-naga.akella@oss.qualcomm.com>
Implement stub callbacks for Channel Sounding HCI events and add the
required protocol definitions for CS configuration, procedure control,
and subevent result parsing
Add data structures to support Channel Sounding Processing
Add helper function to get hci conn info list and integrate it with RAP
---
src/shared/hci.c | 67 +++++++++++++-----
src/shared/hci.h | 12 ++++
src/shared/rap.c | 50 +++++++++++++-
src/shared/rap.h | 174 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 285 insertions(+), 18 deletions(-)
diff --git a/src/shared/hci.c b/src/shared/hci.c
index 575254c09..50ba199e3 100644
--- a/src/shared/hci.c
+++ b/src/shared/hci.c
@@ -20,9 +20,11 @@
#include <sys/un.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
+#include "lib/bluetooth/hci.h"
#include "monitor/bt.h"
#include "src/shared/mainloop.h"
#include "src/shared/io.h"
@@ -30,22 +32,6 @@
#include "src/shared/queue.h"
#include "src/shared/hci.h"
-#define BTPROTO_HCI 1
-struct sockaddr_hci {
- sa_family_t hci_family;
- unsigned short hci_dev;
- unsigned short hci_channel;
-};
-#define HCI_CHANNEL_RAW 0
-#define HCI_CHANNEL_USER 1
-
-#define SOL_HCI 0
-#define HCI_FILTER 2
-struct hci_filter {
- uint32_t type_mask;
- uint32_t event_mask[2];
- uint16_t opcode;
-};
struct bt_hci {
int ref_count;
@@ -673,3 +659,52 @@ bool bt_hci_unregister(struct bt_hci *hci, unsigned int id)
return true;
}
+
+bool bt_hci_get_conn_info(struct bt_hci *hci, uint16_t handle,
+ struct bt_hci_conn_info *info)
+{
+ struct hci_conn_list_req *cl;
+ struct hci_conn_info *ci;
+ int fd, i;
+ bool found = false;
+
+ if (!hci || !info)
+ return false;
+
+ fd = io_get_fd(hci->io);
+ if (fd < 0)
+ return false;
+
+ /* Allocate buffer for connection list request */
+ cl = malloc(10 * sizeof(*ci) + sizeof(*cl));
+ if (!cl)
+ return false;
+
+ memset(cl, 0, 10 * sizeof(*ci) + sizeof(*cl));
+ cl->dev_id = 0; /* Will be filled by ioctl */
+ cl->conn_num = 10;
+
+ /* Get connection list via ioctl */
+ if (ioctl(fd, HCIGETCONNLIST, (void *) cl) < 0) {
+ free(cl);
+ return false;
+ }
+
+ /* Search for the connection with matching handle */
+ ci = cl->conn_info;
+ for (i = 0; i < cl->conn_num; i++, ci++) {
+ if (ci->handle == handle) {
+ info->handle = ci->handle;
+ memcpy(info->bdaddr, &ci->bdaddr, 6);
+ info->type = ci->type;
+ info->out = ci->out;
+ info->state = ci->state;
+ info->link_mode = ci->link_mode;
+ found = true;
+ break;
+ }
+ }
+
+ free(cl);
+ return found;
+}
diff --git a/src/shared/hci.h b/src/shared/hci.h
index 76ee72f54..742e24897 100644
--- a/src/shared/hci.h
+++ b/src/shared/hci.h
@@ -13,6 +13,15 @@
typedef void (*bt_hci_destroy_func_t)(void *user_data);
+struct bt_hci_conn_info {
+ uint16_t handle;
+ uint8_t bdaddr[6];
+ uint8_t type;
+ uint8_t out;
+ uint16_t state;
+ uint32_t link_mode;
+};
+
struct bt_hci;
struct bt_hci *bt_hci_new(int fd);
@@ -41,3 +50,6 @@ unsigned int bt_hci_register(struct bt_hci *hci, uint8_t event,
bt_hci_callback_func_t callback,
void *user_data, bt_hci_destroy_func_t destroy);
bool bt_hci_unregister(struct bt_hci *hci, unsigned int id);
+
+bool bt_hci_get_conn_info(struct bt_hci *hci, uint16_t handle,
+ struct bt_hci_conn_info *info);
diff --git a/src/shared/rap.c b/src/shared/rap.c
index 39ef3f278..5745cda08 100644
--- a/src/shared/rap.c
+++ b/src/shared/rap.c
@@ -26,8 +26,8 @@
#include "src/shared/gatt-client.h"
#include "src/shared/rap.h"
-#define DBG(_rap, fmt, arg...) \
- rap_debug(_rap, "%s:%s() " fmt, __FILE__, __func__, ## arg)
+#define DBG(_rap, fmt, ...) \
+ rap_debug(_rap, "%s:%s() " fmt, __FILE__, __func__, ##__VA_ARGS__)
#define RAS_UUID16 0x185B
@@ -504,6 +504,52 @@ bool bt_rap_unregister(unsigned int id)
return true;
}
+void bt_rap_hci_cs_subevent_result_cont_callback(uint16_t length,
+ const void *param,
+ void *user_data)
+{
+ struct bt_rap *rap = user_data;
+
+ DBG(rap, "Received CS subevent CONT: len=%d", length);
+}
+
+void bt_rap_hci_cs_subevent_result_callback(uint16_t length,
+ const void *param,
+ void *user_data)
+{
+ struct bt_rap *rap = user_data;
+
+ DBG(rap, "Received CS subevent: len=%d", length);
+}
+
+void bt_rap_hci_cs_procedure_enable_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data)
+{
+ struct bt_rap *rap = user_data;
+
+ DBG(rap, "Received CS procedure enable complete subevent: len=%d",
+ length);
+}
+
+void bt_rap_hci_cs_sec_enable_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data)
+{
+ struct bt_rap *rap = user_data;
+
+ DBG(rap, "Received CS security enable subevent: len=%d", length);
+}
+
+void bt_rap_hci_cs_config_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data)
+{
+ struct bt_rap *rap = user_data;
+
+ DBG(rap, "Received CS config complete subevent: len=%d", length);
+}
+
struct bt_rap *bt_rap_new(struct gatt_db *ldb, struct gatt_db *rdb)
{
struct bt_rap *rap;
diff --git a/src/shared/rap.h b/src/shared/rap.h
index a1d1ff2ae..21de72af3 100644
--- a/src/shared/rap.h
+++ b/src/shared/rap.h
@@ -9,9 +9,154 @@
#include <inttypes.h>
#include "src/shared/io.h"
+#include "lib/bluetooth/mgmt.h"
+#include "src/shared/hci.h"
struct bt_rap;
+/* Channel Sounding Events */
+struct bt_rap_hci_cs_options {
+ uint8_t role;
+ uint8_t cs_sync_ant_sel;
+ int8_t max_tx_power;
+ int rtt_type;
+};
+
+#define CS_MODE_ZERO 0x00
+#define CS_MODE_ONE 0x01
+#define CS_MODE_TWO 0x02
+#define CS_MODE_THREE 0x03
+
+#define CS_REFLECTOR 0x01
+#define CS_INITIATOR 0x00
+
+#define CS_MAX_ANT_PATHS 0x05
+#define CS_MAX_STEPS 0xA0
+#define CS_MAX_STEP_DATA_LEN 0xFF
+
+struct rap_ev_cs_config_cmplt {
+ uint8_t status;
+ uint16_t conn_hdl;
+ uint8_t config_id;
+ uint8_t action;
+ uint8_t main_mode_type;
+ uint8_t sub_mode_type;
+ uint8_t min_main_mode_steps;
+ uint8_t max_main_mode_steps;
+ uint8_t main_mode_rep;
+ uint8_t mode_0_steps;
+ uint8_t role;
+ uint8_t rtt_type;
+ uint8_t cs_sync_phy;
+ uint8_t channel_map[10];
+ uint8_t channel_map_rep;
+ uint8_t channel_sel_type;
+ uint8_t ch3c_shape;
+ uint8_t ch3c_jump;
+ uint8_t reserved;
+ uint8_t t_ip1_time;
+ uint8_t t_ip2_time;
+ uint8_t t_fcs_time;
+ uint8_t t_pm_time;
+} __packed;
+
+struct rap_ev_cs_sec_enable_cmplt {
+ uint8_t status;
+ uint16_t conn_hdl;
+} __packed;
+
+struct rap_ev_cs_proc_enable_cmplt {
+ uint8_t status;
+ uint16_t conn_hdl;
+ uint8_t config_id;
+ uint8_t state;
+ uint8_t tone_ant_config_sel;
+ int8_t sel_tx_pwr;
+ uint8_t sub_evt_len[3];
+ uint8_t sub_evts_per_evt;
+ uint16_t sub_evt_intrvl;
+ uint16_t evt_intrvl;
+ uint16_t proc_intrvl;
+ uint16_t proc_counter;
+ uint16_t max_proc_len;
+} __packed;
+
+#define CS_MAX_STEPS 0xA0
+
+struct pct_iq_sample {
+ int16_t i_sample;
+ int16_t q_sample;
+} __packed;
+
+struct cs_mode_zero_data {
+ uint8_t packet_quality;
+ uint8_t packet_rssi_dbm;
+ uint8_t packet_ant;
+ uint32_t init_measured_freq_offset;
+} __packed;
+
+struct cs_mode_one_data {
+ uint8_t packet_quality;
+ uint8_t packet_rssi_dbm;
+ uint8_t packet_ant;
+ uint8_t packet_nadm;
+ int16_t toa_tod_init;
+ int16_t tod_toa_refl;
+ struct pct_iq_sample packet_pct1;
+ struct pct_iq_sample packet_pct2;
+} __packed;
+
+struct cs_mode_two_data {
+ uint8_t ant_perm_index;
+ struct pct_iq_sample tone_pct[4];
+ uint8_t tone_quality_indicator[4];
+} __packed;
+
+struct cs_mode_three_data {
+ struct cs_mode_one_data mode_one_data;
+ struct cs_mode_two_data mode_two_data;
+} __packed;
+
+union cs_mode_data {
+ struct cs_mode_zero_data mode_zero_data;
+ struct cs_mode_one_data mode_one_data;
+ struct cs_mode_two_data mode_two_data;
+ struct cs_mode_three_data mode_three_data;
+};
+
+struct cs_step_data {
+ uint8_t step_mode;
+ uint8_t step_chnl;
+ uint8_t step_data_length;
+ union cs_mode_data step_mode_data;
+} __packed;
+
+struct rap_ev_cs_subevent_result {
+ uint16_t conn_hdl;
+ uint8_t config_id;
+ uint16_t start_acl_conn_evt_counter;
+ uint16_t proc_counter;
+ uint16_t freq_comp;
+ uint8_t ref_pwr_lvl;
+ uint8_t proc_done_status;
+ uint8_t subevt_done_status;
+ uint8_t abort_reason;
+ uint8_t num_ant_paths;
+ uint8_t num_steps_reported;
+ struct cs_step_data step_data[];
+} __packed;
+
+struct rap_ev_cs_subevent_result_cont {
+ uint16_t conn_hdl;
+ uint8_t config_id;
+ uint8_t proc_done_status;
+ uint8_t subevt_done_status;
+ uint8_t abort_reason;
+ uint8_t num_ant_paths;
+ uint8_t num_steps_reported;
+ struct cs_step_data step_data[];
+} __packed;
+
typedef void (*bt_rap_debug_func_t)(const char *str, void *user_data);
typedef void (*bt_rap_ready_func_t)(struct bt_rap *rap, void *user_data);
typedef void (*bt_rap_destroy_func_t)(void *user_data);
@@ -43,3 +188,32 @@ bool bt_rap_ready_unregister(struct bt_rap *rap, unsigned int id);
bool bt_rap_unregister(unsigned int id);
struct bt_rap *bt_rap_new(struct gatt_db *ldb, struct gatt_db *rdb);
+
+/* HCI Raw Channel Approach */
+void bt_rap_hci_cs_config_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data);
+void bt_rap_hci_cs_sec_enable_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data);
+void bt_rap_hci_cs_procedure_enable_complete_callback(uint16_t length,
+ const void *param,
+ void *user_data);
+void bt_rap_hci_cs_subevent_result_callback(uint16_t length,
+ const void *param,
+ void *user_data);
+void bt_rap_hci_cs_subevent_result_cont_callback(uint16_t length,
+ const void *param,
+ void *user_data);
+
+void bt_rap_hci_set_le_bcs_options(uint8_t role, uint8_t cs_sync_ant_sel,
+ int8_t max_tx_power);
+
+bool bt_rap_attach_hci(struct bt_rap *rap, struct bt_hci *hci);
+void bt_rap_detach_hci(struct bt_rap *rap);
+void bt_rap_hci_sm_cleanup(void);
+
+/* Connection handle mapping functions */
+bool bt_rap_set_conn_handle(struct bt_rap *rap, uint16_t handle,
+ const uint8_t *bdaddr, uint8_t bdaddr_type);
+void bt_rap_clear_conn_handle(struct bt_rap *rap, uint16_t handle);
--
^ permalink raw reply related
* [PATCH BlueZ v4 0/3] Bluetooth: Add initial Channel Sounding
From: Naga Bhavani Akella @ 2026-04-13 10:41 UTC (permalink / raw)
To: linux-bluetooth
Cc: luiz.dentz, quic_mohamull, quic_hbandi, quic_anubhavg,
prathibha.madugonde, Naga Bhavani Akella
This patch series introduces initial support for Bluetooth Channel Sounding
(CS) using the raw HCI interface.
This series lays the groundwork for CS support by adding commonly
required protocol definitions, configuration parsing, and event handling
for the reflector role.
The changes include:
1) Introduction of raw HCI support structures and callbacks for Channel
Sounding procedures and events. This provides the foundational data
definitions and HCI subevent handling needed by higher-level profiles.
2) Addition of Channel Sounding configuration parsing from the BlueZ
configuration file.This patch also updates the systemd
service capability bounding set to include CAP_NET_RAW, which is
required for bluetoothd to receive and process LE Channel Sounding
events when running under a constrained systemd environment.
3) Implementation of HCI LE Channel Sounding event handling in the Ranging
profile for the reflector role. This includes opening a raw HCI channel,
parsing relevant CS LE events, routing them to the RAP profile
Patch overview:
1/3 shared: rap: introduce Channel Sounding HCI raw interface support
2/3 bluetooth: add Channel Sounding config parsing support
3/3 profiles: ranging: add HCI LE Channel Sounding event handling (reflector)
Naga Bhavani Akella (3):
shared: rap: Introduce Channel Sounding HCI raw interface support
bluetooth: Add Channel Sounding config parsing support
profiles: ranging: Add HCI LE Event Handling in Reflector role
Makefile.plugins | 3 +-
profiles/ranging/rap.c | 83 ++-
profiles/ranging/rap_hci.c | 1288 ++++++++++++++++++++++++++++++++++++
src/bluetooth.service.in | 2 +-
src/btd.h | 7 +
src/main.c | 129 ++++
src/main.conf | 24 +
src/shared/hci.c | 67 +-
src/shared/hci.h | 12 +
src/shared/rap.c | 50 +-
src/shared/rap.h | 174 +++++
11 files changed, 1813 insertions(+), 26 deletions(-)
create mode 100644 profiles/ranging/rap_hci.c
--
^ permalink raw reply
* RE: Bluetooth: l2cap: Fix MPS check in l2cap_ecred_reconf_req
From: bluez.test.bot @ 2026-04-13 9:41 UTC (permalink / raw)
To: linux-bluetooth, phx0fer
In-Reply-To: <20260413085600.75248-1-phx0fer@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 6870 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=1080587
---Test result---
Test Summary:
CheckPatch PENDING 0.35 seconds
GitLint PENDING 0.30 seconds
SubjectPrefix PASS 0.12 seconds
BuildKernel PASS 26.08 seconds
CheckAllWarning PASS 29.06 seconds
CheckSparse PASS 28.35 seconds
BuildKernel32 PASS 26.03 seconds
TestRunnerSetup PASS 564.70 seconds
TestRunner_l2cap-tester PASS 28.13 seconds
TestRunner_iso-tester PASS 39.45 seconds
TestRunner_bnep-tester PASS 6.31 seconds
TestRunner_mgmt-tester FAIL 114.54 seconds
TestRunner_rfcomm-tester PASS 9.38 seconds
TestRunner_sco-tester FAIL 14.43 seconds
TestRunner_ioctl-tester PASS 10.18 seconds
TestRunner_mesh-tester FAIL 12.55 seconds
TestRunner_smp-tester PASS 8.56 seconds
TestRunner_userchan-tester PASS 6.84 seconds
TestRunner_6lowpan-tester FAIL 8.75 seconds
IncrementalBuild PENDING 0.26 seconds
Details
##############################
Test: CheckPatch - PENDING
Desc: Run checkpatch.pl script
Output:
##############################
Test: GitLint - PENDING
Desc: Run gitlint
Output:
##############################
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.104 seconds
##############################
Test: TestRunner_sco-tester - FAIL
Desc: Run sco-tester with test-runner
Output:
WARNING: possible circular locking dependency detected
7.0.0-rc2-g8a170d9e02f8 #1 Not tainted
------------------------------------------------------
kworker/u5:2/117 is trying to acquire lock:
ffff888001946240 (sk_lock-AF_BLUETOOTH-BTPROTO_SCO){+.+.}-{0:0}, at: sco_connect_cfm+0x358/0x8d0
but task is already holding lock:
ffff8880023c6220 (&conn->lock){+.+.}-{3:3}, at: sco_connect_cfm+0x22d/0x8d0
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #1 (&conn->lock){+.+.}-{3:3}:
lock_acquire+0xf7/0x2c0
_raw_spin_lock+0x2a/0x40
sco_sock_connect+0x4d7/0x1280
__sys_connect+0x1a3/0x260
__x64_sys_connect+0x6e/0xb0
do_syscall_64+0xa0/0x570
entry_SYSCALL_64_after_hwframe+0x74/0x7c
-> #0 (sk_lock-AF_BLUETOOTH-BTPROTO_SCO){+.+.}-{0:0}:
check_prev_add+0xe9/0xc70
__lock_acquire+0x1457/0x1df0
lock_acquire+0xf7/0x2c0
lock_sock_nested+0x36/0xd0
sco_connect_cfm+0x358/0x8d0
hci_sync_conn_complete_evt+0x3d3/0x8e0
hci_event_packet+0x74f/0xb10
hci_rx_work+0x398/0xd00
process_scheduled_works+0xb16/0x1ac0
worker_thread+0x4ff/0xba0
kthread+0x368/0x490
ret_from_fork+0x498/0x7e0
ret_from_fork_asm+0x19/0x30
other info that might help us debug this:
...
BUG: sleeping function called from invalid context at net/core/sock.c:3782
in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 117, name: kworker/u5:2
preempt_count: 1, expected: 0
RCU nest depth: 0, expected: 0
INFO: lockdep is turned off.
CPU: 0 UID: 0 PID: 117 Comm: kworker/u5:2 Not tainted 7.0.0-rc2-g8a170d9e02f8 #1 PREEMPT(lazy)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-1ubuntu1.1 04/01/2014
Workqueue: hci0 hci_rx_work
Call Trace:
<TASK>
dump_stack_lvl+0x49/0x60
__might_resched+0x2ea/0x500
lock_sock_nested+0x47/0xd0
? sco_connect_cfm+0x358/0x8d0
sco_connect_cfm+0x358/0x8d0
? hci_debugfs_create_conn+0x190/0x210
? __pfx_sco_connect_cfm+0x10/0x10
hci_sync_conn_complete_evt+0x3d3/0x8e0
hci_event_packet+0x74f/0xb10
? __pfx_hci_sync_conn_complete_evt+0x10/0x10
? __pfx_hci_event_packet+0x10/0x10
? mark_held_locks+0x49/0x80
? lockdep_hardirqs_on_prepare+0xd4/0x180
? _raw_spin_unlock_irqrestore+0x2c/0x50
hci_rx_work+0x398/0xd00
process_scheduled_works+0xb16/0x1ac0
? __pfx_process_scheduled_works+0x10/0x10
? lock_acquire+0xf7/0x2c0
? lock_is_held_type+0x9b/0x110
? __pfx_hci_rx_work+0x10/0x10
worker_thread+0x4ff/0xba0
? _raw_spin_unlock_irqrestore+0x2c/0x50
? __pfx_worker_thread+0x10/0x10
kthread+0x368/0x490
? _raw_spin_unlock_irq+0x23/0x40
? __pfx_kthread+0x10/0x10
ret_from_fork+0x498/0x7e0
? __pfx_ret_from_fork+0x10/0x10
? __switch_to+0x9e4/0xe50
? __switch_to_asm+0x32/0x60
...
Total: 30, Passed: 30 (100.0%), Failed: 0, Not Run: 0
##############################
Test: TestRunner_mesh-tester - FAIL
Desc: Run mesh-tester with test-runner
Output:
Total: 10, Passed: 8 (80.0%), Failed: 2, Not Run: 0
Failed Test Cases
Mesh - Send cancel - 1 Timed out 2.733 seconds
Mesh - Send cancel - 2 Timed out 1.993 seconds
##############################
Test: TestRunner_6lowpan-tester - FAIL
Desc: Run 6lowpan-tester with test-runner
Output:
WARNING: possible circular locking dependency detected
7.0.0-rc2-g8a170d9e02f8 #1 Not tainted
------------------------------------------------------
kworker/0:1/11 is trying to acquire lock:
ffff888002777140 ((wq_completion)hci0#2){+.+.}-{0:0}, at: touch_wq_lockdep_map+0x75/0x180
but task is already holding lock:
ffffffffb964d720 (rtnl_mutex){+.+.}-{4:4}, at: lowpan_unregister_netdev+0xd/0x30
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #4 (rtnl_mutex){+.+.}-{4:4}:
lock_acquire+0xf7/0x2c0
__mutex_lock+0x16b/0x1fc0
lowpan_register_netdev+0x11/0x30
chan_ready_cb+0x836/0xd00
l2cap_recv_frame+0x6465/0x8910
l2cap_recv_acldata+0x790/0xdf0
hci_rx_work+0x500/0xd00
process_scheduled_works+0xb16/0x1ac0
worker_thread+0x4ff/0xba0
kthread+0x368/0x490
ret_from_fork+0x498/0x7e0
ret_from_fork_asm+0x19/0x30
-> #3 (&chan->lock#3/1){+.+.}-{4:4}:
lock_acquire+0xf7/0x2c0
__mutex_lock+0x16b/0x1fc0
l2cap_chan_connect+0x74e/0x1980
lowpan_control_write+0x523/0x660
full_proxy_write+0x10b/0x190
vfs_write+0x1c0/0xf60
ksys_write+0xf1/0x1d0
do_syscall_64+0xa0/0x570
entry_SYSCALL_64_after_hwframe+0x74/0x7c
-> #2 (&conn->lock){+.+.}-{4:4}:
...
Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0
##############################
Test: IncrementalBuild - PENDING
Desc: Incremental build with the patches in the series
Output:
https://github.com/bluez/bluetooth-next/pull/78
---
Regards,
Linux Bluetooth
^ permalink raw reply
* RE: Bluetooth: bnep: Fix endianness in bnep_rx_frame() extension parsing
From: bluez.test.bot @ 2026-04-13 9:41 UTC (permalink / raw)
To: linux-bluetooth, phx0fer
In-Reply-To: <20260413084442.68604-1-phx0fer@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 6871 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=1080572
---Test result---
Test Summary:
CheckPatch PENDING 0.46 seconds
GitLint PENDING 0.41 seconds
SubjectPrefix PASS 0.12 seconds
BuildKernel PASS 26.05 seconds
CheckAllWarning PASS 28.97 seconds
CheckSparse PASS 28.08 seconds
BuildKernel32 PASS 25.95 seconds
TestRunnerSetup PASS 539.48 seconds
TestRunner_l2cap-tester PASS 28.18 seconds
TestRunner_iso-tester PASS 39.47 seconds
TestRunner_bnep-tester PASS 6.45 seconds
TestRunner_mgmt-tester FAIL 116.46 seconds
TestRunner_rfcomm-tester PASS 9.55 seconds
TestRunner_sco-tester FAIL 14.30 seconds
TestRunner_ioctl-tester PASS 10.15 seconds
TestRunner_mesh-tester FAIL 11.60 seconds
TestRunner_smp-tester PASS 10.58 seconds
TestRunner_userchan-tester PASS 6.79 seconds
TestRunner_6lowpan-tester FAIL 8.84 seconds
IncrementalBuild PENDING 0.27 seconds
Details
##############################
Test: CheckPatch - PENDING
Desc: Run checkpatch.pl script
Output:
##############################
Test: GitLint - PENDING
Desc: Run gitlint
Output:
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
Total: 494, Passed: 489 (99.0%), Failed: 1, Not Run: 4
Failed Test Cases
Read Exp Feature - Success Failed 0.111 seconds
##############################
Test: TestRunner_sco-tester - FAIL
Desc: Run sco-tester with test-runner
Output:
WARNING: possible circular locking dependency detected
7.0.0-rc2-gc26941412ef4 #1 Not tainted
------------------------------------------------------
kworker/u5:2/117 is trying to acquire lock:
ffff888001abe240 (sk_lock-AF_BLUETOOTH-BTPROTO_SCO){+.+.}-{0:0}, at: sco_connect_cfm+0x358/0x8d0
but task is already holding lock:
ffff888002090c20 (&conn->lock){+.+.}-{3:3}, at: sco_connect_cfm+0x22d/0x8d0
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #1 (&conn->lock){+.+.}-{3:3}:
lock_acquire+0xf7/0x2c0
_raw_spin_lock+0x2a/0x40
sco_sock_connect+0x4d7/0x1280
__sys_connect+0x1a3/0x260
__x64_sys_connect+0x6e/0xb0
do_syscall_64+0xa0/0x570
entry_SYSCALL_64_after_hwframe+0x74/0x7c
-> #0 (sk_lock-AF_BLUETOOTH-BTPROTO_SCO){+.+.}-{0:0}:
check_prev_add+0xe9/0xc70
__lock_acquire+0x1457/0x1df0
lock_acquire+0xf7/0x2c0
lock_sock_nested+0x36/0xd0
sco_connect_cfm+0x358/0x8d0
hci_sync_conn_complete_evt+0x3d3/0x8e0
hci_event_packet+0x74f/0xb10
hci_rx_work+0x398/0xd00
process_scheduled_works+0xb16/0x1ac0
worker_thread+0x4ff/0xba0
kthread+0x368/0x490
ret_from_fork+0x498/0x7e0
ret_from_fork_asm+0x19/0x30
other info that might help us debug this:
...
BUG: sleeping function called from invalid context at net/core/sock.c:3782
in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 117, name: kworker/u5:2
preempt_count: 1, expected: 0
RCU nest depth: 0, expected: 0
INFO: lockdep is turned off.
CPU: 0 UID: 0 PID: 117 Comm: kworker/u5:2 Not tainted 7.0.0-rc2-gc26941412ef4 #1 PREEMPT(lazy)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-1ubuntu1.1 04/01/2014
Workqueue: hci0 hci_rx_work
Call Trace:
<TASK>
dump_stack_lvl+0x49/0x60
__might_resched+0x2ea/0x500
lock_sock_nested+0x47/0xd0
? sco_connect_cfm+0x358/0x8d0
sco_connect_cfm+0x358/0x8d0
? hci_debugfs_create_conn+0x190/0x210
? __pfx_sco_connect_cfm+0x10/0x10
hci_sync_conn_complete_evt+0x3d3/0x8e0
hci_event_packet+0x74f/0xb10
? __pfx_hci_sync_conn_complete_evt+0x10/0x10
? __pfx_hci_event_packet+0x10/0x10
? mark_held_locks+0x49/0x80
? lockdep_hardirqs_on_prepare+0xd4/0x180
? _raw_spin_unlock_irqrestore+0x2c/0x50
hci_rx_work+0x398/0xd00
process_scheduled_works+0xb16/0x1ac0
? __pfx_process_scheduled_works+0x10/0x10
? lock_acquire+0xf7/0x2c0
? lock_is_held_type+0x9b/0x110
? __pfx_hci_rx_work+0x10/0x10
worker_thread+0x4ff/0xba0
? _raw_spin_unlock_irqrestore+0x2c/0x50
? __pfx_worker_thread+0x10/0x10
kthread+0x368/0x490
? _raw_spin_unlock_irq+0x23/0x40
? __pfx_kthread+0x10/0x10
ret_from_fork+0x498/0x7e0
? __pfx_ret_from_fork+0x10/0x10
? __switch_to+0x9e4/0xe50
? __switch_to_asm+0x32/0x60
...
Total: 30, Passed: 30 (100.0%), Failed: 0, Not Run: 0
##############################
Test: TestRunner_mesh-tester - FAIL
Desc: Run mesh-tester with test-runner
Output:
Total: 10, Passed: 8 (80.0%), Failed: 2, Not Run: 0
Failed Test Cases
Mesh - Send cancel - 1 Timed out 1.788 seconds
Mesh - Send cancel - 2 Timed out 1.993 seconds
##############################
Test: TestRunner_6lowpan-tester - FAIL
Desc: Run 6lowpan-tester with test-runner
Output:
WARNING: possible circular locking dependency detected
7.0.0-rc2-gc26941412ef4 #1 Not tainted
------------------------------------------------------
kworker/0:1/11 is trying to acquire lock:
ffff8880026e8940 ((wq_completion)hci0#2){+.+.}-{0:0}, at: touch_wq_lockdep_map+0x75/0x180
but task is already holding lock:
ffffffff98c4d720 (rtnl_mutex){+.+.}-{4:4}, at: lowpan_unregister_netdev+0xd/0x30
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #4 (rtnl_mutex){+.+.}-{4:4}:
lock_acquire+0xf7/0x2c0
__mutex_lock+0x16b/0x1fc0
lowpan_register_netdev+0x11/0x30
chan_ready_cb+0x836/0xd00
l2cap_recv_frame+0x6a06/0x8920
l2cap_recv_acldata+0x790/0xdf0
hci_rx_work+0x500/0xd00
process_scheduled_works+0xb16/0x1ac0
worker_thread+0x4ff/0xba0
kthread+0x368/0x490
ret_from_fork+0x498/0x7e0
ret_from_fork_asm+0x19/0x30
-> #3 (&chan->lock#3/1){+.+.}-{4:4}:
lock_acquire+0xf7/0x2c0
__mutex_lock+0x16b/0x1fc0
l2cap_chan_connect+0x74e/0x1980
lowpan_control_write+0x523/0x660
full_proxy_write+0x10b/0x190
vfs_write+0x1c0/0xf60
ksys_write+0xf1/0x1d0
do_syscall_64+0xa0/0x570
entry_SYSCALL_64_after_hwframe+0x74/0x7c
-> #2 (&conn->lock){+.+.}-{4:4}:
...
Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0
##############################
Test: IncrementalBuild - PENDING
Desc: Incremental build with the patches in the series
Output:
https://github.com/bluez/bluetooth-next/pull/76
---
Regards,
Linux Bluetooth
^ permalink raw reply
* RE: Bluetooth: hci_conn: Use disable_delayed_work_sync for le_conn_timeout
From: bluez.test.bot @ 2026-04-13 9:40 UTC (permalink / raw)
To: linux-bluetooth, phx0fer
In-Reply-To: <20260413085455.74585-1-phx0fer@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 7138 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=1080586
---Test result---
Test Summary:
CheckPatch PENDING 0.35 seconds
GitLint PENDING 0.28 seconds
SubjectPrefix PASS 0.11 seconds
BuildKernel PASS 27.69 seconds
CheckAllWarning PASS 30.82 seconds
CheckSparse PASS 26.17 seconds
BuildKernel32 PASS 23.95 seconds
TestRunnerSetup PASS 530.21 seconds
TestRunner_l2cap-tester FAIL 28.10 seconds
TestRunner_iso-tester PASS 35.75 seconds
TestRunner_bnep-tester PASS 6.44 seconds
TestRunner_mgmt-tester FAIL 114.59 seconds
TestRunner_rfcomm-tester PASS 9.45 seconds
TestRunner_sco-tester FAIL 14.38 seconds
TestRunner_ioctl-tester PASS 10.23 seconds
TestRunner_mesh-tester FAIL 12.53 seconds
TestRunner_smp-tester PASS 8.65 seconds
TestRunner_userchan-tester PASS 6.68 seconds
TestRunner_6lowpan-tester FAIL 9.17 seconds
IncrementalBuild PENDING 0.34 seconds
Details
##############################
Test: CheckPatch - PENDING
Desc: Run checkpatch.pl script
Output:
##############################
Test: GitLint - PENDING
Desc: Run gitlint
Output:
##############################
Test: TestRunner_l2cap-tester - FAIL
Desc: Run l2cap-tester with test-runner
Output:
Total: 96, Passed: 95 (99.0%), Failed: 1, Not Run: 0
Failed Test Cases
L2CAP LE Server - Set PHY Coded Failed 0.141 seconds
##############################
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.105 seconds
##############################
Test: TestRunner_sco-tester - FAIL
Desc: Run sco-tester with test-runner
Output:
WARNING: possible circular locking dependency detected
7.0.0-rc2-g666e7bacebcb #1 Not tainted
------------------------------------------------------
kworker/u5:2/117 is trying to acquire lock:
ffff888001e19240 (sk_lock-AF_BLUETOOTH-BTPROTO_SCO){+.+.}-{0:0}, at: sco_connect_cfm+0x358/0x8d0
but task is already holding lock:
ffff888002141c20 (&conn->lock){+.+.}-{3:3}, at: sco_connect_cfm+0x22d/0x8d0
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #1 (&conn->lock){+.+.}-{3:3}:
lock_acquire+0xf7/0x2c0
_raw_spin_lock+0x2a/0x40
sco_sock_connect+0x4d7/0x1280
__sys_connect+0x1a3/0x260
__x64_sys_connect+0x6e/0xb0
do_syscall_64+0xa0/0x570
entry_SYSCALL_64_after_hwframe+0x74/0x7c
-> #0 (sk_lock-AF_BLUETOOTH-BTPROTO_SCO){+.+.}-{0:0}:
check_prev_add+0xe9/0xc70
__lock_acquire+0x1457/0x1df0
lock_acquire+0xf7/0x2c0
lock_sock_nested+0x36/0xd0
sco_connect_cfm+0x358/0x8d0
hci_sync_conn_complete_evt+0x3d3/0x8e0
hci_event_packet+0x74f/0xb10
hci_rx_work+0x398/0xd00
process_scheduled_works+0xb16/0x1ac0
worker_thread+0x4ff/0xba0
kthread+0x368/0x490
ret_from_fork+0x498/0x7e0
ret_from_fork_asm+0x19/0x30
other info that might help us debug this:
...
BUG: sleeping function called from invalid context at net/core/sock.c:3782
in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 117, name: kworker/u5:2
preempt_count: 1, expected: 0
RCU nest depth: 0, expected: 0
INFO: lockdep is turned off.
CPU: 0 UID: 0 PID: 117 Comm: kworker/u5:2 Not tainted 7.0.0-rc2-g666e7bacebcb #1 PREEMPT(lazy)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-1ubuntu1.1 04/01/2014
Workqueue: hci0 hci_rx_work
Call Trace:
<TASK>
dump_stack_lvl+0x49/0x60
__might_resched+0x2ea/0x500
lock_sock_nested+0x47/0xd0
? sco_connect_cfm+0x358/0x8d0
sco_connect_cfm+0x358/0x8d0
? hci_debugfs_create_conn+0x190/0x210
? __pfx_sco_connect_cfm+0x10/0x10
hci_sync_conn_complete_evt+0x3d3/0x8e0
hci_event_packet+0x74f/0xb10
? __pfx_hci_sync_conn_complete_evt+0x10/0x10
? __pfx_hci_event_packet+0x10/0x10
? mark_held_locks+0x49/0x80
? lockdep_hardirqs_on_prepare+0xd4/0x180
? _raw_spin_unlock_irqrestore+0x2c/0x50
hci_rx_work+0x398/0xd00
process_scheduled_works+0xb16/0x1ac0
? __pfx_process_scheduled_works+0x10/0x10
? lock_acquire+0xf7/0x2c0
? lock_is_held_type+0x9b/0x110
? __pfx_hci_rx_work+0x10/0x10
worker_thread+0x4ff/0xba0
? _raw_spin_unlock_irqrestore+0x2c/0x50
? __pfx_worker_thread+0x10/0x10
kthread+0x368/0x490
? _raw_spin_unlock_irq+0x23/0x40
? __pfx_kthread+0x10/0x10
ret_from_fork+0x498/0x7e0
? __pfx_ret_from_fork+0x10/0x10
? __switch_to+0x9e4/0xe50
? __switch_to_asm+0x32/0x60
...
Total: 30, Passed: 30 (100.0%), Failed: 0, Not Run: 0
##############################
Test: TestRunner_mesh-tester - FAIL
Desc: Run mesh-tester with test-runner
Output:
Total: 10, Passed: 8 (80.0%), Failed: 2, Not Run: 0
Failed Test Cases
Mesh - Send cancel - 1 Timed out 2.729 seconds
Mesh - Send cancel - 2 Timed out 1.996 seconds
##############################
Test: TestRunner_6lowpan-tester - FAIL
Desc: Run 6lowpan-tester with test-runner
Output:
WARNING: possible circular locking dependency detected
7.0.0-rc2-g666e7bacebcb #1 Not tainted
------------------------------------------------------
kworker/0:1/11 is trying to acquire lock:
ffff888002454140 ((wq_completion)hci0#2){+.+.}-{0:0}, at: touch_wq_lockdep_map+0x75/0x180
but task is already holding lock:
ffffffff9f64d720 (rtnl_mutex){+.+.}-{4:4}, at: lowpan_unregister_netdev+0xd/0x30
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #4 (rtnl_mutex){+.+.}-{4:4}:
lock_acquire+0xf7/0x2c0
__mutex_lock+0x16b/0x1fc0
lowpan_register_netdev+0x11/0x30
chan_ready_cb+0x836/0xd00
l2cap_recv_frame+0x6a06/0x8920
l2cap_recv_acldata+0x790/0xdf0
hci_rx_work+0x500/0xd00
process_scheduled_works+0xb16/0x1ac0
worker_thread+0x4ff/0xba0
kthread+0x368/0x490
ret_from_fork+0x498/0x7e0
ret_from_fork_asm+0x19/0x30
-> #3 (&chan->lock#3/1){+.+.}-{4:4}:
lock_acquire+0xf7/0x2c0
__mutex_lock+0x16b/0x1fc0
l2cap_chan_connect+0x74e/0x1980
lowpan_control_write+0x523/0x660
full_proxy_write+0x10b/0x190
vfs_write+0x1c0/0xf60
ksys_write+0xf1/0x1d0
do_syscall_64+0xa0/0x570
entry_SYSCALL_64_after_hwframe+0x74/0x7c
-> #2 (&conn->lock){+.+.}-{4:4}:
...
Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0
##############################
Test: IncrementalBuild - PENDING
Desc: Incremental build with the patches in the series
Output:
https://github.com/bluez/bluetooth-next/pull/77
---
Regards,
Linux Bluetooth
^ permalink raw reply
* RE: Bluetooth: Add initial Channel Sounding
From: bluez.test.bot @ 2026-04-13 9:22 UTC (permalink / raw)
To: linux-bluetooth, naga.akella
In-Reply-To: <20260413080023.1455582-2-naga.akella@oss.qualcomm.com>
[-- Attachment #1: Type: text/plain, Size: 642 bytes --]
This is an automated email and please do not reply to this email.
Dear Submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
While preparing the CI tests, the patches you submitted couldn't be applied to the current HEAD of the repository.
----- Output -----
error: src/shared/hci.c: does not exist in index
error: src/shared/hci.h: does not exist in index
error: src/shared/rap.c: does not exist in index
error: src/shared/rap.h: does not exist in index
hint: Use 'git am --show-current-patch' to see the failed patch
Please resolve the issue and submit the patches again.
---
Regards,
Linux Bluetooth
^ permalink raw reply
* RE: [BlueZ] audio/player: Ensure metadata string is valid UTF-8
From: bluez.test.bot @ 2026-04-13 9:15 UTC (permalink / raw)
To: linux-bluetooth, frederic.danis
In-Reply-To: <20260413071246.19221-1-frederic.danis@collabora.com>
[-- Attachment #1: Type: text/plain, Size: 1304 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=1080516
---Test result---
Test Summary:
CheckPatch PENDING 0.36 seconds
GitLint PENDING 0.37 seconds
BuildEll PASS 20.64 seconds
BluezMake PASS 637.53 seconds
MakeCheck PASS 18.61 seconds
MakeDistcheck PASS 244.94 seconds
CheckValgrind PASS 292.36 seconds
CheckSmatch PASS 347.80 seconds
bluezmakeextell PASS 182.56 seconds
IncrementalBuild PENDING 0.40 seconds
ScanBuild PASS 1029.92 seconds
Details
##############################
Test: CheckPatch - PENDING
Desc: Run checkpatch.pl script
Output:
##############################
Test: GitLint - PENDING
Desc: Run gitlint
Output:
##############################
Test: IncrementalBuild - PENDING
Desc: Incremental build with the patches in the series
Output:
https://github.com/bluez/bluez/pull/2030
---
Regards,
Linux Bluetooth
^ 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