* [PATCH BlueZ v3 1/4] doc/hci-protocol: Fix missing & on mtu argument in BT_RCVMTU example
2026-09-03 14:47 [PATCH BlueZ v3 0/4] BlueZ: Support vendor packets Zijun Hu
@ 2026-09-03 14:47 ` Zijun Hu
2026-09-03 15:53 ` BlueZ: Support vendor packets bluez.test.bot
2026-09-03 14:47 ` [PATCH BlueZ v3 2/4] monitor: s/vendor_(evt|event)/\1_vendor/ Zijun Hu
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Zijun Hu @ 2026-09-03 14:47 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz
Cc: Zijun Hu, linux-bluetooth, linux-kernel
getsockopt() requires a pointer argument, but mtu was passed by value.
Fix by using &mtu instead of mtu.
---
doc/hci-protocol.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/hci-protocol.rst b/doc/hci-protocol.rst
index f28684655842..db10b35df736 100644
--- a/doc/hci-protocol.rst
+++ b/doc/hci-protocol.rst
@@ -129,17 +129,17 @@ Example:
.. code-block::
uint16_t mtu;
socklen_t len;
int err;
len = sizeof(mtu);
- err = getsockopt(sock, SOL_BLUETOOTH, BT_RCVMTU, mtu, &len);
+ err = getsockopt(sock, SOL_BLUETOOTH, BT_RCVMTU, &mtu, &len);
RESOURCES
=========
http://www.bluez.org
REPORTING BUGS
==============
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* RE: BlueZ: Support vendor packets
2026-09-03 14:47 ` [PATCH BlueZ v3 1/4] doc/hci-protocol: Fix missing & on mtu argument in BT_RCVMTU example Zijun Hu
@ 2026-09-03 15:53 ` bluez.test.bot
0 siblings, 0 replies; 9+ messages in thread
From: bluez.test.bot @ 2026-09-03 15:53 UTC (permalink / raw)
To: linux-bluetooth, zijun.hu
[-- Attachment #1: Type: text/plain, Size: 2160 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=1157193
---Test result---
Test Summary:
CheckPatch PASS 1.27 seconds
GitLint FAIL 0.86 seconds
BuildEll PASS 20.46 seconds
BluezMake PASS 607.30 seconds
MakeCheck PASS 19.51 seconds
MakeDistcheck PASS 163.48 seconds
CheckValgrind PASS 235.45 seconds
CheckSmatch WARNING 317.06 seconds
bluezmakeextell PASS 104.20 seconds
IncrementalBuild PASS 663.91 seconds
ScanBuild PASS 1011.07 seconds
Details
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[BlueZ,v3,1/4] doc/hci-protocol: Fix missing & on mtu argument in BT_RCVMTU example
1: T1 Title exceeds max length (83>80): "[BlueZ,v3,1/4] doc/hci-protocol: Fix missing & on mtu argument in BT_RCVMTU example"
[BlueZ,v3,3/4] doc/hci-protocol: Add BT_RECV_VENDOR_PKT socket option for HCI_CHANNEL_USER
1: T1 Title exceeds max length (90>80): "[BlueZ,v3,3/4] doc/hci-protocol: Add BT_RECV_VENDOR_PKT socket option for HCI_CHANNEL_USER"
##############################
Test: CheckSmatch - WARNING
Desc: Run smatch tool with source
Output:
monitor/msft.c: note: in included file:monitor/msft.h:88:44: warning: array of flexible structuresmonitor/packet.c:2003:26: warning: Variable length array is used.monitor/packet.c: note: in included file:monitor/bt.h:3924:52: warning: array of flexible structuresmonitor/bt.h:3912:40: warning: array of flexible structuresmonitor/packet.c:2003:26: warning: Variable length array is used.monitor/packet.c: note: in included file:monitor/bt.h:3924:52: warning: array of flexible structuresmonitor/bt.h:3912:40: warning: array of flexible structures
https://github.com/bluez/bluez/pull/2481
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH BlueZ v3 2/4] monitor: s/vendor_(evt|event)/\1_vendor/
2026-09-03 14:47 [PATCH BlueZ v3 0/4] BlueZ: Support vendor packets Zijun Hu
2026-09-03 14:47 ` [PATCH BlueZ v3 1/4] doc/hci-protocol: Fix missing & on mtu argument in BT_RCVMTU example Zijun Hu
@ 2026-09-03 14:47 ` Zijun Hu
2026-09-03 14:47 ` [PATCH BlueZ v3 3/4] doc/hci-protocol: Add BT_RECV_VENDOR_PKT socket option for HCI_CHANNEL_USER Zijun Hu
2026-09-03 14:47 ` [PATCH BlueZ v3 4/4] monitor: Support vendor packets Zijun Hu
3 siblings, 0 replies; 9+ messages in thread
From: Zijun Hu @ 2026-09-03 14:47 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz
Cc: Zijun Hu, linux-bluetooth, linux-kernel
Kernel include/net/bluetooth/hci.h defines:
#define HCI_EVENT_PKT 0x04
#define HCI_VENDOR_PKT 0xff
#define HCI_EV_VENDOR 0xff
HCI_VENDOR_PKT and HCI_EV_VENDOR share the same value, but are very
different, as the table below shows:
+------------+-----------------------+---------------------------+
| | HCI_VENDOR_PKT | HCI_EV_VENDOR |
+------------+-----------------------+---------------------------+
| Defined by | Vendor | BT SIG |
+------------+-----------------------+---------------------------+
| Hierarchy | Parallel to | Nested inside |
| | HCI_EVENT_PKT | HCI_EVENT_PKT |
+------------+-----------------------+---------------------------+
| Direction | RX and TX | RX only |
+------------+-----------------------+---------------------------+
| kernel <-> | HCI_VENDOR_PKT, ... | 0x04, HCI_EV_VENDOR, ... |
| userspace | | |
+------------+-----------------------+---------------------------+
| kernel <-> | RX: 23, vendor packet | RX: 3, HCI_EV_VENDOR, ... |
| monitor | TX: 22, vendor packet | |
+------------+-----------------------+---------------------------+
monitor is about to gain HCI_VENDOR_PKT support. To avoid confusing the
two, rename what deals with HCI_EV_VENDOR to follow its pattern:
s/vendor_(evt|event)/\1_vendor/
---
monitor/broadcom.c | 10 +++++-----
monitor/broadcom.h | 4 ++--
monitor/intel.c | 16 ++++++++--------
monitor/intel.h | 4 ++--
monitor/msft.c | 6 +++---
monitor/msft.h | 4 ++--
monitor/packet.c | 20 ++++++++++----------
monitor/vendor.c | 2 +-
monitor/vendor.h | 4 ++--
9 files changed, 35 insertions(+), 35 deletions(-)
diff --git a/monitor/broadcom.c b/monitor/broadcom.c
index 80c95e91db0a..0dbc5eb39bb8 100644
--- a/monitor/broadcom.c
+++ b/monitor/broadcom.c
@@ -707,24 +707,24 @@ void broadcom_lm_diag(const void *data, uint8_t size)
}
static void lm_diag_evt(struct timeval *tv, uint16_t index,
const void *data, uint8_t size)
{
broadcom_lm_diag(data, 63);
}
-static const struct vendor_evt vendor_evt_table[] = {
+static const struct evt_vendor evt_vendor_table[] = {
{ 0xb4, "LM Diag", lm_diag_evt, 64, true },
{ }
};
-const struct vendor_evt *broadcom_vendor_evt(uint8_t evt)
+const struct evt_vendor *broadcom_evt_vendor(uint8_t evt)
{
int i;
- for (i = 0; vendor_evt_table[i].str; i++) {
- if (vendor_evt_table[i].evt == evt)
- return &vendor_evt_table[i];
+ for (i = 0; evt_vendor_table[i].str; i++) {
+ if (evt_vendor_table[i].evt == evt)
+ return &evt_vendor_table[i];
}
return NULL;
}
diff --git a/monitor/broadcom.h b/monitor/broadcom.h
index 5cb51d81dbb8..36492a4071a7 100644
--- a/monitor/broadcom.h
+++ b/monitor/broadcom.h
@@ -7,13 +7,13 @@
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
*/
#include <stdint.h>
struct vendor_ocf;
-struct vendor_evt;
+struct evt_vendor;
const struct vendor_ocf *broadcom_vendor_ocf(uint16_t ocf);
-const struct vendor_evt *broadcom_vendor_evt(uint8_t evt);
+const struct evt_vendor *broadcom_evt_vendor(uint8_t evt);
void broadcom_lm_diag(const void *data, uint8_t size);
diff --git a/monitor/intel.c b/monitor/intel.c
index 782fda675422..d52b2dc80e4c 100644
--- a/monitor/intel.c
+++ b/monitor/intel.c
@@ -1286,17 +1286,17 @@ static void system_exception_evt(struct timeval *tv, uint16_t index,
break;
}
print_field("Type: %s (0x%2.2x)", str, type);
packet_hexdump(data + 1, size - 1);
}
-static const struct vendor_evt vendor_evt_table[] = {
+static const struct evt_vendor evt_vendor_table[] = {
{ 0x00, "Startup",
startup_evt, 0, true },
{ 0x01, "Fatal Exception",
fatal_exception_evt, 4, true },
{ 0x02, "Bootup",
bootup_evt, 6, true },
{ 0x05, "Default BD Data",
default_bd_data_evt, 1, true },
@@ -1861,17 +1861,17 @@ static void intel_vendor_ext_evt(struct timeval *tv, uint16_t index,
tlv = process_ext_subevent(tlv, last_tlv);
/* If an error occurs in decoding the subevents, hexdump the packet. */
if (!tlv)
packet_hexdump(data, size);
}
/* Vendor extended events with a vendor prefix. */
-static const struct vendor_evt vendor_prefix_evt_table[] = {
+static const struct evt_vendor vendor_prefix_evt_table[] = {
{ 0x03, "Extended Telemetry", intel_vendor_ext_evt },
{ }
};
static const uint8_t intel_vendor_prefix[] = {0x87, 0x80};
#define INTEL_VENDOR_PREFIX_SIZE sizeof(intel_vendor_prefix)
/*
@@ -1883,17 +1883,17 @@ static const uint8_t intel_vendor_prefix[] = {0x87, 0x80};
* When <subopcode> == 0x03, it is a telemetry event; and
* <data> is a number of tlv data.
*/
struct vendor_prefix_evt {
uint8_t prefix_data[INTEL_VENDOR_PREFIX_SIZE];
uint8_t subopcode;
};
-static const struct vendor_evt *intel_vendor_prefix_evt(const void *data,
+static const struct evt_vendor *intel_vendor_prefix_evt(const void *data,
int *consumed_size)
{
unsigned int i;
const struct vendor_prefix_evt *vnd = data;
char prefix_string[INTEL_VENDOR_PREFIX_SIZE * 2 + 1] = { 0 };
/* Check if the vendor prefix matches. */
for (i = 0; i < INTEL_VENDOR_PREFIX_SIZE; i++) {
@@ -1914,29 +1914,29 @@ static const struct vendor_evt *intel_vendor_prefix_evt(const void *data,
*consumed_size = sizeof(struct vendor_prefix_evt);
return &vendor_prefix_evt_table[i];
}
}
return NULL;
}
-const struct vendor_evt *intel_vendor_evt(const void *data, int *consumed_size)
+const struct evt_vendor *intel_evt_vendor(const void *data, int *consumed_size)
{
uint8_t evt = *((const uint8_t *) data);
int i;
/*
* Handle the vendor event without a vendor prefix.
* 0xff <length> <evt> <data>
- * This loop checks whether the <evt> exists in the vendor_evt_table.
+ * This loop checks whether the <evt> exists in the evt_vendor_table.
*/
- for (i = 0; vendor_evt_table[i].str; i++) {
- if (vendor_evt_table[i].evt == evt)
- return &vendor_evt_table[i];
+ for (i = 0; evt_vendor_table[i].str; i++) {
+ if (evt_vendor_table[i].evt == evt)
+ return &evt_vendor_table[i];
}
/*
* It is not a regular event. Check whether it is a vendor extended
* event that comes with a vendor prefix followed by a subopcode.
*/
return intel_vendor_prefix_evt(data, consumed_size);
}
diff --git a/monitor/intel.h b/monitor/intel.h
index bfb04540c058..e218745a8712 100644
--- a/monitor/intel.h
+++ b/monitor/intel.h
@@ -7,12 +7,12 @@
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
*/
#include <stdint.h>
struct vendor_ocf;
-struct vendor_evt;
+struct evt_vendor;
const struct vendor_ocf *intel_vendor_ocf(uint16_t ocf);
-const struct vendor_evt *intel_vendor_evt(const void *data, int *consumed_size);
+const struct evt_vendor *intel_evt_vendor(const void *data, int *consumed_size);
diff --git a/monitor/msft.c b/monitor/msft.c
index d41f10d68a96..1fd13cf88ea0 100644
--- a/monitor/msft.c
+++ b/monitor/msft.c
@@ -364,23 +364,23 @@ static void msft_evt(struct timeval *tv, uint16_t index,
" (0x%2.2x)", code);
if (code_func)
code_func(data, size);
else
packet_hexdump(data + 1, size - 1);
}
-static const struct vendor_evt vendor_evt_entry = {
+static const struct evt_vendor evt_vendor_entry = {
0x00, "Extension", msft_evt, 1, false
};
-const struct vendor_evt *msft_vendor_evt(void)
+const struct evt_vendor *msft_evt_vendor(void)
{
- return &vendor_evt_entry;
+ return &evt_vendor_entry;
}
bool msft_event_code_valid(uint8_t code)
{
int i;
for (i = 0; evt_table[i].str; i++) {
if (evt_table[i].code == code)
diff --git a/monitor/msft.h b/monitor/msft.h
index ff6c28011018..8ecc925add80 100644
--- a/monitor/msft.h
+++ b/monitor/msft.h
@@ -178,13 +178,13 @@ struct msft_evt_monitor_device {
uint8_t subevt;
uint8_t addr_type;
uint8_t addr[6];
uint8_t handle;
uint8_t state;
} __attribute__((packed));
struct vendor_ocf;
-struct vendor_evt;
+struct evt_vendor;
const struct vendor_ocf *msft_vendor_ocf(void);
-const struct vendor_evt *msft_vendor_evt(void);
+const struct evt_vendor *msft_evt_vendor(void);
bool msft_event_code_valid(uint8_t code);
diff --git a/monitor/packet.c b/monitor/packet.c
index 0d3b23cc3fb7..08051f434ba2 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -11131,46 +11131,46 @@ static const struct vendor_ocf *current_vendor_ocf(uint16_t ocf)
return intel_vendor_ocf(ocf);
case COMPANY_ID_BROADCOM:
return broadcom_vendor_ocf(ocf);
}
return NULL;
}
-static const struct vendor_evt *current_vendor_evt(const void *data,
+static const struct evt_vendor *current_evt_vendor(const void *data,
uint8_t size, int *consumed_size)
{
uint16_t manufacturer;
uint8_t evt = *((const uint8_t *) data);
if (msft_event_prefix_match(data, size)) {
*consumed_size = index_list[index_current].msft_evt_len;
- return msft_vendor_evt();
+ return msft_evt_vendor();
}
/* A regular vendor event consumes 1 byte. */
*consumed_size = 1;
if (index_current < MAX_INDEX)
manufacturer = index_list[index_current].manufacturer;
else
manufacturer = fallback_manufacturer;
switch (manufacturer) {
case COMPANY_ID_INTEL:
- return intel_vendor_evt(data, consumed_size);
+ return intel_evt_vendor(data, consumed_size);
case COMPANY_ID_BROADCOM:
- return broadcom_vendor_evt(evt);
+ return broadcom_evt_vendor(evt);
}
return NULL;
}
-static const char *current_vendor_evt_str(const void *data, uint8_t size)
+static const char *current_evt_vendor_str(const void *data, uint8_t size)
{
uint16_t manufacturer;
if (msft_event_prefix_match(data, size))
return "Microsoft";
if (index_current < MAX_INDEX)
manufacturer = index_list[index_current].manufacturer;
@@ -13791,27 +13791,27 @@ static void le_meta_event_evt(struct timeval *tv, uint16_t index,
subevent_data = &le_meta_event_table[i];
break;
}
}
print_subevent(tv, index, subevent_data, data + 1, size - 1);
}
-static void vendor_evt(struct timeval *tv, uint16_t index,
+static void evt_vendor(struct timeval *tv, uint16_t index,
const void *data, uint8_t size)
{
struct subevent_data vendor_data;
char vendor_str[150];
int consumed_size;
- const struct vendor_evt *vnd = current_vendor_evt(data, size,
+ const struct evt_vendor *vnd = current_evt_vendor(data, size,
&consumed_size);
if (vnd) {
- const char *str = current_vendor_evt_str(data, size);
+ const char *str = current_evt_vendor_str(data, size);
if (str) {
snprintf(vendor_str, sizeof(vendor_str),
"%s %s", str, vnd->str);
vendor_data.str = vendor_str;
} else {
vendor_data.str = vnd->str;
}
@@ -13826,17 +13826,17 @@ static void vendor_evt(struct timeval *tv, uint16_t index,
} else {
uint16_t manufacturer;
if (index_current < MAX_INDEX)
manufacturer = index_list[index_current].manufacturer;
else
manufacturer = fallback_manufacturer;
- vendor_event(manufacturer, data, size);
+ event_vendor(manufacturer, data, size);
}
}
struct event_data {
uint8_t event;
const char *str;
void (*func) (struct timeval *tv, uint16_t index, const void *data,
uint8_t size);
@@ -13993,17 +13993,17 @@ static const struct event_data event_table[] = {
{ 0x56, "Inquiry Response Notification",
inquiry_response_notify_evt, 4, true },
{ 0x57, "Authenticated Payload Timeout Expired",
auth_payload_timeout_expired_evt, 2, true },
{ 0x58, "SAM Status Change" },
{ 0x59, "Encryption Change v2",
encrypt_change_evt_v2, 5, true },
{ 0xfe, "Testing" },
- { 0xff, "Vendor", vendor_evt, 0, false },
+ { 0xff, "Vendor", evt_vendor, 0, false },
{ }
};
void packet_new_index(struct timeval *tv, uint16_t index, const char *label,
uint8_t type, uint8_t bus, const char *name)
{
char details[48];
diff --git a/monitor/vendor.c b/monitor/vendor.c
index ecbfcf2eb817..9942e3d735d8 100644
--- a/monitor/vendor.c
+++ b/monitor/vendor.c
@@ -12,12 +12,12 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define _GNU_SOURCE
#include "packet.h"
#include "vendor.h"
-void vendor_event(uint16_t manufacturer, const void *data, uint8_t size)
+void event_vendor(uint16_t manufacturer, const void *data, uint8_t size)
{
packet_hexdump(data, size);
}
diff --git a/monitor/vendor.h b/monitor/vendor.h
index 996ed44cb18e..1ce42a645096 100644
--- a/monitor/vendor.h
+++ b/monitor/vendor.h
@@ -17,18 +17,18 @@ struct vendor_ocf {
void (*cmd_func) (uint16_t index, const void *data, uint8_t size);
uint8_t cmd_size;
bool cmd_fixed;
void (*rsp_func) (uint16_t index, const void *data, uint8_t size);
uint8_t rsp_size;
bool rsp_fixed;
};
-struct vendor_evt {
+struct evt_vendor {
uint8_t evt;
const char *str;
void (*evt_func) (struct timeval *tv, uint16_t index,
const void *data, uint8_t size);
uint8_t evt_size;
bool evt_fixed;
};
-void vendor_event(uint16_t manufacturer, const void *data, uint8_t size);
+void event_vendor(uint16_t manufacturer, const void *data, uint8_t size);
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH BlueZ v3 3/4] doc/hci-protocol: Add BT_RECV_VENDOR_PKT socket option for HCI_CHANNEL_USER
2026-09-03 14:47 [PATCH BlueZ v3 0/4] BlueZ: Support vendor packets Zijun Hu
2026-09-03 14:47 ` [PATCH BlueZ v3 1/4] doc/hci-protocol: Fix missing & on mtu argument in BT_RCVMTU example Zijun Hu
2026-09-03 14:47 ` [PATCH BlueZ v3 2/4] monitor: s/vendor_(evt|event)/\1_vendor/ Zijun Hu
@ 2026-09-03 14:47 ` Zijun Hu
2026-09-03 15:16 ` Luiz Augusto von Dentz
2026-09-03 14:47 ` [PATCH BlueZ v3 4/4] monitor: Support vendor packets Zijun Hu
3 siblings, 1 reply; 9+ messages in thread
From: Zijun Hu @ 2026-09-03 14:47 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz
Cc: Zijun Hu, linux-bluetooth, linux-kernel
BT_RECV_VENDOR_PKT controls receiving vendor packets over HCI_CHANNEL_USER.
Disabled by default to avoid regressions for existing applications.
---
doc/hci-protocol.rst | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/doc/hci-protocol.rst b/doc/hci-protocol.rst
index db10b35df736..53734a0037a9 100644
--- a/doc/hci-protocol.rst
+++ b/doc/hci-protocol.rst
@@ -131,16 +131,34 @@ Example:
uint16_t mtu;
socklen_t len;
int err;
len = sizeof(mtu);
err = getsockopt(sock, SOL_BLUETOOTH, BT_RCVMTU, &mtu, &len);
+BT_RECV_VENDOR_PKT (since Linux 7.3)
+------------------------------------
+
+Control receiving vendor packets, requires hci_channel to be set to
+HCI_CHANNEL_USER.
+
+Default is disabled.
+
+Example:
+
+.. code-block::
+
+ uint32_t enable = 1;
+ int err;
+
+ err = setsockopt(fd, SOL_BLUETOOTH, BT_RECV_VENDOR_PKT, &enable,
+ sizeof(enable));
+
RESOURCES
=========
http://www.bluez.org
REPORTING BUGS
==============
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH BlueZ v3 3/4] doc/hci-protocol: Add BT_RECV_VENDOR_PKT socket option for HCI_CHANNEL_USER
2026-09-03 14:47 ` [PATCH BlueZ v3 3/4] doc/hci-protocol: Add BT_RECV_VENDOR_PKT socket option for HCI_CHANNEL_USER Zijun Hu
@ 2026-09-03 15:16 ` Luiz Augusto von Dentz
2026-09-04 14:12 ` Zijun Hu
0 siblings, 1 reply; 9+ messages in thread
From: Luiz Augusto von Dentz @ 2026-09-03 15:16 UTC (permalink / raw)
To: Zijun Hu; +Cc: Marcel Holtmann, Zijun Hu, linux-bluetooth, linux-kernel
Hi Zijun,
On Thu, Sep 3, 2026 at 10:47 AM Zijun Hu <zijun.hu@oss.qualcomm.com> wrote:
>
> BT_RECV_VENDOR_PKT controls receiving vendor packets over HCI_CHANNEL_USER.
>
> Disabled by default to avoid regressions for existing applications.
> ---
> doc/hci-protocol.rst | 18 ++++++++++++++++++
> 1 file changed, 18 insertions(+)
>
> diff --git a/doc/hci-protocol.rst b/doc/hci-protocol.rst
> index db10b35df736..53734a0037a9 100644
> --- a/doc/hci-protocol.rst
> +++ b/doc/hci-protocol.rst
> @@ -131,16 +131,34 @@ Example:
>
> uint16_t mtu;
> socklen_t len;
> int err;
>
> len = sizeof(mtu);
> err = getsockopt(sock, SOL_BLUETOOTH, BT_RCVMTU, &mtu, &len);
>
> +BT_RECV_VENDOR_PKT (since Linux 7.3)
> +------------------------------------
> +
> +Control receiving vendor packets, requires hci_channel to be set to
> +HCI_CHANNEL_USER.
> +
> +Default is disabled.
> +
> +Example:
> +
> +.. code-block::
> +
> + uint32_t enable = 1;
> + int err;
> +
> + err = setsockopt(fd, SOL_BLUETOOTH, BT_RECV_VENDOR_PKT, &enable,
> + sizeof(enable));
I don't think we ever applied this socket option to the kernel,
though. Anyway, I think we are better off adding another channel,
e.g., HCI_CHANNEL_VENDOR which can then allow packet type rather than
just the known ones.
> RESOURCES
> =========
>
> http://www.bluez.org
>
> REPORTING BUGS
> ==============
>
>
> --
> 2.34.1
>
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH BlueZ v3 3/4] doc/hci-protocol: Add BT_RECV_VENDOR_PKT socket option for HCI_CHANNEL_USER
2026-09-03 15:16 ` Luiz Augusto von Dentz
@ 2026-09-04 14:12 ` Zijun Hu
2026-09-04 14:31 ` Luiz Augusto von Dentz
0 siblings, 1 reply; 9+ messages in thread
From: Zijun Hu @ 2026-09-04 14:12 UTC (permalink / raw)
To: Luiz Augusto von Dentz
Cc: Marcel Holtmann, Zijun Hu, linux-bluetooth, linux-kernel
On 9/3/2026 11:16 PM, Luiz Augusto von Dentz wrote:
>> +BT_RECV_VENDOR_PKT (since Linux 7.3)
>> +------------------------------------
>> +
>> +Control receiving vendor packets, requires hci_channel to be set to
>> +HCI_CHANNEL_USER.
>> +
>> +Default is disabled.
>> +
>> +Example:
>> +
>> +.. code-block::
>> +
>> + uint32_t enable = 1;
>> + int err;
>> +
>> + err = setsockopt(fd, SOL_BLUETOOTH, BT_RECV_VENDOR_PKT, &enable,
>> + sizeof(enable));
> I don't think we ever applied this socket option to the kernel,
> though. Anyway, I think we are better off adding another channel,
Hi Luiz,
Good catch — that socket option is introduced by the below kernel patch, which is still under review:
https://lore.kernel.org/all/20260830-btusb_qcc2072-v2-2-5c0e0c9dd98b@oss.qualcomm.com
I'll drop this userspace patch in v4 temporarily to avoid confusion.
> e.g., HCI_CHANNEL_VENDOR which can then allow packet type rather than
> just the known ones.
For this new proposal:
1) Is my below understanding correct?
- H/W wire: BT and vendor packets are serialized together.
- Kernel: splits BT and vendor packets to their own channels.
- Userspace: merges both channels on RX, sends to the corresponding channel on TX.
2) How would a HCI_CHANNEL_USER user, e.g. Chromebook, send and receive vendor packets?
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH BlueZ v3 3/4] doc/hci-protocol: Add BT_RECV_VENDOR_PKT socket option for HCI_CHANNEL_USER
2026-09-04 14:12 ` Zijun Hu
@ 2026-09-04 14:31 ` Luiz Augusto von Dentz
0 siblings, 0 replies; 9+ messages in thread
From: Luiz Augusto von Dentz @ 2026-09-04 14:31 UTC (permalink / raw)
To: Zijun Hu; +Cc: Marcel Holtmann, Zijun Hu, linux-bluetooth, linux-kernel
Hi Zijun,
On Fri, Sep 4, 2026 at 10:12 AM Zijun Hu <zijun.hu@oss.qualcomm.com> wrote:
>
> On 9/3/2026 11:16 PM, Luiz Augusto von Dentz wrote:
> >> +BT_RECV_VENDOR_PKT (since Linux 7.3)
> >> +------------------------------------
> >> +
> >> +Control receiving vendor packets, requires hci_channel to be set to
> >> +HCI_CHANNEL_USER.
> >> +
> >> +Default is disabled.
> >> +
> >> +Example:
> >> +
> >> +.. code-block::
> >> +
> >> + uint32_t enable = 1;
> >> + int err;
> >> +
> >> + err = setsockopt(fd, SOL_BLUETOOTH, BT_RECV_VENDOR_PKT, &enable,
> >> + sizeof(enable));
> > I don't think we ever applied this socket option to the kernel,
> > though. Anyway, I think we are better off adding another channel,
>
> Hi Luiz,
>
> Good catch — that socket option is introduced by the below kernel patch, which is still under review:
> https://lore.kernel.org/all/20260830-btusb_qcc2072-v2-2-5c0e0c9dd98b@oss.qualcomm.com
> I'll drop this userspace patch in v4 temporarily to avoid confusion.
>
> > e.g., HCI_CHANNEL_VENDOR which can then allow packet type rather than
> > just the known ones.
>
> For this new proposal:
>
> 1) Is my below understanding correct?
> - H/W wire: BT and vendor packets are serialized together.
> - Kernel: splits BT and vendor packets to their own channels.
> - Userspace: merges both channels on RX, sends to the corresponding channel on TX.
I guess that is up to us to define, HCI_CHANNEL_VENDOR could just
serialize everything, so it supersed HCI_CHANNEL_USER which only took
care of known packet types. That said I don't think it would be an API
break if we decide HCI_CHANNEL_USER carry everything, but since you
are trying to introduce BT_RECV_VENDOR_PKT there maybe a reason not to
enable everything to be send over HCI_CHANNEL_USER.
> 2) How would a HCI_CHANNEL_USER user, e.g. Chromebook, send and receive vendor packets?
Would have to switch to use HCI_CHANNEL_VENDOR, just as it would have
to use BT_RECV_VENDOR_PKT, but then again Id rather do it on
HCI_CHANNEL_USER if we don't consider it an API breakage.
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH BlueZ v3 4/4] monitor: Support vendor packets
2026-09-03 14:47 [PATCH BlueZ v3 0/4] BlueZ: Support vendor packets Zijun Hu
` (2 preceding siblings ...)
2026-09-03 14:47 ` [PATCH BlueZ v3 3/4] doc/hci-protocol: Add BT_RECV_VENDOR_PKT socket option for HCI_CHANNEL_USER Zijun Hu
@ 2026-09-03 14:47 ` Zijun Hu
3 siblings, 0 replies; 9+ messages in thread
From: Zijun Hu @ 2026-09-03 14:47 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz
Cc: Zijun Hu, linux-bluetooth, linux-kernel
Kernel include/net/bluetooth/hci.h defines its packet type as:
#define HCI_VENDOR_PKT 0xff
- Defined by vendor
- Bidirectional (RX and TX)
- kernel <-> userspace: HCI_VENDOR_PKT followed by vendor packet
- kernel <-> monitor: vendor packet has TX opcode (22) or RX
opcode (23)
Support them in tool btmon.
---
doc/btsnoop-protocol.rst | 8 ++++++++
monitor/analyze.c | 23 +++++++++++++++++++++++
monitor/packet.c | 26 ++++++++++++++++++++++++++
monitor/packet.h | 2 ++
src/shared/btsnoop.h | 2 ++
5 files changed, 61 insertions(+)
diff --git a/doc/btsnoop-protocol.rst b/doc/btsnoop-protocol.rst
index a875db63a9dd..ba1eb858f185 100644
--- a/doc/btsnoop-protocol.rst
+++ b/doc/btsnoop-protocol.rst
@@ -111,16 +111,24 @@ values match the definitions in ``src/shared/btsnoop.h``.
* - BTSNOOP_OPCODE_ISO_TX_PKT
- 18
- 0x0012
- Outgoing ISO packet
* - BTSNOOP_OPCODE_ISO_RX_PKT
- 19
- 0x0013
- Incoming ISO packet
+ * - BTSNOOP_OPCODE_VENDOR_TX_PKT
+ - 22
+ - 0x0016
+ - Outgoing vendor packet
+ * - BTSNOOP_OPCODE_VENDOR_RX_PKT
+ - 23
+ - 0x0017
+ - Incoming vendor packet
New Index
---------
Code: 0x0000
Parameters:
diff --git a/monitor/analyze.c b/monitor/analyze.c
index de9c23603a21..e3b2c2fe65f2 100644
--- a/monitor/analyze.c
+++ b/monitor/analyze.c
@@ -39,16 +39,17 @@ struct hci_dev {
struct timeval time_added;
struct timeval time_removed;
unsigned long num_hci;
unsigned long num_cmd;
unsigned long num_evt;
unsigned long num_acl;
unsigned long num_sco;
unsigned long num_iso;
+ unsigned long num_vendor;
unsigned long vendor_diag;
unsigned long system_note;
unsigned long user_log;
unsigned long ctrl_msg;
unsigned long unknown;
uint16_t manufacturer;
struct queue *conn_list;
};
@@ -460,16 +461,17 @@ static void dev_destroy(void *data)
printf("\n");
printf(" %lu commands\n", dev->num_cmd);
printf(" %lu events\n", dev->num_evt);
printf(" %lu ACL packets\n", dev->num_acl);
printf(" %lu SCO packets\n", dev->num_sco);
printf(" %lu ISO packets\n", dev->num_iso);
+ printf(" %lu vendor packets\n", dev->num_vendor);
printf(" %lu vendor diagnostics\n", dev->vendor_diag);
printf(" %lu system notes\n", dev->system_note);
printf(" %lu user logs\n", dev->user_log);
printf(" %lu control messages \n", dev->ctrl_msg);
printf(" %lu unknown opcodes\n", dev->unknown);
queue_destroy(dev->conn_list, conn_destroy);
printf("\n");
@@ -1357,16 +1359,29 @@ static void iso_pkt(struct timeval *tv, uint16_t index, bool out,
if (out) {
conn_pkt_tx(conn, tv, size - sizeof(*hdr), NULL);
} else {
conn_pkt_rx(conn, tv, size - sizeof(*hdr), NULL);
}
}
+static void vendor_pkt(struct timeval *tv, uint16_t index, bool out,
+ const void *data, uint16_t size)
+{
+ struct hci_dev *dev;
+
+ dev = dev_lookup(index);
+ if (!dev)
+ return;
+
+ dev->num_hci++;
+ dev->num_vendor++;
+}
+
static void unknown_opcode(struct timeval *tv, uint16_t index,
const void *data, uint16_t size)
{
struct hci_dev *dev;
dev = dev_lookup(index);
if (!dev)
return;
@@ -1463,16 +1478,24 @@ void analyze_trace(const char *path)
case BTSNOOP_OPCODE_ISO_TX_PKT:
num_frames++;
iso_pkt(&tv, index, true, buf, pktlen);
break;
case BTSNOOP_OPCODE_ISO_RX_PKT:
num_frames++;
iso_pkt(&tv, index, false, buf, pktlen);
break;
+ case BTSNOOP_OPCODE_VENDOR_TX_PKT:
+ num_frames++;
+ vendor_pkt(&tv, index, true, buf, pktlen);
+ break;
+ case BTSNOOP_OPCODE_VENDOR_RX_PKT:
+ num_frames++;
+ vendor_pkt(&tv, index, false, buf, pktlen);
+ break;
default:
unknown_opcode(&tv, index, buf, pktlen);
break;
}
num_packets++;
}
diff --git a/monitor/packet.c b/monitor/packet.c
index 08051f434ba2..1b1e8c3ecdab 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -67,16 +67,17 @@
#define COLOR_HCI_COMMAND COLOR_BLUE
#define COLOR_HCI_COMMAND_UNKNOWN COLOR_WHITE_BG
#define COLOR_HCI_EVENT COLOR_MAGENTA
#define COLOR_HCI_EVENT_UNKNOWN COLOR_WHITE_BG
#define COLOR_HCI_ACLDATA COLOR_CYAN
#define COLOR_HCI_SCODATA COLOR_YELLOW
#define COLOR_HCI_ISODATA COLOR_YELLOW
+#define COLOR_HCI_VENDOR COLOR_GREEN
#define COLOR_UNKNOWN_ERROR COLOR_WHITE_BG
#define COLOR_UNKNOWN_FEATURE_BIT COLOR_WHITE_BG
#define COLOR_UNKNOWN_COMMAND_BIT COLOR_WHITE_BG
#define COLOR_UNKNOWN_EVENT_MASK COLOR_WHITE_BG
#define COLOR_UNKNOWN_LE_STATES COLOR_WHITE_BG
#define COLOR_UNKNOWN_SERVICE_CLASS COLOR_WHITE_BG
#define COLOR_UNKNOWN_PKT_TYPE_BIT COLOR_WHITE_BG
@@ -4523,16 +4524,22 @@ void packet_monitor(struct timeval *tv, struct ucred *cred,
packet_hci_scodata(tv, cred, index, true, data, size);
break;
case BTSNOOP_OPCODE_ISO_TX_PKT:
packet_hci_isodata(tv, cred, index, false, data, size);
break;
case BTSNOOP_OPCODE_ISO_RX_PKT:
packet_hci_isodata(tv, cred, index, true, data, size);
break;
+ case BTSNOOP_OPCODE_VENDOR_TX_PKT:
+ packet_hci_vendor(tv, cred, index, false, data, size);
+ break;
+ case BTSNOOP_OPCODE_VENDOR_RX_PKT:
+ packet_hci_vendor(tv, cred, index, true, data, size);
+ break;
case BTSNOOP_OPCODE_OPEN_INDEX:
if (index < MAX_INDEX)
addr2str(index_list[index].bdaddr, str);
else
sprintf(str, "00:00:00:00:00:00");
packet_open_index(tv, index, str);
break;
@@ -14650,16 +14657,35 @@ malformed:
print_packet(tv, cred, '*', index, NULL, COLOR_ERROR,
"Malformed ISO Data RX packet", NULL, NULL);
else
print_packet(tv, cred, '*', index, NULL, COLOR_ERROR,
"Malformed ISO Data TX packet", NULL, NULL);
packet_hexdump(data, size);
}
+void packet_hci_vendor(struct timeval *tv, struct ucred *cred, uint16_t index,
+ bool in, const void *data, uint16_t size)
+{
+ char extra_str[16];
+
+ if (index >= MAX_INDEX) {
+ print_field("Invalid index (%d).", index);
+ return;
+ }
+
+ index_list[index].frame++;
+
+ sprintf(extra_str, "(len %d)", size);
+ print_packet(tv, cred, in ? '>' : '<', index, NULL, COLOR_HCI_VENDOR,
+ "HCI Vendor", NULL, extra_str);
+
+ packet_hexdump(data, size);
+}
+
void packet_ctrl_open(struct timeval *tv, struct ucred *cred, uint16_t index,
const void *data, uint16_t size)
{
uint32_t cookie;
uint16_t format;
char channel[11];
if (size < 6) {
diff --git a/monitor/packet.h b/monitor/packet.h
index 73a86f64b242..8c519eca61c1 100644
--- a/monitor/packet.h
+++ b/monitor/packet.h
@@ -130,16 +130,18 @@ void packet_hci_command(struct timeval *tv, struct ucred *cred, uint16_t index,
void packet_hci_event(struct timeval *tv, struct ucred *cred, uint16_t index,
const void *data, uint16_t size);
void packet_hci_acldata(struct timeval *tv, struct ucred *cred, uint16_t index,
bool in, const void *data, uint16_t size);
void packet_hci_scodata(struct timeval *tv, struct ucred *cred, uint16_t index,
bool in, const void *data, uint16_t size);
void packet_hci_isodata(struct timeval *tv, struct ucred *cred, uint16_t index,
bool in, const void *data, uint16_t size);
+void packet_hci_vendor(struct timeval *tv, struct ucred *cred, uint16_t index,
+ bool in, const void *data, uint16_t size);
void packet_ctrl_open(struct timeval *tv, struct ucred *cred, uint16_t index,
const void *data, uint16_t size);
void packet_ctrl_close(struct timeval *tv, struct ucred *cred, uint16_t index,
const void *data, uint16_t size);
void packet_ctrl_command(struct timeval *tv, struct ucred *cred, uint16_t index,
const void *data, uint16_t size);
void packet_ctrl_event(struct timeval *tv, struct ucred *cred, uint16_t index,
diff --git a/src/shared/btsnoop.h b/src/shared/btsnoop.h
index c24755d56729..efa87a8f2971 100644
--- a/src/shared/btsnoop.h
+++ b/src/shared/btsnoop.h
@@ -37,16 +37,18 @@
#define BTSNOOP_OPCODE_SYSTEM_NOTE 12
#define BTSNOOP_OPCODE_USER_LOGGING 13
#define BTSNOOP_OPCODE_CTRL_OPEN 14
#define BTSNOOP_OPCODE_CTRL_CLOSE 15
#define BTSNOOP_OPCODE_CTRL_COMMAND 16
#define BTSNOOP_OPCODE_CTRL_EVENT 17
#define BTSNOOP_OPCODE_ISO_TX_PKT 18
#define BTSNOOP_OPCODE_ISO_RX_PKT 19
+#define BTSNOOP_OPCODE_VENDOR_TX_PKT 22
+#define BTSNOOP_OPCODE_VENDOR_RX_PKT 23
#define BTSNOOP_MAX_PACKET_SIZE (1486 + 4)
#define BTSNOOP_TYPE_PRIMARY 0
#define BTSNOOP_TYPE_AMP 1
#define BTSNOOP_BUS_VIRTUAL 0
#define BTSNOOP_BUS_USB 1
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread