Re: [PATCH RFC v2 3/3] Bluetooth: Add hdev->recv_bt_vendor() to handle BT vendor frames

Luiz Augusto von Dentz <[email protected]>
Newsgroups org.kernel.vger.linux-bluetooth,org.kernel.vger.linux-kernel
Message-ID <CABBYNZL7ApV6wzTOLGu4gRxBU_89x+D-JNd27tg0X-sOmXqEog@mail.gmail.com>
Hi Zijun,

On Wed, Jul 22, 2026 at 12:24 PM Zijun Hu <[email protected]> wrote:
>
> For unsolicited VSE and ACL frames with vendor reserved handles:
> Many transport drivers pre-process them in the RX-path because the BT core
> cannot recognize them, and cause:
>
> - Impact performance since skb_clone() in IRQ-disabled context
> - Difficult to debug as frames consumed without btmon logging
>
> Fix by adding the hook to process them within stack's process
> context, when they have been logged by btmon.
>
> Signed-off-by: Zijun Hu <[email protected]>
> ---
>  include/net/bluetooth/hci_core.h |  3 +++
>  net/bluetooth/hci_core.c         | 33 +++++++++++++++++++++++++++++++++
>  net/bluetooth/hci_event.c        |  5 +++++
>  3 files changed, 41 insertions(+)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 428261591288..12f3720f6cc8 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -646,6 +646,8 @@ struct hci_dev {
>         int (*setup)(struct hci_dev *hdev);
>         int (*shutdown)(struct hci_dev *hdev);
>         int (*send)(struct hci_dev *hdev, struct sk_buff *skb);
> +       /* Return true if @skb was consumed, false otherwise */
> +       bool (*recv_bt_vendor)(struct hci_dev *hdev, struct sk_buff *skb);

This should be probably called recv_vendor_ev or something like that.

>         void (*recv_vendor_pkt)(struct hci_dev *hdev, struct sk_buff *skb);
>         void (*notify)(struct hci_dev *hdev, unsigned int evt);
>         void (*hw_error)(struct hci_dev *hdev, u8 code);
> @@ -2329,6 +2331,7 @@ static inline int hci_check_conn_params(u16 min, u16 max, u16 latency,
>  int hci_register_cb(struct hci_cb *hcb);
>  int hci_unregister_cb(struct hci_cb *hcb);
>
> +bool hci_recv_bt_vendor(struct hci_dev *hdev, struct sk_buff *skb);
>  int hci_send_vendor_frame(struct hci_dev *hdev, struct iov_iter *iter);
>
>  int __hci_cmd_send(struct hci_dev *hdev, u16 opcode, u32 plen,
> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> index 90807562e8ed..21ef748e3528 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -3830,6 +3830,12 @@ static void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
>         __u16 handle, flags;
>         int err;
>
> +       /* Header is valid when ACL frame arrives here */
> +       if (hci_recv_bt_vendor(hdev, skb)) {
> +               hdev->stat.acl_rx++;
> +               return;
> +       }
> +
>         hdr = skb_pull_data(skb, sizeof(*hdr));
>         if (!hdr) {
>                 bt_dev_err(hdev, "ACL packet too small");
> @@ -3918,6 +3924,33 @@ static void hci_isodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
>                            handle, err);
>  }
>
> +bool hci_recv_bt_vendor(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> +       struct hci_event_hdr *evt_hdr;
> +       u8 evt, pkt_type;
> +
> +       if (!hdev->recv_bt_vendor)
> +               return false;
> +
> +       pkt_type = hci_skb_pkt_type(skb);
> +
> +       /* Save the event code before calling into the driver, since @skb
> +        * may be freed once consumed.
> +        */
> +       if (pkt_type == HCI_EVENT_PKT) {
> +               evt_hdr = hci_event_hdr(skb);
> +               evt = evt_hdr->evt;
> +       }
> +
> +       if (!hdev->recv_bt_vendor(hdev, skb))
> +               return false;
> +
> +       if (pkt_type == HCI_EVENT_PKT && evt != HCI_EV_VENDOR)
> +               bt_dev_warn(hdev, "consumed unexpected BT event 0x%2.2x", evt);
> +
> +       return true;
> +}
> +
>  static bool hci_req_is_complete(struct hci_dev *hdev)
>  {
>         struct sk_buff *skb;
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index ea858391c789..94c02b66bdfa 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -7801,6 +7801,11 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
>                 goto done;
>         }
>
> +       if (hci_recv_bt_vendor(hdev, skb)) {
> +               hdev->stat.evt_rx++;
> +               return;
> +       }

This seems too early actually, I would have expected it to run after
hci_event_func or within it if ev->func is NULL, that said we
currently assume HCI_EV_VENDOR=msft_vendor_evt which is probably not
valid, or maybe it is which then screw the whole idea that 0xff is
only used with 1 vendor specific domain, now if we try to squeesh both
a vendor event and a msft event handler their opcodes shall not
collide otherwise the whole thing doesn't work.

Anyway, I had the impression you would be using a vendor packet not a
vendor event, or you use both?

>         hci_dev_lock(hdev);
>         kfree_skb(hdev->recv_event);
>         hdev->recv_event = skb_clone(skb, GFP_KERNEL);
>
> --
> 2.34.1
>


-- 
Luiz Augusto von Dentz
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.