* [PATCH v3 0/7] Bluetooth: Miscellaneous fixes and cleanups
@ 2026-08-02 6:31 Zijun Hu
2026-08-02 6:31 ` [PATCH v3 1/7] Bluetooth: btintel: Fix diagnostics event detection Zijun Hu
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Zijun Hu @ 2026-08-02 6:31 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz, Abhishek Pandit-Subedi,
Manish Mandlik, Chethan Tumkur Narayan, Amitkumar Karwar,
Neeraj Kale
Cc: Zijun Hu, Luiz Augusto von Dentz, linux-bluetooth, linux-kernel,
Zijun Hu
This series has bug fixes, cleanups, a new helper, and a new hook for
transport drivers — all simple.
---
Changes in v3:
- Append 4 more simple commits.
- Link to v2: https://patch.msgid.link/20260727-generic_fix-v2-0-a57bdb81ac67@oss.qualcomm.com
Changes in v2:
- Rework patch 1: guard with (@len + 1) against skb->len, per Luiz.
- Add two more btintel/coredump cleanups.
- Drop "hci_core: Don't treat HCI_DRV_PKT/HCI_DIAG_PKT as unknown type".
- Link to v1: https://patch.msgid.link/20260725-generic_fix-v1-0-305aec261a19@oss.qualcomm.com
---
Zijun Hu (7):
Bluetooth: btintel: Fix diagnostics event detection
Bluetooth: btintel: Remove redundant (hdr->plen > 0) in btintel_recv_event()
Bluetooth: coredump: Expose header size and end marker to drivers
Bluetooth: hci_core: Introduce __hci_reset_dev() with a hardware error code
Bluetooth: btnxpuart: Simplify nxp_set_ind_reset() by __hci_reset_dev()
Bluetooth: hci_event: Introduce handle_ev_vendor() for HCI_EV_VENDOR
Bluetooth: hci_event: Use 255 as max event payload length in hci_ev_table[]
drivers/bluetooth/btintel.c | 5 ++---
drivers/bluetooth/btnxpuart.c | 14 +-------------
include/net/bluetooth/coredump.h | 7 +++++++
include/net/bluetooth/hci.h | 1 +
include/net/bluetooth/hci_core.h | 10 +++++++++-
net/bluetooth/coredump.c | 7 ++-----
net/bluetooth/hci_core.c | 6 +++---
net/bluetooth/hci_event.c | 22 +++++++++++++++-------
8 files changed, 40 insertions(+), 32 deletions(-)
---
base-commit: d264c90ca22e2034ef46b1831d38b1f47af44380
change-id: 20260724-generic_fix-6f13710b92ea
Best regards,
--
Zijun Hu <zijun.hu@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 1/7] Bluetooth: btintel: Fix diagnostics event detection
2026-08-02 6:31 [PATCH v3 0/7] Bluetooth: Miscellaneous fixes and cleanups Zijun Hu
@ 2026-08-02 6:31 ` Zijun Hu
2026-08-02 6:31 ` [PATCH v3 2/7] Bluetooth: btintel: Remove redundant (hdr->plen > 0) in btintel_recv_event() Zijun Hu
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Zijun Hu @ 2026-08-02 6:31 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz, Abhishek Pandit-Subedi,
Manish Mandlik, Chethan Tumkur Narayan, Amitkumar Karwar,
Neeraj Kale
Cc: Zijun Hu, Luiz Augusto von Dentz, linux-bluetooth, linux-kernel,
Zijun Hu
For a diagnostics VSE, diagnostics_hdr[] sits at the start of the event
payload, skb->data[2], but btintel_recv_event() wrongly guards its
memcmp with @len, which is measured from skb->data[3] for the earlier
INTEL_BOOTLOADER check.
Fix by using (@len + 1) instead, which ==
(skb->len - HCI_EVENT_HDR_SIZE) exactly.
Fixes: af395330abed ("Bluetooth: btintel: Add Intel devcoredump support")
Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
drivers/bluetooth/btintel.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 770b1fb371c7..d06a335ff1db 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -4016,17 +4016,17 @@ int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
kfree_skb(skb);
return 0;
}
}
/* Handle all diagnostics events separately. May still call
* hci_recv_frame.
*/
- if (len >= sizeof(diagnostics_hdr) &&
+ if (len + 1 >= sizeof(diagnostics_hdr) &&
memcmp(&skb->data[2], diagnostics_hdr,
sizeof(diagnostics_hdr)) == 0) {
return btintel_diagnostics(hdev, skb);
}
}
return hci_recv_frame(hdev, skb);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 2/7] Bluetooth: btintel: Remove redundant (hdr->plen > 0) in btintel_recv_event()
2026-08-02 6:31 [PATCH v3 0/7] Bluetooth: Miscellaneous fixes and cleanups Zijun Hu
2026-08-02 6:31 ` [PATCH v3 1/7] Bluetooth: btintel: Fix diagnostics event detection Zijun Hu
@ 2026-08-02 6:31 ` Zijun Hu
2026-08-02 6:31 ` [PATCH v3 3/7] Bluetooth: coredump: Expose header size and end marker to drivers Zijun Hu
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Zijun Hu @ 2026-08-02 6:31 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz, Abhishek Pandit-Subedi,
Manish Mandlik, Chethan Tumkur Narayan, Amitkumar Karwar,
Neeraj Kale
Cc: Zijun Hu, Luiz Augusto von Dentz, linux-bluetooth, linux-kernel,
Zijun Hu
Drop the check since:
- it is already implied by the existing (skb->len > HCI_EVENT_HDR_SIZE)
- hdr->plen is then not used by the function at all
Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
drivers/bluetooth/btintel.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index d06a335ff1db..bcb2514b7bc0 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -3986,18 +3986,17 @@ static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
return hci_recv_frame(hdev, skb);
}
int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_event_hdr *hdr = (void *)skb->data;
const char diagnostics_hdr[] = { 0x87, 0x80, 0x03 };
- if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff &&
- hdr->plen > 0) {
+ if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff) {
const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1;
unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1;
if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
switch (skb->data[2]) {
case 0x02:
/* When switching to the operational firmware
* the device sends a vendor specific event
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 3/7] Bluetooth: coredump: Expose header size and end marker to drivers
2026-08-02 6:31 [PATCH v3 0/7] Bluetooth: Miscellaneous fixes and cleanups Zijun Hu
2026-08-02 6:31 ` [PATCH v3 1/7] Bluetooth: btintel: Fix diagnostics event detection Zijun Hu
2026-08-02 6:31 ` [PATCH v3 2/7] Bluetooth: btintel: Remove redundant (hdr->plen > 0) in btintel_recv_event() Zijun Hu
@ 2026-08-02 6:31 ` Zijun Hu
2026-08-02 6:31 ` [PATCH v3 4/7] Bluetooth: hci_core: Introduce __hci_reset_dev() with a hardware error code Zijun Hu
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Zijun Hu @ 2026-08-02 6:31 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz, Abhishek Pandit-Subedi,
Manish Mandlik, Chethan Tumkur Narayan, Amitkumar Karwar,
Neeraj Kale
Cc: Zijun Hu, Luiz Augusto von Dentz, linux-bluetooth, linux-kernel,
Zijun Hu
To separate the coredump header and data far more easily, give a
vendor driver the option to pad its header to a fixed size, by
moving the header size limit and ending marker to coredump.h:
- HCI_DEVCD_HDR_SIZE_MAX: the max header size
- HCI_DEVCD_HDR_END_MARKER: the header-ending marker
Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
Previous version:
https://lore.kernel.org/all/20260713-btusb_prep_qcc2072-v2-2-bbcb651285f2@oss.qualcomm.com
Changes since previous version:
- Rename MAX_HCI_DEVCD_HDR_SIZE to HCI_DEVCD_HDR_SIZE_MAX
- Rename HCI_DEVCD_HDR_END to HCI_DEVCD_HDR_END_MARKER
- Improve the commit title and message
---
include/net/bluetooth/coredump.h | 7 +++++++
net/bluetooth/coredump.c | 7 ++-----
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/include/net/bluetooth/coredump.h b/include/net/bluetooth/coredump.h
index ab85a6adfffd..1f071ab55416 100644
--- a/include/net/bluetooth/coredump.h
+++ b/include/net/bluetooth/coredump.h
@@ -3,16 +3,23 @@
* Copyright (C) 2022 Google Corporation
*/
#ifndef __COREDUMP_H
#define __COREDUMP_H
#define DEVCOREDUMP_TIMEOUT msecs_to_jiffies(10000) /* 10 sec */
+/*
+ * Max header size, shared by both the devcoredump core and
+ * the dmp_hdr() registered by driver via hci_devcd_register()
+ */
+#define HCI_DEVCD_HDR_SIZE_MAX 512
+#define HCI_DEVCD_HDR_END_MARKER "--- Start dump ---\n"
+
typedef void (*coredump_t)(struct hci_dev *hdev);
typedef void (*dmp_hdr_t)(struct hci_dev *hdev, struct sk_buff *skb);
typedef void (*notify_change_t)(struct hci_dev *hdev, int state);
/* struct hci_devcoredump - Devcoredump state
*
* @supported: Indicates if FW dump collection is supported by driver
* @state: Current state of dump collection
diff --git a/net/bluetooth/coredump.c b/net/bluetooth/coredump.c
index 913bbba559f8..5bee863bd6d2 100644
--- a/net/bluetooth/coredump.c
+++ b/net/bluetooth/coredump.c
@@ -29,18 +29,16 @@ struct hci_devcoredump_skb_pattern {
#define hci_dmp_cb(skb) ((struct hci_devcoredump_skb_cb *)((skb)->cb))
#define DBG_UNEXPECTED_STATE() \
bt_dev_dbg(hdev, \
"Unexpected packet (%d) for state %s.", \
hci_dmp_cb(skb)->pkt_type, \
hci_devcd_state_name(hdev->dump.state))
-#define MAX_DEVCOREDUMP_HDR_SIZE 512 /* bytes */
-
static int hci_devcd_update_hdr_state(char *buf, size_t size, int state)
{
int len = 0;
if (!buf)
return 0;
len = scnprintf(buf, size, "Bluetooth devcoredump\nState: %d\n", state);
@@ -58,28 +56,27 @@ static int hci_devcd_update_state(struct hci_dev *hdev, int state)
hdev->dump.state = state;
return hci_devcd_update_hdr_state(hdev->dump.head,
hdev->dump.alloc_size, state);
}
static int hci_devcd_mkheader(struct hci_dev *hdev, struct sk_buff *skb)
{
- char dump_start[] = "--- Start dump ---\n";
char hdr[80];
int hdr_len;
hdr_len = hci_devcd_update_hdr_state(hdr, sizeof(hdr),
HCI_DEVCOREDUMP_IDLE);
skb_put_data(skb, hdr, hdr_len);
if (hdev->dump.dmp_hdr)
hdev->dump.dmp_hdr(hdev, skb);
- skb_put_data(skb, dump_start, strlen(dump_start));
+ skb_put_data(skb, HCI_DEVCD_HDR_END_MARKER, strlen(HCI_DEVCD_HDR_END_MARKER));
return skb->len;
}
/* Do not call with hci_dev_lock since this calls driver code. */
static void hci_devcd_notify(struct hci_dev *hdev, int state)
{
if (hdev->dump.notify_change)
@@ -149,17 +146,17 @@ static bool hci_devcd_memset(struct hci_dev *hdev, u8 pattern, u32 len)
/* Call with hci_dev_lock only. */
static int hci_devcd_prepare(struct hci_dev *hdev, u32 dump_size)
{
struct sk_buff *skb;
int dump_hdr_size;
int err = 0;
- skb = alloc_skb(MAX_DEVCOREDUMP_HDR_SIZE, GFP_ATOMIC);
+ skb = alloc_skb(HCI_DEVCD_HDR_SIZE_MAX, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
dump_hdr_size = hci_devcd_mkheader(hdev, skb);
if (hci_devcd_alloc(hdev, dump_hdr_size + dump_size)) {
err = -ENOMEM;
goto hdr_free;
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 4/7] Bluetooth: hci_core: Introduce __hci_reset_dev() with a hardware error code
2026-08-02 6:31 [PATCH v3 0/7] Bluetooth: Miscellaneous fixes and cleanups Zijun Hu
` (2 preceding siblings ...)
2026-08-02 6:31 ` [PATCH v3 3/7] Bluetooth: coredump: Expose header size and end marker to drivers Zijun Hu
@ 2026-08-02 6:31 ` Zijun Hu
2026-08-02 6:31 ` [PATCH v3 5/7] Bluetooth: btnxpuart: Simplify nxp_set_ind_reset() by __hci_reset_dev() Zijun Hu
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Zijun Hu @ 2026-08-02 6:31 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz, Abhishek Pandit-Subedi,
Manish Mandlik, Chethan Tumkur Narayan, Amitkumar Karwar,
Neeraj Kale
Cc: Zijun Hu, Luiz Augusto von Dentz, linux-bluetooth, linux-kernel,
Zijun Hu
hci_reset_dev() injects a constant hardware error code 0x00 to restart
the device. But a transport driver may need a different error code.
Fix by introducing __hci_reset_dev(hdev, hw_err_code), which will be
used by a follow-up patch.
Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
include/net/bluetooth/hci_core.h | 8 +++++++-
net/bluetooth/hci_core.c | 6 +++---
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 01b938c4b24a..b7e71733f360 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1780,17 +1780,23 @@ static inline struct hci_dev *hci_alloc_dev(void)
void hci_free_dev(struct hci_dev *hdev);
int hci_register_dev(struct hci_dev *hdev);
void hci_unregister_dev(struct hci_dev *hdev);
void hci_release_dev(struct hci_dev *hdev);
int hci_register_suspend_notifier(struct hci_dev *hdev);
int hci_unregister_suspend_notifier(struct hci_dev *hdev);
int hci_suspend_dev(struct hci_dev *hdev);
int hci_resume_dev(struct hci_dev *hdev);
-int hci_reset_dev(struct hci_dev *hdev);
+int __hci_reset_dev(struct hci_dev *hdev, u8 hw_err_code);
+
+static inline int hci_reset_dev(struct hci_dev *hdev)
+{
+ return __hci_reset_dev(hdev, 0);
+}
+
int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb);
int hci_recv_diag(struct hci_dev *hdev, struct sk_buff *skb);
__printf(2, 3) void hci_set_hw_info(struct hci_dev *hdev, const char *fmt, ...);
__printf(2, 3) void hci_set_fw_info(struct hci_dev *hdev, const char *fmt, ...);
static inline void hci_set_msft_opcode(struct hci_dev *hdev, __u16 opcode)
{
#if IS_ENABLED(CONFIG_BT_MSFTEXT)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9d5adf882509..509c820a693d 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2847,34 +2847,34 @@ int hci_resume_dev(struct hci_dev *hdev)
hdev->wake_addr_type);
hci_sock_dev_event(hdev, HCI_DEV_RESUME);
return ret;
}
EXPORT_SYMBOL(hci_resume_dev);
/* Reset HCI device */
-int hci_reset_dev(struct hci_dev *hdev)
+int __hci_reset_dev(struct hci_dev *hdev, u8 hw_err_code)
{
- static const u8 hw_err[] = { HCI_EV_HARDWARE_ERROR, 0x01, 0x00 };
+ const u8 hw_err[] = { HCI_EV_HARDWARE_ERROR, 0x01, hw_err_code };
struct sk_buff *skb;
skb = bt_skb_alloc(3, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
skb_put_data(skb, hw_err, 3);
bt_dev_err(hdev, "Injecting HCI hardware error event");
/* Send Hardware Error to upper stack */
return hci_recv_frame(hdev, skb);
}
-EXPORT_SYMBOL(hci_reset_dev);
+EXPORT_SYMBOL(__hci_reset_dev);
static u8 hci_dev_classify_pkt_type(struct hci_dev *hdev, struct sk_buff *skb)
{
if (hdev->classify_pkt_type)
return hdev->classify_pkt_type(hdev, skb);
return hci_skb_pkt_type(skb);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 5/7] Bluetooth: btnxpuart: Simplify nxp_set_ind_reset() by __hci_reset_dev()
2026-08-02 6:31 [PATCH v3 0/7] Bluetooth: Miscellaneous fixes and cleanups Zijun Hu
` (3 preceding siblings ...)
2026-08-02 6:31 ` [PATCH v3 4/7] Bluetooth: hci_core: Introduce __hci_reset_dev() with a hardware error code Zijun Hu
@ 2026-08-02 6:31 ` Zijun Hu
2026-08-02 6:31 ` [PATCH v3 6/7] Bluetooth: hci_event: Introduce handle_ev_vendor() for HCI_EV_VENDOR Zijun Hu
2026-08-02 6:31 ` [PATCH v3 7/7] Bluetooth: hci_event: Use 255 as max event payload length in hci_ev_table[] Zijun Hu
6 siblings, 0 replies; 8+ messages in thread
From: Zijun Hu @ 2026-08-02 6:31 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz, Abhishek Pandit-Subedi,
Manish Mandlik, Chethan Tumkur Narayan, Amitkumar Karwar,
Neeraj Kale
Cc: Zijun Hu, Luiz Augusto von Dentz, linux-bluetooth, linux-kernel,
Zijun Hu
nxp_set_ind_reset() injects the non-zero hardware error code
BTNXPUART_IR_HW_ERR.
Simplify it by __hci_reset_dev(hdev, BTNXPUART_IR_HW_ERR).
Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
drivers/bluetooth/btnxpuart.c | 14 +-------------
1 file changed, 1 insertion(+), 13 deletions(-)
diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c
index 0bb300eef157..993c48b5f593 100644
--- a/drivers/bluetooth/btnxpuart.c
+++ b/drivers/bluetooth/btnxpuart.c
@@ -1326,29 +1326,17 @@ static int nxp_check_boot_sign(struct btnxpuart_dev *nxpdev)
return wait_event_interruptible_timeout(nxpdev->check_boot_sign_wait_q,
!test_bit(BTNXPUART_CHECK_BOOT_SIGNATURE,
&nxpdev->tx_state),
msecs_to_jiffies(1000));
}
static int nxp_set_ind_reset(struct hci_dev *hdev, void *data)
{
- static const u8 ir_hw_err[] = { HCI_EV_HARDWARE_ERROR,
- 0x01, BTNXPUART_IR_HW_ERR };
- struct sk_buff *skb;
-
- skb = bt_skb_alloc(3, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
- skb_put_data(skb, ir_hw_err, 3);
-
- /* Inject Hardware Error to upper stack */
- return hci_recv_frame(hdev, skb);
+ return __hci_reset_dev(hdev, BTNXPUART_IR_HW_ERR);
}
/* Firmware dump */
static void nxp_coredump(struct hci_dev *hdev)
{
struct sk_buff *skb;
u8 pcmd = 2;
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 6/7] Bluetooth: hci_event: Introduce handle_ev_vendor() for HCI_EV_VENDOR
2026-08-02 6:31 [PATCH v3 0/7] Bluetooth: Miscellaneous fixes and cleanups Zijun Hu
` (4 preceding siblings ...)
2026-08-02 6:31 ` [PATCH v3 5/7] Bluetooth: btnxpuart: Simplify nxp_set_ind_reset() by __hci_reset_dev() Zijun Hu
@ 2026-08-02 6:31 ` Zijun Hu
2026-08-02 6:31 ` [PATCH v3 7/7] Bluetooth: hci_event: Use 255 as max event payload length in hci_ev_table[] Zijun Hu
6 siblings, 0 replies; 8+ messages in thread
From: Zijun Hu @ 2026-08-02 6:31 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz, Abhishek Pandit-Subedi,
Manish Mandlik, Chethan Tumkur Narayan, Amitkumar Karwar,
Neeraj Kale
Cc: Zijun Hu, Luiz Augusto von Dentz, linux-bluetooth, linux-kernel,
Zijun Hu
Introduce the hook to solve issues below:
msft_vendor_evt(), the current handler for all VSEs, is unsuitable
since:
- many VSEs are not MSFT ones;
- it always corrupts the non-MSFT VSEs by calling skb_pull_data()
once the MSFT extension is enabled.
Several issues are caused by many transport drivers pre-processing
VSEs in their RX path, often an IRQ-disabled atomic context. Take
the two typical cases below as examples:
Case 1:
// no btmon log, no way to reach userspace
Step 1: handle and free @original_skb directly
Case 2:
// hurts performance and consumes GFP_ATOMIC memory
Step 1: cloned_skb = skb_clone(original_skb, GFP_ATOMIC);
// the VSE is handled here
Step 2: handle and free @cloned_skb
Step 3: hci_recv_frame(hdev, original_skb);
// already handled, but re-enters the stack's event-handling path
Step 4: hci_event_packet(hdev, original_skb);
Fix by introducing the hook with usage:
1) the transport driver registers the hook for VSEs of interest;
2) the stack calls it in process context, handling the VSE like any
other event:
- if interested, handle the VSE - no need to free it - and
return true;
- otherwise return false.
Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
Previous version:
https://lore.kernel.org/all/20260722-support_vendor_hci-v2-3-132b506460a4@oss.qualcomm.com
Changes since previous version:
1) Don't handle ACL frames with a vendor-reserved handle for special
usage.
2) Rename recv_bt_vendor() to handle_ev_vendor(), since the event is
only in the RX direction.
---
include/net/bluetooth/hci_core.h | 2 ++
net/bluetooth/hci_event.c | 10 +++++++++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index b7e71733f360..87db877f8c5c 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -641,16 +641,18 @@ struct hci_dev {
#endif
int (*open)(struct hci_dev *hdev);
int (*close)(struct hci_dev *hdev);
int (*flush)(struct hci_dev *hdev);
int (*setup)(struct hci_dev *hdev);
int (*shutdown)(struct hci_dev *hdev);
int (*send)(struct hci_dev *hdev, struct sk_buff *skb);
+ /* Handle HCI_EV_VENDOR; return true if handled, false otherwise */
+ bool (*handle_ev_vendor)(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);
int (*post_init)(struct hci_dev *hdev);
int (*set_diag)(struct hci_dev *hdev, bool enable);
int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
void (*reset)(struct hci_dev *hdev);
bool (*wakeup)(struct hci_dev *hdev);
int (*set_quality_report)(struct hci_dev *hdev, bool enable);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 9c8bf6708356..8452d372524f 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -7597,16 +7597,24 @@ static void hci_le_meta_evt(struct hci_dev *hdev, void *data,
ev->subevent, skb->len, subev->max_len);
data = hci_le_ev_skb_pull(hdev, skb, ev->subevent, subev->min_len);
if (!data)
return;
subev->func(hdev, data, skb);
}
+static void hci_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb)
+{
+ if (hdev->handle_ev_vendor && hdev->handle_ev_vendor(hdev, skb))
+ return;
+
+ msft_vendor_evt(hdev, data, skb);
+}
+
static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,
u8 event, struct sk_buff *skb)
{
struct hci_ev_cmd_complete *ev;
struct hci_event_hdr *hdr;
if (!skb)
return false;
@@ -7824,17 +7832,17 @@ static const struct hci_ev {
sizeof(struct hci_ev_keypress_notify)),
/* [0x3d = HCI_EV_REMOTE_HOST_FEATURES] */
HCI_EV(HCI_EV_REMOTE_HOST_FEATURES, hci_remote_host_features_evt,
sizeof(struct hci_ev_remote_host_features)),
/* [0x3e = HCI_EV_LE_META] */
HCI_EV_REQ_VL(HCI_EV_LE_META, hci_le_meta_evt,
sizeof(struct hci_ev_le_meta), HCI_MAX_EVENT_SIZE),
/* [0xff = HCI_EV_VENDOR] */
- HCI_EV_VL(HCI_EV_VENDOR, msft_vendor_evt, 0, HCI_MAX_EVENT_SIZE),
+ HCI_EV_VL(HCI_EV_VENDOR, hci_vendor_evt, 0, HCI_MAX_EVENT_SIZE),
};
static void hci_event_func(struct hci_dev *hdev, u8 event, struct sk_buff *skb,
u16 *opcode, u8 *status,
hci_req_complete_t *req_complete,
hci_req_complete_skb_t *req_complete_skb)
{
const struct hci_ev *ev = &hci_ev_table[event];
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 7/7] Bluetooth: hci_event: Use 255 as max event payload length in hci_ev_table[]
2026-08-02 6:31 [PATCH v3 0/7] Bluetooth: Miscellaneous fixes and cleanups Zijun Hu
` (5 preceding siblings ...)
2026-08-02 6:31 ` [PATCH v3 6/7] Bluetooth: hci_event: Introduce handle_ev_vendor() for HCI_EV_VENDOR Zijun Hu
@ 2026-08-02 6:31 ` Zijun Hu
6 siblings, 0 replies; 8+ messages in thread
From: Zijun Hu @ 2026-08-02 6:31 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz, Abhishek Pandit-Subedi,
Manish Mandlik, Chethan Tumkur Narayan, Amitkumar Karwar,
Neeraj Kale
Cc: Zijun Hu, Luiz Augusto von Dentz, linux-bluetooth, linux-kernel,
Zijun Hu
hci_event_func() validates skb->len against ev->max_len from the
entry in hci_ev_table[]. By then, the header has already been
stripped by skb_pull(). So the max event payload is 255, but
hci_ev_table[] still uses HCI_MAX_EVENT_SIZE (260) for it, which is
imprecise.
Fix by introducing HCI_MAX_EVENT_PLEN (255) and using it instead.
Signed-off-by: Zijun Hu <zijun.hu@oss.qualcomm.com>
---
Both hci_cc_table[] and hci_le_ev_table[] have the same issue. I'll
send separate patches for them if this one is accepted.
---
include/net/bluetooth/hci.h | 1 +
net/bluetooth/hci_event.c | 14 +++++++-------
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index cd3520a29131..1641d879dbda 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -3377,16 +3377,17 @@ struct hci_ev_si_security {
__u16 proto;
__u16 subproto;
__u8 incoming;
} __packed;
/* ---- HCI Packet structures ---- */
#define HCI_COMMAND_HDR_SIZE 3
#define HCI_EVENT_HDR_SIZE 2
+#define HCI_MAX_EVENT_PLEN 255
#define HCI_ACL_HDR_SIZE 4
#define HCI_SCO_HDR_SIZE 3
#define HCI_ISO_HDR_SIZE 4
struct hci_command_hdr {
__le16 opcode; /* OCF & OGF */
__u8 plen;
} __packed;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 8452d372524f..3879ba302d4d 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -7721,17 +7721,17 @@ static const struct hci_ev {
};
u16 min_len;
u16 max_len;
} hci_ev_table[U8_MAX + 1] = {
/* [0x01 = HCI_EV_INQUIRY_COMPLETE] */
HCI_EV_STATUS(HCI_EV_INQUIRY_COMPLETE, hci_inquiry_complete_evt),
/* [0x02 = HCI_EV_INQUIRY_RESULT] */
HCI_EV_VL(HCI_EV_INQUIRY_RESULT, hci_inquiry_result_evt,
- sizeof(struct hci_ev_inquiry_result), HCI_MAX_EVENT_SIZE),
+ sizeof(struct hci_ev_inquiry_result), HCI_MAX_EVENT_PLEN),
/* [0x03 = HCI_EV_CONN_COMPLETE] */
HCI_EV(HCI_EV_CONN_COMPLETE, hci_conn_complete_evt,
sizeof(struct hci_ev_conn_complete)),
/* [0x04 = HCI_EV_CONN_REQUEST] */
HCI_EV(HCI_EV_CONN_REQUEST, hci_conn_request_evt,
sizeof(struct hci_ev_conn_request)),
/* [0x05 = HCI_EV_DISCONN_COMPLETE] */
HCI_EV(HCI_EV_DISCONN_COMPLETE, hci_disconn_complete_evt,
@@ -7749,29 +7749,29 @@ static const struct hci_ev {
HCI_EV(HCI_EV_CHANGE_LINK_KEY_COMPLETE,
hci_change_link_key_complete_evt,
sizeof(struct hci_ev_change_link_key_complete)),
/* [0x0b = HCI_EV_REMOTE_FEATURES] */
HCI_EV(HCI_EV_REMOTE_FEATURES, hci_remote_features_evt,
sizeof(struct hci_ev_remote_features)),
/* [0x0e = HCI_EV_CMD_COMPLETE] */
HCI_EV_REQ_VL(HCI_EV_CMD_COMPLETE, hci_cmd_complete_evt,
- sizeof(struct hci_ev_cmd_complete), HCI_MAX_EVENT_SIZE),
+ sizeof(struct hci_ev_cmd_complete), HCI_MAX_EVENT_PLEN),
/* [0x0f = HCI_EV_CMD_STATUS] */
HCI_EV_REQ(HCI_EV_CMD_STATUS, hci_cmd_status_evt,
sizeof(struct hci_ev_cmd_status)),
/* [0x10 = HCI_EV_CMD_STATUS] */
HCI_EV(HCI_EV_HARDWARE_ERROR, hci_hardware_error_evt,
sizeof(struct hci_ev_hardware_error)),
/* [0x12 = HCI_EV_ROLE_CHANGE] */
HCI_EV(HCI_EV_ROLE_CHANGE, hci_role_change_evt,
sizeof(struct hci_ev_role_change)),
/* [0x13 = HCI_EV_NUM_COMP_PKTS] */
HCI_EV_VL(HCI_EV_NUM_COMP_PKTS, hci_num_comp_pkts_evt,
- sizeof(struct hci_ev_num_comp_pkts), HCI_MAX_EVENT_SIZE),
+ sizeof(struct hci_ev_num_comp_pkts), HCI_MAX_EVENT_PLEN),
/* [0x14 = HCI_EV_MODE_CHANGE] */
HCI_EV(HCI_EV_MODE_CHANGE, hci_mode_change_evt,
sizeof(struct hci_ev_mode_change)),
/* [0x16 = HCI_EV_PIN_CODE_REQ] */
HCI_EV(HCI_EV_PIN_CODE_REQ, hci_pin_code_request_evt,
sizeof(struct hci_ev_pin_code_req)),
/* [0x17 = HCI_EV_LINK_KEY_REQ] */
HCI_EV(HCI_EV_LINK_KEY_REQ, hci_link_key_request_evt,
@@ -7787,27 +7787,27 @@ static const struct hci_ev {
sizeof(struct hci_ev_pkt_type_change)),
/* [0x20 = HCI_EV_PSCAN_REP_MODE] */
HCI_EV(HCI_EV_PSCAN_REP_MODE, hci_pscan_rep_mode_evt,
sizeof(struct hci_ev_pscan_rep_mode)),
/* [0x22 = HCI_EV_INQUIRY_RESULT_WITH_RSSI] */
HCI_EV_VL(HCI_EV_INQUIRY_RESULT_WITH_RSSI,
hci_inquiry_result_with_rssi_evt,
sizeof(struct hci_ev_inquiry_result_rssi),
- HCI_MAX_EVENT_SIZE),
+ HCI_MAX_EVENT_PLEN),
/* [0x23 = HCI_EV_REMOTE_EXT_FEATURES] */
HCI_EV(HCI_EV_REMOTE_EXT_FEATURES, hci_remote_ext_features_evt,
sizeof(struct hci_ev_remote_ext_features)),
/* [0x2c = HCI_EV_SYNC_CONN_COMPLETE] */
HCI_EV(HCI_EV_SYNC_CONN_COMPLETE, hci_sync_conn_complete_evt,
sizeof(struct hci_ev_sync_conn_complete)),
/* [0x2f = HCI_EV_EXTENDED_INQUIRY_RESULT] */
HCI_EV_VL(HCI_EV_EXTENDED_INQUIRY_RESULT,
hci_extended_inquiry_result_evt,
- sizeof(struct hci_ev_ext_inquiry_result), HCI_MAX_EVENT_SIZE),
+ sizeof(struct hci_ev_ext_inquiry_result), HCI_MAX_EVENT_PLEN),
/* [0x30 = HCI_EV_KEY_REFRESH_COMPLETE] */
HCI_EV(HCI_EV_KEY_REFRESH_COMPLETE, hci_key_refresh_complete_evt,
sizeof(struct hci_ev_key_refresh_complete)),
/* [0x31 = HCI_EV_IO_CAPA_REQUEST] */
HCI_EV(HCI_EV_IO_CAPA_REQUEST, hci_io_capa_request_evt,
sizeof(struct hci_ev_io_capa_request)),
/* [0x32 = HCI_EV_IO_CAPA_REPLY] */
HCI_EV(HCI_EV_IO_CAPA_REPLY, hci_io_capa_reply_evt,
@@ -7830,19 +7830,19 @@ static const struct hci_ev {
/* [0x3c = HCI_EV_KEYPRESS_NOTIFY] */
HCI_EV(HCI_EV_KEYPRESS_NOTIFY, hci_keypress_notify_evt,
sizeof(struct hci_ev_keypress_notify)),
/* [0x3d = HCI_EV_REMOTE_HOST_FEATURES] */
HCI_EV(HCI_EV_REMOTE_HOST_FEATURES, hci_remote_host_features_evt,
sizeof(struct hci_ev_remote_host_features)),
/* [0x3e = HCI_EV_LE_META] */
HCI_EV_REQ_VL(HCI_EV_LE_META, hci_le_meta_evt,
- sizeof(struct hci_ev_le_meta), HCI_MAX_EVENT_SIZE),
+ sizeof(struct hci_ev_le_meta), HCI_MAX_EVENT_PLEN),
/* [0xff = HCI_EV_VENDOR] */
- HCI_EV_VL(HCI_EV_VENDOR, hci_vendor_evt, 0, HCI_MAX_EVENT_SIZE),
+ HCI_EV_VL(HCI_EV_VENDOR, hci_vendor_evt, 0, HCI_MAX_EVENT_PLEN),
};
static void hci_event_func(struct hci_dev *hdev, u8 event, struct sk_buff *skb,
u16 *opcode, u8 *status,
hci_req_complete_t *req_complete,
hci_req_complete_skb_t *req_complete_skb)
{
const struct hci_ev *ev = &hci_ev_table[event];
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-08-02 6:32 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-02 6:31 [PATCH v3 0/7] Bluetooth: Miscellaneous fixes and cleanups Zijun Hu
2026-08-02 6:31 ` [PATCH v3 1/7] Bluetooth: btintel: Fix diagnostics event detection Zijun Hu
2026-08-02 6:31 ` [PATCH v3 2/7] Bluetooth: btintel: Remove redundant (hdr->plen > 0) in btintel_recv_event() Zijun Hu
2026-08-02 6:31 ` [PATCH v3 3/7] Bluetooth: coredump: Expose header size and end marker to drivers Zijun Hu
2026-08-02 6:31 ` [PATCH v3 4/7] Bluetooth: hci_core: Introduce __hci_reset_dev() with a hardware error code Zijun Hu
2026-08-02 6:31 ` [PATCH v3 5/7] Bluetooth: btnxpuart: Simplify nxp_set_ind_reset() by __hci_reset_dev() Zijun Hu
2026-08-02 6:31 ` [PATCH v3 6/7] Bluetooth: hci_event: Introduce handle_ev_vendor() for HCI_EV_VENDOR Zijun Hu
2026-08-02 6:31 ` [PATCH v3 7/7] Bluetooth: hci_event: Use 255 as max event payload length in hci_ev_table[] Zijun Hu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox