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;

Reply via email to