This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 038e17eb46f846d6d80d8705b6a8708d4baeebe4 Author: Lingao Meng <[email protected]> AuthorDate: Thu Oct 22 11:49:33 2026 +0800 wireless/bluetooth: Check Controller to Host flow control support Host initialization unconditionally sends Host Buffer Size and Set Controller To Host Flow Control. Controllers without these optional commands reject initialization, even though advertising and scanning do not require Controller to Host flow control. The receive buffer release path also reports completed ACL packets when flow control is disabled. Read Local Supported Commands before configuring flow control and require all three related commands. Warn and continue initialization when they are unavailable, and skip the optional commands entirely when flow control is disabled by configuration. Wait for Host Buffer Size to complete before enabling flow control. Track successful activation, clear it on initialization and Reset, and send Host Number Of Completed Packets only while flow control is active. Found by running BTSak advertising and scanning against BSWorld's Python Controller, which does not advertise Controller to Host flow control. The firmware compiled successfully but could not initialize the Host. Testing: Host: Ubuntu 22.04 x86_64 Board/config: sim:bthcisock with SIM_BSIM_TIME=y Built with CONFIG_BLUETOOTH_CNTRL_HOST_FLOW_DISABLE both enabled and disabled. BTSak advertising/scanning passed against Python Controllers. Eight protocol-injection cases passed against the real NuttX binaries: supported/unsupported capabilities with both flow-control settings, a truncated capability response, rejected Host Buffer Size, rejected flow-control activation, and disabled flow control skipping a rejected buffer command. Checked command ordering and completed-packet reporting by injecting an ACL packet into the receive buffer release path. git diff --check and tools/checkpatch.sh -f passed. Assisted-by: OpenAI Codex Signed-off-by: Lingao Meng <[email protected]> --- include/nuttx/wireless/bluetooth/bt_hci.h | 7 +++ wireless/bluetooth/bt_buf.c | 2 +- wireless/bluetooth/bt_hcicore.c | 95 +++++++++++++++++++++---------- wireless/bluetooth/bt_hcicore.h | 1 + 4 files changed, 74 insertions(+), 31 deletions(-) diff --git a/include/nuttx/wireless/bluetooth/bt_hci.h b/include/nuttx/wireless/bluetooth/bt_hci.h index c8d905dbd09..419f387d484 100644 --- a/include/nuttx/wireless/bluetooth/bt_hci.h +++ b/include/nuttx/wireless/bluetooth/bt_hci.h @@ -131,6 +131,7 @@ #define BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS BT_OP(BT_OGF_BASEBAND, 0x0035) #define BT_HCI_OP_LE_WRITE_LE_HOST_SUPP BT_OP(BT_OGF_BASEBAND, 0x006d) #define BT_HCI_OP_READ_LOCAL_VERSION_INFO BT_OP(BT_OGF_INFO, 0x0001) +#define BT_HCI_OP_READ_LOCAL_COMMANDS BT_OP(BT_OGF_INFO, 0x0002) #define BT_HCI_OP_READ_LOCAL_FEATURES BT_OP(BT_OGF_INFO, 0x0003) #define BT_HCI_OP_READ_BUFFER_SIZE BT_OP(BT_OGF_INFO, 0x0005) #define BT_HCI_OP_READ_BD_ADDR BT_OP(BT_OGF_INFO, 0x0009) @@ -365,6 +366,12 @@ begin_packed_struct struct bt_hci_rp_read_local_version_info_s uint16_t lmp_subversion; } end_packed_struct; +begin_packed_struct struct bt_hci_rp_read_local_commands_s +{ + uint8_t status; + uint8_t commands[64]; +} end_packed_struct; + begin_packed_struct struct bt_hci_rp_read_local_features_s { uint8_t status; diff --git a/wireless/bluetooth/bt_buf.c b/wireless/bluetooth/bt_buf.c index d1edde64b57..f5d70525733 100644 --- a/wireless/bluetooth/bt_buf.c +++ b/wireless/bluetooth/bt_buf.c @@ -463,7 +463,7 @@ void bt_buf_release(FAR struct bt_buf_s *buf) wlinfo("Buffer freed: %p\n", buf); #ifdef CONFIG_WIRELESS_BLUETOOTH_HOST - if (type == BT_ACL_IN) + if (type == BT_ACL_IN && g_btdev.flow_control_enable) { FAR struct bt_hci_cp_host_num_completed_packets_s *cp; FAR struct bt_hci_handle_count_s *hc; diff --git a/wireless/bluetooth/bt_hcicore.c b/wireless/bluetooth/bt_hcicore.c index 7496d2962d5..fb0575fdd73 100644 --- a/wireless/bluetooth/bt_hcicore.c +++ b/wireless/bluetooth/bt_hcicore.c @@ -312,6 +312,7 @@ static void hci_reset_complete(FAR struct bt_buf_s *buf) } g_scan_dev_found_cb = NULL; + g_btdev.flow_control_enable = false; g_btdev.scan_enable = BT_LE_SCAN_DISABLE; g_btdev.scan_filter = BT_LE_SCAN_FILTER_DUP_ENABLE; } @@ -1427,11 +1428,15 @@ static void le_read_buffer_size_complete(FAR struct bt_buf_s *buf) static int hci_initialize(void) { +#ifndef CONFIG_BLUETOOTH_CNTRL_HOST_FLOW_DISABLE + FAR struct bt_hci_rp_read_local_commands_s *commands; FAR struct bt_hci_cp_host_buffer_size_s *hbs; + FAR uint8_t *enable; + bool flow_control; +#endif FAR struct bt_hci_cp_set_event_mask_s *ev; FAR struct bt_buf_s *buf; FAR struct bt_buf_s *rsp; - FAR uint8_t *enable; int ret; /* Send HCI_RESET */ @@ -1561,47 +1566,76 @@ static int hci_initialize(void) return ret; } - buf = bt_hci_cmd_create(BT_HCI_OP_HOST_BUFFER_SIZE, sizeof(*hbs)); - if (buf == NULL) - { - wlerr("ERROR: Failed to create buffer\n"); - return -ENOBUFS; - } - - hbs = bt_buf_extend(buf, sizeof(*hbs)); - memset(hbs, 0, sizeof(*hbs)); - hbs->acl_mtu = BT_HOST2LE16(BLUETOOTH_MAX_FRAMELEN - - sizeof(struct bt_hci_acl_hdr_s) - - g_btdev.btdev->head_reserve); - hbs->acl_pkts = BT_HOST2LE16(CONFIG_BLUETOOTH_BUFFER_PREALLOC); +#ifndef CONFIG_BLUETOOTH_CNTRL_HOST_FLOW_DISABLE + /* Supported Commands octet 10, bits 5..7 describe Set Controller To Host + * Flow Control, Host Buffer Size and Host Number Of Completed Packets. + */ - ret = bt_hci_cmd_send(BT_HCI_OP_HOST_BUFFER_SIZE, buf); + ret = bt_hci_cmd_send_sync(BT_HCI_OP_READ_LOCAL_COMMANDS, NULL, &rsp); if (ret < 0) { - wlerr("ERROR: bt_hci_cmd_send failed: %d\n", ret); return ret; } - buf = bt_hci_cmd_create(BT_HCI_OP_SET_CTL_TO_HOST_FLOW, 1); - if (buf == NULL) + if (rsp->len < sizeof(*commands)) { - wlerr("ERROR: Failed to create buffer\n"); - return -ENOBUFS; + bt_buf_release(rsp); + return -EINVAL; } - enable = bt_buf_extend(buf, sizeof(*enable)); -#ifdef CONFIG_BLUETOOTH_CNTRL_HOST_FLOW_DISABLE - *enable = 0; -#else - *enable = 1; -#endif + commands = (FAR void *)rsp->data; + flow_control = (commands->commands[10] & 0xe0) == 0xe0; + bt_buf_release(rsp); - ret = bt_hci_cmd_send_sync(BT_HCI_OP_SET_CTL_TO_HOST_FLOW, buf, NULL); - if (ret < 0) + if (flow_control) { - wlerr("ERROR: bt_hci_cmd_send_sync failed: %d\n", ret); - return ret; + buf = bt_hci_cmd_create(BT_HCI_OP_HOST_BUFFER_SIZE, sizeof(*hbs)); + if (buf == NULL) + { + wlerr("ERROR: Failed to create buffer\n"); + return -ENOBUFS; + } + + hbs = bt_buf_extend(buf, sizeof(*hbs)); + memset(hbs, 0, sizeof(*hbs)); + hbs->acl_mtu = BT_HOST2LE16(BLUETOOTH_MAX_FRAMELEN - + sizeof(struct bt_hci_acl_hdr_s) - + g_btdev.btdev->head_reserve); + hbs->acl_pkts = BT_HOST2LE16(CONFIG_BLUETOOTH_BUFFER_PREALLOC); + + ret = bt_hci_cmd_send_sync(BT_HCI_OP_HOST_BUFFER_SIZE, buf, NULL); + if (ret < 0) + { + wlerr("ERROR: bt_hci_cmd_send_sync failed: %d\n", ret); + return ret; + } + + buf = bt_hci_cmd_create(BT_HCI_OP_SET_CTL_TO_HOST_FLOW, 1); + if (buf == NULL) + { + wlerr("ERROR: Failed to create buffer\n"); + return -ENOBUFS; + } + + enable = bt_buf_extend(buf, sizeof(*enable)); + *enable = 1; + + ret = bt_hci_cmd_send_sync(BT_HCI_OP_SET_CTL_TO_HOST_FLOW, buf, NULL); + if (ret < 0) + { + wlerr("ERROR: bt_hci_cmd_send_sync failed: %d\n", ret); + return ret; + } + + /* Report completed packets only after flow control is enabled. */ + + g_btdev.flow_control_enable = true; + } + else + { + wlwarn("WARNING: Controller to Host flow control is not supported\n"); } +#endif if (lmp_bredr_capable(g_btdev)) { @@ -1806,6 +1840,7 @@ int bt_initialize(void) #ifdef CONFIG_WIRELESS_BLUETOOTH_HOST g_callback_list = NULL; g_scan_dev_found_cb = NULL; + g_btdev.flow_control_enable = false; #endif memset(&g_lp_rxlist, 0, sizeof(g_lp_rxlist)); diff --git a/wireless/bluetooth/bt_hcicore.h b/wireless/bluetooth/bt_hcicore.h index 7488a3d0001..60dfb43984c 100644 --- a/wireless/bluetooth/bt_hcicore.h +++ b/wireless/bluetooth/bt_hcicore.h @@ -97,6 +97,7 @@ struct bt_dev_s /* Controller buffer information */ + bool flow_control_enable; uint8_t le_pkts; uint16_t le_mtu; sem_t le_pkts_sem;
