Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bluetooth: Controller: build assert if comand buffer is too small #19869

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions doc/nrf/releases_and_maturity/known_issues.rst
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,16 @@ KRKNWK-14299: NRPA MAC address cannot be set in Zephyr
Bluetooth LE
============

.. rst-class:: v2-9-0-nRF54H20-1 v2-9-0 v2-8-0 v2-7-0 v2-6-2 v2-6-1 v2-6-0

DRGN-24352: Missing disconnection events when HCI Controller to host flow control is enabled
The :zephyr:code-sample:`bluetooth_hci_ipc` sample and :ref:`ipc_radio` application do not support stream flow control and drop bytes.
With the deferred disconnection complete generation added in the |NCS| v2.6.0, there are cases where the :kconfig:option:`CONFIG_BT_HCI_ACL_FLOW_CONTROL` Kconfig option has value ``y``, and the value of :kconfig:option:`CONFIG_BT_BUF_CMD_TX_COUNT` is smaller than (:kconfig:option:`CONFIG_BT_BUF_ACL_RX_COUNT` + 1).
This might result in dropped HCI command packets.
The visible symptom is a missing disconnect event and subsequent failure in connection, if a peripheral device falls out of range or is powered off.

**Workaround:** Make sure that the value of the :kconfig:option:`CONFIG_BT_BUF_ACL_RX_COUNT` Kconfig option is smaller than the one for :kconfig:option:`CONFIG_BT_BUF_CMD_TX_COUNT` in your project.

.. rst-class:: v2-9-0-nRF54H20-rc1 v2-9-0 v2-8-0 v2-7-0 v2-6-2 v2-6-1 v2-6-0
KyraLengfeld marked this conversation as resolved.
Show resolved Hide resolved

NCSDK-31095: Issues with the :kconfig:option:`CONFIG_SEGGER_SYSVIEW` Kconfig option
Expand Down
5 changes: 5 additions & 0 deletions scripts/ci/tags.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,11 @@ ci_tests_subsys_audio_module:
- nrf/subsys/audio/
- nrf/tests/subsys/audio/

ci_tests_subsys_bluetooth_controller:
files:
- nrf/subsys/bluetooth/controller
- nrf/tests/subsys/bluetooth/controller

ci_tests_subsys_mpsl:
files:
- nrf/subsys/mpsl/
Expand Down
1 change: 1 addition & 0 deletions subsys/bluetooth/controller/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ zephyr_library()
zephyr_library_sources(
hci_driver.c
hci_internal.c
hci_internal_wrappers.c
)

zephyr_library_sources_ifdef(
Expand Down
7 changes: 5 additions & 2 deletions subsys/bluetooth/controller/hci_internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
#include <sdc_hci_vs.h>

#include "hci_internal.h"
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
#include "hci_internal_wrappers.h"
#endif
#include "ecdh.h"

#define CMD_COMPLETE_MIN_SIZE (BT_HCI_EVT_HDR_SIZE \
Expand Down Expand Up @@ -956,7 +959,7 @@ static uint8_t controller_and_baseband_cmd_put(uint8_t const * const cmd,
case SDC_HCI_OPCODE_CMD_CB_SET_CONTROLLER_TO_HOST_FLOW_CONTROL:
return sdc_hci_cmd_cb_set_controller_to_host_flow_control((void *)cmd_params);
case SDC_HCI_OPCODE_CMD_CB_HOST_BUFFER_SIZE:
return sdc_hci_cmd_cb_host_buffer_size((void *)cmd_params);
return sdc_hci_cmd_cb_host_buffer_size_wrapper((void *)cmd_params);
case SDC_HCI_OPCODE_CMD_CB_HOST_NUMBER_OF_COMPLETED_PACKETS:
return sdc_hci_cmd_cb_host_number_of_completed_packets((void *)cmd_params);
#endif
Expand Down Expand Up @@ -1928,7 +1931,7 @@ int hci_internal_msg_get(uint8_t *msg_out, sdc_hci_msg_type_t *msg_type_out)
return 0;
}

const int retval = sdc_hci_get(msg_out, msg_type_out);
const int retval = sdc_hci_get(msg_out, (uint8_t *)msg_type_out);

#if defined(CONFIG_BT_CTLR_SDC_PAWR_SYNC)
if (retval == 0 && *msg_type_out == SDC_HCI_MSG_TYPE_EVT
Expand Down
49 changes: 49 additions & 0 deletions subsys/bluetooth/controller/hci_internal_wrappers.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#include "hci_internal_wrappers.h"
#include <zephyr/sys/util.h>
#include <zephyr/bluetooth/buf.h>

#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
/*
* The Host will generate up to acl_pkts number of Host Number of Completed Packets command plus a
* number of normal HCI commands, as such we need to ensure the tx command buffer count is big
* enough to not block incoming ACKs from the host.
*
* When Controller to Host data flow control is supported, ensure that BT_BUF_CMD_TX_COUNT is
* greater than or equal to (BT_BUF_ACL_RX_COUNT + Ncmd), where Ncmd is the supported maximum
* Num_HCI_Command_Packets.
*
* The SDC controller (currently) does not support Num_HCI_Command_Packets > 1, which means Ncmd
* is always 1.
*/
#if defined(CONFIG_BT_CONN) && defined(CONFIG_BT_HCI_HOST)
BUILD_ASSERT(BT_BUF_ACL_RX_COUNT < CONFIG_BT_BUF_CMD_TX_COUNT,
"Too low HCI command buffers compared to ACL Rx buffers, \
reduce CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA or increase CONFIG_BT_BUF_CMD_TX_COUNT.");
#else /* controller-only build */
BUILD_ASSERT(CONFIG_BT_BUF_CMD_TX_COUNT - 1 > 0,
"We need at least two HCI command buffers to avoid deadlocks.");
#endif /* CONFIG_BT_CONN && CONFIG_BT_HCI_HOST */

/* Note: When host and controller are built separately, the RX Buffer Count communicated here from
* the host might be exeeding the controller's TX command buffer count. This may result in the
* controller sending up to host_total_num_acl_data_packets, it cannot receive the acknoledgements
* via its TX command buffers for.
* As we do not propagate the TX command buffer count information to the controller, the simplest
* approach is to align the communicated host RX Buffer Count to it here.
*/
int sdc_hci_cmd_cb_host_buffer_size_wrapper(const sdc_hci_cmd_cb_host_buffer_size_t *cmd_params)
{
sdc_hci_cmd_cb_host_buffer_size_t ctrl_cmd_params =
*(const sdc_hci_cmd_cb_host_buffer_size_t *)cmd_params;
ctrl_cmd_params.host_total_num_acl_data_packets = MIN(
ctrl_cmd_params.host_total_num_acl_data_packets, (CONFIG_BT_BUF_CMD_TX_COUNT - 1));

return sdc_hci_cmd_cb_host_buffer_size((const void *)&ctrl_cmd_params);
}
#endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */
21 changes: 21 additions & 0 deletions subsys/bluetooth/controller/hci_internal_wrappers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

/** @file
* @brief Internal HCI interface Wrappers
*/

#include <stdint.h>
#include <stdbool.h>
#include <sdc_hci_cmd_controller_baseband.h>

#ifndef HCI_INTERNAL_WRAPPERS_H__
#define HCI_INTERNAL_WRAPPERS_H__

int sdc_hci_cmd_cb_host_buffer_size_wrapper(const sdc_hci_cmd_cb_host_buffer_size_t *cmd_params);

#endif
26 changes: 26 additions & 0 deletions tests/subsys/bluetooth/controller/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#
# Copyright (c) 2025 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(hci_cmd_cb_host_buffer_size_test)

# Generate runner for the test
test_runner_generate(src/hci_cmd_cb_host_buffer_size_test.c)

# Add Unit Under Test source files
target_sources(app PRIVATE ${ZEPHYR_NRF_MODULE_DIR}/subsys/bluetooth/controller/hci_internal_wrappers.c)

# Add test source file
target_sources(app PRIVATE src/hci_cmd_cb_host_buffer_size_test.c)

# Create mocks
cmock_handle(${ZEPHYR_NRFXLIB_MODULE_DIR}/softdevice_controller/include/sdc_hci_cmd_controller_baseband.h)

# Include paths
include_directories(${ZEPHYR_HAL_NORDIC_MODULE_DIR}/nrfx)
include_directories(${ZEPHYR_NRF_MODULE_DIR}/subsys/bluetooth/controller)
13 changes: 13 additions & 0 deletions tests/subsys/bluetooth/controller/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#
# Copyright (c) 2025 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#
CONFIG_BT_CENTRAL=y
CONFIG_BT_HCI=y
CONFIG_BT=y

CONFIG_BT_HCI_ACL_FLOW_CONTROL=y
CONFIG_BT_BUF_CMD_TX_COUNT=10

CONFIG_UNITY=y
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
#include <unity.h>
#include <stdbool.h>
#include <stdio.h>
#include <errno.h>
#include <zephyr/sys/util.h>

#include "hci_internal_wrappers.h"
#include "cmock_sdc_hci_cmd_controller_baseband.h"

#define TEST_HOST_ACL_DATA_PCKT_LNGTH 55
#define TEST_HOST_SYNC_DATA_PCKT_LNGTH 55
#define TEST_HOST_NUM_SYNC_DATA_PCKTS 5555

/* The unity_main is not declared in any header file. It is only defined in the generated test
* runner because of ncs' unity configuration. It is therefore declared here to avoid a compiler
* warning.
*/
extern int unity_main(void);

typedef struct {
uint16_t acl_input_pckts;
uint16_t exp_acl_pckts;
} test_vector_t;

static const test_vector_t test_vectors[] = {
{5, 5}, /* Input within range, no adjustment needed */
{15, (CONFIG_BT_BUF_CMD_TX_COUNT - 1)}, /* Input exceeds TX buffer count - 1 limit */
{0xFF, (CONFIG_BT_BUF_CMD_TX_COUNT - 1)}, /* Maximum input value, corner case */
};

void test_sdc_hci_cmd_cb_host_buffer_size_wrapper(void)
{
sdc_hci_cmd_cb_host_buffer_size_t cmd_params;
cmd_params.host_acl_data_packet_length = TEST_HOST_ACL_DATA_PCKT_LNGTH;
cmd_params.host_sync_data_packet_length = TEST_HOST_SYNC_DATA_PCKT_LNGTH;
cmd_params.host_total_num_sync_data_packets = TEST_HOST_NUM_SYNC_DATA_PCKTS;

for (size_t i = 0; i < ARRAY_SIZE(test_vectors); i++) {
const test_vector_t *v = &test_vectors[i];

sdc_hci_cmd_cb_host_buffer_size_t exp_cmd_params = cmd_params;
exp_cmd_params.host_total_num_acl_data_packets = v->exp_acl_pckts;
__cmock_sdc_hci_cmd_cb_host_buffer_size_ExpectAndReturn(&exp_cmd_params, 0);

cmd_params.host_total_num_acl_data_packets = v->acl_input_pckts;
sdc_hci_cmd_cb_host_buffer_size_wrapper(&cmd_params);
}
}

int main(void)
{
(void)unity_main();

return 0;
}
8 changes: 8 additions & 0 deletions tests/subsys/bluetooth/controller/testcase.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
tests:
bluetooth.controller:
platform_allow: native_sim
integration_platforms:
- native_sim
tags:
- unittest
- ci_tests_subsys_bluetooth_controller
2 changes: 1 addition & 1 deletion tests/subsys/bluetooth/enocean/testcase.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ tests:
- ci_build
integration_platforms:
- native_sim
- qemu_cortex_m3
- qemu_cortex_m3K
4 changes: 3 additions & 1 deletion tests/subsys/mpsl/pm/testcase.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
tests:
mpsl.pm:
platform_allow: native_sim
platform_allow:
- native_sim
- native_posix
integration_platforms:
- native_sim
tags:
Expand Down
Loading