From 3134a1c89d630fe0d9f1fd749066085fe59273c0 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 7 Oct 2025 14:50:27 +0200 Subject: [PATCH 1/2] bluetooth: hci: Add data fields to event and meta event structs Those flexible arrays allow for easy access to event data. Signed-off-by: Szymon Janc --- include/zephyr/bluetooth/hci_types.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/zephyr/bluetooth/hci_types.h b/include/zephyr/bluetooth/hci_types.h index cd6c716c1cbe1..92f51b69a4551 100644 --- a/include/zephyr/bluetooth/hci_types.h +++ b/include/zephyr/bluetooth/hci_types.h @@ -60,6 +60,7 @@ struct bt_hci_sco_hdr { struct bt_hci_evt_hdr { uint8_t evt; uint8_t len; + uint8_t data[]; } __packed; #define BT_HCI_EVT_HDR_SIZE 2 @@ -3178,6 +3179,7 @@ struct bt_hci_evt_user_passkey_notify { #define BT_HCI_EVT_LE_META_EVENT 0x3e struct bt_hci_evt_le_meta_event { uint8_t subevent; + uint8_t data[]; } __packed; #define BT_HCI_EVT_AUTH_PAYLOAD_TIMEOUT_EXP 0x57 From 4e2b5ee74c7160463042c5a211c8e78dc08d63e0 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 7 Oct 2025 08:34:18 +0200 Subject: [PATCH 2/2] bluetooth: hci: userchan: Improve RX allocation handling This makes userchan transport behavior similar to other HCI transports (eg IPC). Improved logging gives clear overview of what RX events are discarded helping for configuration tuning. Signed-off-by: Szymon Janc --- drivers/bluetooth/hci/userchan.c | 76 +++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 20 deletions(-) diff --git a/drivers/bluetooth/hci/userchan.c b/drivers/bluetooth/hci/userchan.c index 92dabd389a284..9798a71ab6af0 100644 --- a/drivers/bluetooth/hci/userchan.c +++ b/drivers/bluetooth/hci/userchan.c @@ -58,26 +58,24 @@ static unsigned int port; static char socket_path[UNIX_ADDR_BUFF_SIZE]; static bool arg_found; -static bool is_hci_event_discardable(const uint8_t *evt_data) +static bool is_hci_event_discardable(const struct bt_hci_evt_hdr *evt) { - uint8_t evt_type = evt_data[0]; - - switch (evt_type) { + switch (evt->evt) { #if defined(CONFIG_BT_CLASSIC) case BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI: case BT_HCI_EVT_EXTENDED_INQUIRY_RESULT: return true; #endif case BT_HCI_EVT_LE_META_EVENT: { - uint8_t subevt_type = evt_data[sizeof(struct bt_hci_evt_hdr)]; + const struct bt_hci_evt_le_meta_event *meta_evt = (const void *)evt->data; - switch (subevt_type) { + switch (meta_evt->subevent) { case BT_HCI_EVT_LE_ADVERTISING_REPORT: return true; #if defined(CONFIG_BT_EXT_ADV) case BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT: { const struct bt_hci_evt_le_ext_advertising_report *ext_adv = - (void *)&evt_data[3]; + (const void *)meta_evt->data; return (ext_adv->num_reports == 1) && ((ext_adv->adv_info[0].evt_type & BT_HCI_LE_ADV_EVT_TYPE_LEGACY) != @@ -93,28 +91,67 @@ static bool is_hci_event_discardable(const uint8_t *evt_data) } } +static struct net_buf *get_rx_evt(const uint8_t *data) +{ + const struct bt_hci_evt_hdr *evt = (const void *)data; + const bool discardable = is_hci_event_discardable(evt); + const k_timeout_t timeout = discardable ? K_NO_WAIT : K_SECONDS(1); + struct net_buf *buf; + + do { + buf = bt_buf_get_evt(evt->evt, discardable, timeout); + if (buf == NULL) { + if (discardable) { + LOG_DBG_RATELIMIT("Discardable buffer pool full, ignoring event"); + return buf; + } + LOG_WRN("Couldn't allocate a buffer after waiting 1 second."); + } + } while (!buf); + + return buf; +} + +static struct net_buf *get_rx_acl(const uint8_t *data) +{ + struct net_buf *buf; + + buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT); + if (buf == NULL) { + LOG_ERR("No available ACL buffers!"); + } + + return buf; +} + +static struct net_buf *get_rx_iso(const uint8_t *data) +{ + struct net_buf *buf; + + buf = bt_buf_get_rx(BT_BUF_ISO_IN, K_NO_WAIT); + if (buf == NULL) { + LOG_ERR_RATELIMIT("No available ISO buffers!"); + } + + return buf; +} + static struct net_buf *get_rx(const uint8_t *buf) { - bool discardable = false; - k_timeout_t timeout = K_FOREVER; + uint8_t hci_h4_type = buf[0]; - switch (buf[0]) { + switch (hci_h4_type) { case BT_HCI_H4_EVT: - if (is_hci_event_discardable(buf)) { - discardable = true; - timeout = K_NO_WAIT; - } - - return bt_buf_get_evt(buf[1], discardable, timeout); + return get_rx_evt(&buf[1]); case BT_HCI_H4_ACL: - return bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER); + return get_rx_acl(&buf[1]); case BT_HCI_H4_ISO: if (IS_ENABLED(CONFIG_BT_ISO)) { - return bt_buf_get_rx(BT_BUF_ISO_IN, K_FOREVER); + return get_rx_iso(&buf[1]); } __fallthrough; default: - LOG_ERR("Unknown packet type: %u", buf[0]); + LOG_ERR("Unknown packet type: %u", hci_h4_type); } return NULL; @@ -281,7 +318,6 @@ static void rx_thread(void *p1, void *p2, void *p3) frame_start += decoded_len; if (!buf) { - LOG_DBG("Discard adv report due to insufficient buf"); continue; }