diff --git a/doc/releases/migration-guide-4.1.rst b/doc/releases/migration-guide-4.1.rst new file mode 100644 index 00000000000..c033dd9c81c --- /dev/null +++ b/doc/releases/migration-guide-4.1.rst @@ -0,0 +1,125 @@ +:orphan: + +.. _migration_4.1: + +Migration guide to Zephyr v4.1.0 (Working Draft) +################################################ + +This document describes the changes required when migrating your application from Zephyr v4.0.0 to +Zephyr v4.1.0. + +Any other changes (not directly related to migrating applications) can be found in +the :ref:`release notes`. + +.. contents:: + :local: + :depth: 2 + +Build System +************ + +Kernel +****** + +Boards +****** + +Modules +******* + +Mbed TLS +======== + +Trusted Firmware-M +================== + +LVGL +==== + +Device Drivers and Devicetree +***************************** + +Controller Area Network (CAN) +============================= + +Display +======= + +Enhanced Serial Peripheral Interface (eSPI) +=========================================== + +GNSS +==== + +Input +===== + +Interrupt Controller +==================== + +LED Strip +========= + +Sensors +======= + +Serial +====== + +Regulator +========= + +Bluetooth +********* + +Bluetooth HCI +============= + +Bluetooth Mesh +============== + +Bluetooth Audio +=============== + +Bluetooth Classic +================= + +Bluetooth Host +============== + +* :kconfig:option:`CONFIG_BT_BUF_ACL_RX_COUNT` has been deprecated. The number of ACL RX buffers is + now computed internally and is equal to :kconfig:option:`CONFIG_BT_MAX_CONN` + 1. If an application + needs more buffers, it can use the new :kconfig:option:`CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA` to add + additional ones. + + e.g. if :kconfig:option:`CONFIG_BT_MAX_CONN` was ``3`` and + :kconfig:option:`CONFIG_BT_BUF_ACL_RX_COUNT` was ``7`` then + :kconfig:option:`CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA` should be set to ``7 - (3 + 1) = 3``. + + .. warning:: + + The default value of :kconfig:option:`CONFIG_BT_BUF_ACL_RX_COUNT` has been set to 0. + +Bluetooth Crypto +================ + +Networking +********** + +Other Subsystems +**************** + +Flash map +========= + +hawkBit +======= + +MCUmgr +====== + +Modem +===== + +Architectures +************* diff --git a/doc/releases/release-notes-4.1.rst b/doc/releases/release-notes-4.1.rst new file mode 100644 index 00000000000..fb44daad14a --- /dev/null +++ b/doc/releases/release-notes-4.1.rst @@ -0,0 +1,291 @@ +:orphan: + +.. _zephyr_4.1: + +Zephyr 4.1.0 (Working Draft) +############################ + +We are pleased to announce the release of Zephyr version 4.1.0. + +Major enhancements with this release include: + +An overview of the changes required or recommended when migrating your application from Zephyr +v4.0.0 to Zephyr v4.1.0 can be found in the separate :ref:`migration guide`. + +The following sections provide detailed lists of changes by component. + +Security Vulnerability Related +****************************** +The following CVEs are addressed by this release: + +More detailed information can be found in: +https://docs.zephyrproject.org/latest/security/vulnerabilities.html + +API Changes +*********** + +Removed APIs in this release +============================ + +Deprecated in this release +========================== + +Architectures +************* + +* ARC + +* ARM + +* ARM64 + +* RISC-V + +* Xtensa + +Kernel +****** + +Bluetooth +********* + +* Audio + +* Host + + * :kconfig:option:`CONFIG_BT_BUF_ACL_RX_COUNT` has been deprecated and + :kconfig:option:`CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA` has been added. + +* HCI Drivers + +Boards & SoC Support +******************** + +* Added support for these SoC series: + +* Made these changes in other SoC series: + +* Added support for these boards: + +* Made these board changes: + +* Added support for the following shields: + +Build system and Infrastructure +******************************* + +Drivers and Sensors +******************* + +* ADC + +* Battery + +* CAN + +* Charger + +* Clock control + +* Counter + +* DAC + +* Disk + +* Display + +* Ethernet + +* Flash + +* GNSS + +* GPIO + +* Hardware info + +* I2C + +* I2S + +* I3C + +* Input + +* LED + +* LED Strip + +* LoRa + +* Mailbox + +* MDIO + +* MFD + +* Modem + +* MIPI-DBI + +* MSPI + +* Pin control + +* PWM + +* Regulators + +* Reset + +* RTC + +* RTIO + +* SDHC + +* Sensors + +* Serial + +* SPI + +* USB + +* Video + +* Watchdog + +* Wi-Fi + +Networking +********** + +* ARP: + +* CoAP: + +* Connection manager: + +* DHCPv4: + +* DHCPv6: + +* DNS/mDNS/LLMNR: + +* gPTP/PTP: + +* HTTP: + +* IPSP: + +* IPv4: + +* IPv6: + +* LwM2M: + +* Misc: + +* MQTT: + +* Network Interface: + +* OpenThread + +* PPP + +* Shell: + +* Sockets: + +* Syslog: + +* TCP: + +* Websocket: + +* Wi-Fi: + +* zperf: + +USB +*** + +Devicetree +********** + +Kconfig +******* + +Libraries / Subsystems +********************** + +* Debug + +* Demand Paging + +* Formatted output + +* Management + +* Logging + +* Modem modules + +* Power management + +* Crypto + +* CMSIS-NN + +* FPGA + +* Random + +* SD + +* State Machine Framework + +* Storage + +* Task Watchdog + +* POSIX API + +* LoRa/LoRaWAN + +* ZBus + +HALs +**** + +* Nordic + +* STM32 + +* ADI + +* Espressif + +MCUboot +******* + +OSDP +**** + +Trusted Firmware-M +****************** + +LVGL +**** + +Tests and Samples +***************** + +Issue Related Items +******************* + +Known Issues +============ diff --git a/include/zephyr/bluetooth/buf.h b/include/zephyr/bluetooth/buf.h index fe480196f58..dd452342ef7 100644 --- a/include/zephyr/bluetooth/buf.h +++ b/include/zephyr/bluetooth/buf.h @@ -28,22 +28,22 @@ extern "C" { #endif -/** Possible types of buffers passed around the Bluetooth stack */ +/** Possible types of buffers passed around the Bluetooth stack in a form of bitmask. */ enum bt_buf_type { /** HCI command */ - BT_BUF_CMD, + BT_BUF_CMD = BIT(0), /** HCI event */ - BT_BUF_EVT, + BT_BUF_EVT = BIT(1), /** Outgoing ACL data */ - BT_BUF_ACL_OUT, + BT_BUF_ACL_OUT = BIT(2), /** Incoming ACL data */ - BT_BUF_ACL_IN, + BT_BUF_ACL_IN = BIT(3), /** Outgoing ISO data */ - BT_BUF_ISO_OUT, + BT_BUF_ISO_OUT = BIT(4), /** Incoming ISO data */ - BT_BUF_ISO_IN, + BT_BUF_ISO_IN = BIT(5), /** H:4 data */ - BT_BUF_H4, + BT_BUF_H4 = BIT(6), }; /** @brief This is a base type for bt_buf user data. */ @@ -85,13 +85,41 @@ struct bt_buf_data { #define BT_BUF_ISO_RX_COUNT 0 #endif /* CONFIG_BT_ISO */ +/* see Core Spec v6.0 vol.4 part E 7.4.5 */ +#define BT_BUF_ACL_RX_COUNT_MAX 65535 + +#if defined(CONFIG_BT_CONN) && defined(CONFIG_BT_HCI_HOST) + /* The host needs more ACL buffers than maximum ACL links. This is because of + * the way we re-assemble ACL packets into L2CAP PDUs. + * + * We keep around the first buffer (that comes from the driver) to do + * re-assembly into, and if all links are re-assembling, there will be no buffer + * available for the HCI driver to allocate from. + * + * TODO: When CONFIG_BT_BUF_ACL_RX_COUNT is removed, + * remove the MAX and only keep (CONFIG_BT_MAX_CONN + 1) + */ +#define BT_BUF_ACL_RX_COUNT \ + (MAX(CONFIG_BT_BUF_ACL_RX_COUNT, (CONFIG_BT_MAX_CONN + 1)) + \ + CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA) +#else +#define BT_BUF_ACL_RX_COUNT 0 +#endif /* CONFIG_BT_CONN && CONFIG_BT_HCI_HOST */ + +#if defined(CONFIG_BT_BUF_ACL_RX_COUNT) && CONFIG_BT_BUF_ACL_RX_COUNT > 0 +#warning "CONFIG_BT_BUF_ACL_RX_COUNT is deprecated, see Zephyr 4.1 migration guide" +#endif /* CONFIG_BT_BUF_ACL_RX_COUNT && CONFIG_BT_BUF_ACL_RX_COUNT > 0 */ + +BUILD_ASSERT(BT_BUF_ACL_RX_COUNT <= BT_BUF_ACL_RX_COUNT_MAX, + "Maximum number of ACL RX buffer is 65535, reduce CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA"); + /** Data size needed for HCI ACL, HCI ISO or Event RX buffers */ #define BT_BUF_RX_SIZE (MAX(MAX(BT_BUF_ACL_RX_SIZE, BT_BUF_EVT_RX_SIZE), \ BT_BUF_ISO_RX_SIZE)) /** Buffer count needed for HCI ACL, HCI ISO or Event RX buffers */ #define BT_BUF_RX_COUNT (MAX(MAX(CONFIG_BT_BUF_EVT_RX_COUNT, \ - CONFIG_BT_BUF_ACL_RX_COUNT), \ + BT_BUF_ACL_RX_COUNT), \ BT_BUF_ISO_RX_COUNT)) /** Data size needed for HCI Command buffers. */ @@ -110,6 +138,27 @@ struct bt_buf_data { */ struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout); +/** A callback to notify about freed buffer in the incoming data pool. + * + * This callback is called when a buffer of a given type is freed and can be requested through the + * @ref bt_buf_get_rx function. However, this callback is called from the context of the buffer + * freeing operation and must not attempt to allocate a new buffer from the same pool. + * + * @warning When this callback is called, the scheduler is locked and the callee must not perform + * any action that makes the current thread unready. This callback must only be used for very + * short non-blocking operation (e.g. submitting a work item). + * + * @param type_mask A bit mask of buffer types that have been freed. + */ +typedef void (*bt_buf_rx_freed_cb_t)(enum bt_buf_type type_mask); + +/** Set the callback to notify about freed buffer in the incoming data pool. + * + * @param cb Callback to notify about freed buffer in the incoming data pool. If NULL, the callback + * is disabled. + */ +void bt_buf_rx_freed_cb_set(bt_buf_rx_freed_cb_t cb); + /** Allocate a buffer for outgoing data * * This will set the buffer type so bt_buf_set_type() does not need to diff --git a/include/zephyr/bluetooth/l2cap.h b/include/zephyr/bluetooth/l2cap.h index d3a49f9b3a9..d8812693614 100644 --- a/include/zephyr/bluetooth/l2cap.h +++ b/include/zephyr/bluetooth/l2cap.h @@ -350,6 +350,11 @@ struct bt_l2cap_chan_ops { * @kconfig{CONFIG_BT_L2CAP_SEG_RECV} is enabled and seg_recv is * supplied. * + * If the application returns @c -EINPROGRESS, the application takes + * ownership of the reference in @p buf. (I.e. This pointer value can + * simply be given to @ref bt_l2cap_chan_recv_complete without any + * calls @ref net_buf_ref or @ref net_buf_unref.) + * * @return 0 in case of success or negative value in case of error. * @return -EINPROGRESS in case where user has to confirm once the data * has been processed by calling diff --git a/include/zephyr/bluetooth/testing.h b/include/zephyr/bluetooth/testing.h new file mode 100644 index 00000000000..3ac48c7b36e --- /dev/null +++ b/include/zephyr/bluetooth/testing.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @brief Internal testing interfaces for Bluetooth + * @file + * @internal + * + * The interfaces in this file are internal and not stable. + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_TESTING_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_TESTING_H_ + +#include + +/** @brief Hook for `acl_in_pool.destroy` + * + * Weak-function interface. The user can simply define this + * function, and it will automatically become the event + * listener. + * + * @kconfig_dep{CONFIG_BT_TESTING} + */ +void bt_testing_trace_event_acl_pool_destroy(struct net_buf *buf); + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_TESTING_H_ */ diff --git a/samples/bluetooth/central_hr/prj_minimal.conf b/samples/bluetooth/central_hr/prj_minimal.conf index 1dcf300b1ef..28dcf759bec 100644 --- a/samples/bluetooth/central_hr/prj_minimal.conf +++ b/samples/bluetooth/central_hr/prj_minimal.conf @@ -94,7 +94,6 @@ CONFIG_BT_CTLR_PHY_2M=n # Reduce Bluetooth buffers CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT=1 CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=45 -CONFIG_BT_BUF_ACL_RX_COUNT=2 CONFIG_BT_BUF_EVT_RX_COUNT=2 CONFIG_BT_L2CAP_TX_BUF_COUNT=2 diff --git a/samples/bluetooth/central_multilink/prj.conf b/samples/bluetooth/central_multilink/prj.conf index a450460243e..f0ca905b431 100644 --- a/samples/bluetooth/central_multilink/prj.conf +++ b/samples/bluetooth/central_multilink/prj.conf @@ -4,7 +4,6 @@ CONFIG_BT_AUTO_PHY_UPDATE=n CONFIG_BT_PRIVACY=y CONFIG_BT_MAX_CONN=62 -CONFIG_BT_BUF_ACL_RX_COUNT=63 # CONFIG_BT_GATT_CLIENT=y diff --git a/samples/bluetooth/hci_uart_async/prj.conf b/samples/bluetooth/hci_uart_async/prj.conf index e4d17d492be..1de1a46535e 100644 --- a/samples/bluetooth/hci_uart_async/prj.conf +++ b/samples/bluetooth/hci_uart_async/prj.conf @@ -10,7 +10,6 @@ CONFIG_BT_HCI_RAW_H4_ENABLE=y # Controller configuration. Modify these for your application's needs. CONFIG_BT_MAX_CONN=16 -CONFIG_BT_BUF_ACL_RX_COUNT=17 CONFIG_BT_BUF_ACL_RX_SIZE=255 CONFIG_BT_BUF_CMD_TX_SIZE=255 CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=255 diff --git a/samples/bluetooth/mesh/boards/bbc_microbit.conf b/samples/bluetooth/mesh/boards/bbc_microbit.conf index 1655768864b..053053e7818 100644 --- a/samples/bluetooth/mesh/boards/bbc_microbit.conf +++ b/samples/bluetooth/mesh/boards/bbc_microbit.conf @@ -13,7 +13,7 @@ CONFIG_BT_PERIPHERAL=n CONFIG_BT_EXT_ADV=n CONFIG_BT_RX_STACK_SIZE=1100 CONFIG_BT_BUF_EVT_RX_COUNT=3 -CONFIG_BT_BUF_ACL_RX_COUNT=3 +CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT=3 CONFIG_BT_CTLR_ADV_EXT=n diff --git a/samples/bluetooth/peripheral_hr/prj_minimal.conf b/samples/bluetooth/peripheral_hr/prj_minimal.conf index 6446273584a..9986c85e8c3 100644 --- a/samples/bluetooth/peripheral_hr/prj_minimal.conf +++ b/samples/bluetooth/peripheral_hr/prj_minimal.conf @@ -100,7 +100,6 @@ CONFIG_BT_CTLR_PHY_2M=n # Reduce Bluetooth buffers CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT=1 CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=45 -CONFIG_BT_BUF_ACL_RX_COUNT=2 CONFIG_BT_BUF_EVT_RX_COUNT=2 CONFIG_BT_L2CAP_TX_BUF_COUNT=2 diff --git a/samples/bluetooth/peripheral_identity/prj.conf b/samples/bluetooth/peripheral_identity/prj.conf index 783c25f91e6..8bd97851e36 100644 --- a/samples/bluetooth/peripheral_identity/prj.conf +++ b/samples/bluetooth/peripheral_identity/prj.conf @@ -8,7 +8,6 @@ CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n CONFIG_BT_MAX_CONN=62 CONFIG_BT_ID_MAX=62 -CONFIG_BT_BUF_ACL_RX_COUNT=63 # CONFIG_BT_SMP=y # CONFIG_BT_MAX_PAIRED=62 diff --git a/subsys/bluetooth/common/Kconfig b/subsys/bluetooth/common/Kconfig index 8bec5ba90d5..9147612a70c 100644 --- a/subsys/bluetooth/common/Kconfig +++ b/subsys/bluetooth/common/Kconfig @@ -77,10 +77,21 @@ config BT_BUF_ACL_RX_SIZE In a Controller only build this will determine the maximum ACL size that the Controller will send to the Host. +config BT_BUF_ACL_RX_COUNT_EXTRA + int "Number of extra incoming ACL data buffers" + default 0 + range 0 65535 + help + Number of incoming extra ACL data buffers sent from the Controller to + the Host. + + By default, the number of incoming ACL data buffers is equal to + CONFIG_BT_MAX_CONN + 1. + config BT_BUF_ACL_RX_COUNT - int "Number of incoming ACL data buffers" - default 6 - range 2 256 + int "[DEPRECATED] Number of incoming ACL data buffers" + default 0 + range 0 256 help Number or incoming ACL data buffers sent from the Controller to the Host. diff --git a/subsys/bluetooth/common/dummy.c b/subsys/bluetooth/common/dummy.c index 4500f7edb71..53fe9764648 100644 --- a/subsys/bluetooth/common/dummy.c +++ b/subsys/bluetooth/common/dummy.c @@ -60,27 +60,3 @@ BUILD_ASSERT(!IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE), "Immediate logging " "on selected backend(s) not " "supported with the software Link Layer"); #endif - -#if defined(CONFIG_BT_CONN) && defined(CONFIG_BT_HCI_HOST) -/* The host needs more ACL buffers than maximum ACL links. This is because of - * the way we re-assemble ACL packets into L2CAP PDUs. - * - * We keep around the first buffer (that comes from the driver) to do - * re-assembly into, and if all links are re-assembling, there will be no buffer - * available for the HCI driver to allocate from. - * - * Fixing it properly involves a re-design of the HCI driver interface. - */ -#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) -BUILD_ASSERT(CONFIG_BT_BUF_ACL_RX_COUNT > CONFIG_BT_MAX_CONN); - -#else /* !CONFIG_BT_HCI_ACL_FLOW_CONTROL */ - -/* BT_BUF_RX_COUNT is defined in include/zephyr/bluetooth/buf.h */ -BUILD_ASSERT(BT_BUF_RX_COUNT > CONFIG_BT_MAX_CONN, - "BT_BUF_RX_COUNT needs to be greater than CONFIG_BT_MAX_CONN. " - "In order to do that, increase CONFIG_BT_BUF_ACL_RX_COUNT."); - -#endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */ - -#endif /* CONFIG_BT_CONN */ diff --git a/subsys/bluetooth/host/buf.c b/subsys/bluetooth/host/buf.c index 2ce2477ff05..75bd15834ae 100644 --- a/subsys/bluetooth/host/buf.c +++ b/subsys/bluetooth/host/buf.c @@ -25,6 +25,26 @@ LOG_MODULE_REGISTER(bt_buf, CONFIG_BT_LOG_LEVEL); */ #define SYNC_EVT_SIZE (BT_BUF_RESERVE + BT_HCI_EVT_HDR_SIZE + 255) +static bt_buf_rx_freed_cb_t buf_rx_freed_cb; + +static void buf_rx_freed_notify(enum bt_buf_type mask) +{ + k_sched_lock(); + + if (buf_rx_freed_cb) { + buf_rx_freed_cb(mask); + } + + k_sched_unlock(); +} + +#if defined(CONFIG_BT_ISO_RX) +static void iso_rx_freed_cb(void) +{ + buf_rx_freed_notify(BT_BUF_ISO_IN); +} +#endif + /* Pool for RX HCI buffers that are always freed by `bt_recv` * before it returns. * @@ -40,17 +60,37 @@ NET_BUF_POOL_FIXED_DEFINE(discardable_pool, CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT, sizeof(struct bt_buf_data), NULL); #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) -NET_BUF_POOL_DEFINE(acl_in_pool, CONFIG_BT_BUF_ACL_RX_COUNT, - BT_BUF_ACL_SIZE(CONFIG_BT_BUF_ACL_RX_SIZE), - sizeof(struct acl_data), bt_hci_host_num_completed_packets); +static void acl_in_pool_destroy(struct net_buf *buf) +{ + bt_hci_host_num_completed_packets(buf); + buf_rx_freed_notify(BT_BUF_ACL_IN); +} -NET_BUF_POOL_FIXED_DEFINE(evt_pool, CONFIG_BT_BUF_EVT_RX_COUNT, - BT_BUF_EVT_RX_SIZE, sizeof(struct bt_buf_data), - NULL); +static void evt_pool_destroy(struct net_buf *buf) +{ + net_buf_destroy(buf); + buf_rx_freed_notify(BT_BUF_EVT); +} + +NET_BUF_POOL_DEFINE(acl_in_pool, BT_BUF_ACL_RX_COUNT, BT_BUF_ACL_SIZE(CONFIG_BT_BUF_ACL_RX_SIZE), + sizeof(struct acl_data), acl_in_pool_destroy); + +NET_BUF_POOL_FIXED_DEFINE(evt_pool, CONFIG_BT_BUF_EVT_RX_COUNT, BT_BUF_EVT_RX_SIZE, + sizeof(struct bt_buf_data), evt_pool_destroy); #else -NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, BT_BUF_RX_COUNT, - BT_BUF_RX_SIZE, sizeof(struct acl_data), - NULL); +static void hci_rx_pool_destroy(struct net_buf *buf) +{ + net_buf_destroy(buf); + + /* When ACL Flow Control is disabled, a single pool is used for events and acl data. + * Therefore the callback will always notify about both types of buffers, BT_BUF_EVT and + * BT_BUF_ACL_IN. + */ + buf_rx_freed_notify(BT_BUF_EVT | BT_BUF_ACL_IN); +} + +NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, BT_BUF_RX_COUNT, BT_BUF_RX_SIZE, sizeof(struct acl_data), + hci_rx_pool_destroy); #endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */ struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout) @@ -82,6 +122,19 @@ struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout) return buf; } +void bt_buf_rx_freed_cb_set(bt_buf_rx_freed_cb_t cb) +{ + k_sched_lock(); + + buf_rx_freed_cb = cb; + +#if defined(CONFIG_BT_ISO_RX) + bt_iso_buf_rx_freed_cb_set(cb != NULL ? iso_rx_freed_cb : NULL); +#endif + + k_sched_unlock(); +} + struct net_buf *bt_buf_get_evt(uint8_t evt, bool discardable, k_timeout_t timeout) { diff --git a/subsys/bluetooth/host/classic/rfcomm.c b/subsys/bluetooth/host/classic/rfcomm.c index f8742bff367..4d5bbeeb897 100644 --- a/subsys/bluetooth/host/classic/rfcomm.c +++ b/subsys/bluetooth/host/classic/rfcomm.c @@ -37,7 +37,7 @@ LOG_MODULE_REGISTER(bt_rfcomm); #define RFCOMM_MIN_MTU BT_RFCOMM_SIG_MIN_MTU #define RFCOMM_DEFAULT_MTU 127 -#define RFCOMM_MAX_CREDITS (CONFIG_BT_BUF_ACL_RX_COUNT - 1) +#define RFCOMM_MAX_CREDITS (BT_BUF_ACL_RX_COUNT - 1) #define RFCOMM_CREDITS_THRESHOLD (RFCOMM_MAX_CREDITS / 2) #define RFCOMM_DEFAULT_CREDIT RFCOMM_MAX_CREDITS diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 2db727fb6eb..4a175eb2c74 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ #include #include #include +#include #if DT_HAS_CHOSEN(zephyr_bt_hci) #include #else @@ -263,6 +265,12 @@ void bt_send_one_host_num_completed_packets(uint16_t handle) BT_ASSERT_MSG(err == 0, "Unable to send Host NCP (err %d)", err); } +#if defined(CONFIG_BT_TESTING) +__weak void bt_testing_trace_event_acl_pool_destroy(struct net_buf *buf) +{ +} +#endif + #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) void bt_hci_host_num_completed_packets(struct net_buf *buf) { @@ -270,6 +278,10 @@ void bt_hci_host_num_completed_packets(struct net_buf *buf) struct bt_conn *conn; uint8_t index = acl(buf)->index; + if (IS_ENABLED(CONFIG_BT_TESTING)) { + bt_testing_trace_event_acl_pool_destroy(buf); + } + net_buf_destroy(buf); if (acl(buf)->host_ncp_sent) { @@ -1974,7 +1986,7 @@ static int set_flow_control(void) hbs = net_buf_add(buf, sizeof(*hbs)); (void)memset(hbs, 0, sizeof(*hbs)); hbs->acl_mtu = sys_cpu_to_le16(CONFIG_BT_BUF_ACL_RX_SIZE); - hbs->acl_pkts = sys_cpu_to_le16(CONFIG_BT_BUF_ACL_RX_COUNT); + hbs->acl_pkts = sys_cpu_to_le16(BT_BUF_ACL_RX_COUNT); err = bt_hci_cmd_send_sync(BT_HCI_OP_HOST_BUFFER_SIZE, buf, NULL); if (err) { diff --git a/subsys/bluetooth/host/hci_raw.c b/subsys/bluetooth/host/hci_raw.c index 984c8607ee6..cf50f406d8f 100644 --- a/subsys/bluetooth/host/hci_raw.c +++ b/subsys/bluetooth/host/hci_raw.c @@ -39,8 +39,20 @@ static uint8_t raw_mode = BT_HCI_RAW_MODE_H4; static uint8_t raw_mode; #endif -NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, BT_BUF_RX_COUNT, - BT_BUF_RX_SIZE, sizeof(struct bt_buf_data), NULL); +static bt_buf_rx_freed_cb_t buf_rx_freed_cb; + +static void hci_rx_buf_destroy(struct net_buf *buf) +{ + net_buf_destroy(buf); + + if (buf_rx_freed_cb) { + /* bt_buf_get_rx is used for all types of RX buffers */ + buf_rx_freed_cb(BT_BUF_EVT | BT_BUF_ACL_IN | BT_BUF_ISO_IN); + } +} + +NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, BT_BUF_RX_COUNT, BT_BUF_RX_SIZE, sizeof(struct bt_buf_data), + hci_rx_buf_destroy); NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, CONFIG_BT_BUF_CMD_TX_COUNT, BT_BUF_CMD_SIZE(CONFIG_BT_BUF_CMD_TX_SIZE), sizeof(struct bt_buf_data), NULL); @@ -112,6 +124,11 @@ struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout) return buf; } +void bt_buf_rx_freed_cb_set(bt_buf_rx_freed_cb_t cb) +{ + buf_rx_freed_cb = cb; +} + struct net_buf *bt_buf_get_tx(enum bt_buf_type type, k_timeout_t timeout, const void *data, size_t size) { diff --git a/subsys/bluetooth/host/iso.c b/subsys/bluetooth/host/iso.c index 3cbb06011d3..26440c22a8a 100644 --- a/subsys/bluetooth/host/iso.c +++ b/subsys/bluetooth/host/iso.c @@ -51,8 +51,20 @@ LOG_MODULE_REGISTER(bt_iso, CONFIG_BT_ISO_LOG_LEVEL); #define iso_chan(_iso) ((_iso)->iso.chan); #if defined(CONFIG_BT_ISO_RX) +static bt_iso_buf_rx_freed_cb_t buf_rx_freed_cb; + +static void iso_rx_buf_destroy(struct net_buf *buf) +{ + net_buf_destroy(buf); + + if (buf_rx_freed_cb) { + buf_rx_freed_cb(); + } +} + NET_BUF_POOL_FIXED_DEFINE(iso_rx_pool, CONFIG_BT_ISO_RX_BUF_COUNT, - BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_RX_MTU), sizeof(struct iso_data), NULL); + BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_RX_MTU), sizeof(struct iso_data), + iso_rx_buf_destroy); static struct bt_iso_recv_info iso_info_data[CONFIG_BT_ISO_RX_BUF_COUNT]; #define iso_info(buf) (&iso_info_data[net_buf_id(buf)]) @@ -581,6 +593,11 @@ struct net_buf *bt_iso_get_rx(k_timeout_t timeout) return buf; } +void bt_iso_buf_rx_freed_cb_set(bt_iso_buf_rx_freed_cb_t cb) +{ + buf_rx_freed_cb = cb; +} + void bt_iso_recv(struct bt_conn *iso, struct net_buf *buf, uint8_t flags) { struct bt_hci_iso_sdu_hdr *hdr; diff --git a/subsys/bluetooth/host/iso_internal.h b/subsys/bluetooth/host/iso_internal.h index c997f81f517..765c336c9db 100644 --- a/subsys/bluetooth/host/iso_internal.h +++ b/subsys/bluetooth/host/iso_internal.h @@ -87,6 +87,16 @@ void hci_iso(struct net_buf *buf); /* Allocates RX buffer */ struct net_buf *bt_iso_get_rx(k_timeout_t timeout); +/** A callback used to notify about freed buffer in the iso rx pool. */ +typedef void (*bt_iso_buf_rx_freed_cb_t)(void); + +/** Set a callback to notify about freed buffer in the iso rx pool. + * + * @param cb Callback to notify about freed buffer in the iso rx pool. If NULL, the callback is + * disabled. + */ +void bt_iso_buf_rx_freed_cb_set(bt_iso_buf_rx_freed_cb_t cb); + /* Process CIS Established event */ void hci_le_cis_established(struct net_buf *buf); diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index ed185d12fd7..a8e4843ca3a 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -43,7 +44,7 @@ LOG_MODULE_REGISTER(bt_l2cap, CONFIG_BT_L2CAP_LOG_LEVEL); #define L2CAP_ECRED_MIN_MTU 64 #define L2CAP_ECRED_MIN_MPS 64 -#define L2CAP_LE_MAX_CREDITS (CONFIG_BT_BUF_ACL_RX_COUNT - 1) +#define L2CAP_LE_MAX_CREDITS (BT_BUF_ACL_RX_COUNT - 1) #define L2CAP_LE_CID_DYN_START 0x0040 #define L2CAP_LE_CID_DYN_END 0x007f @@ -2572,6 +2573,7 @@ static void l2cap_chan_le_recv_seg_direct(struct bt_l2cap_le_chan *chan, struct static void l2cap_chan_le_recv(struct bt_l2cap_le_chan *chan, struct net_buf *buf) { + struct net_buf *owned_ref; uint16_t sdu_len; int err; @@ -2645,7 +2647,13 @@ static void l2cap_chan_le_recv(struct bt_l2cap_le_chan *chan, return; } - err = chan->chan.ops->recv(&chan->chan, buf); + owned_ref = net_buf_ref(buf); + err = chan->chan.ops->recv(&chan->chan, owned_ref); + if (err != -EINPROGRESS) { + net_buf_unref(owned_ref); + owned_ref = NULL; + } + if (err < 0) { if (err != -EINPROGRESS) { LOG_ERR("err %d", err); @@ -3244,7 +3252,7 @@ static int bt_l2cap_dyn_chan_send(struct bt_l2cap_le_chan *le_chan, struct net_b /* Call `net_buf_reserve(buf, BT_L2CAP_SDU_CHAN_SEND_RESERVE)` * when allocating buffers intended for bt_l2cap_chan_send(). */ - LOG_DBG("Not enough headroom in buf %p", buf); + LOG_ERR("Not enough headroom in buf %p", buf); return -EINVAL; } @@ -3292,7 +3300,7 @@ int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf) LOG_DBG("chan %p buf %p len %zu", chan, buf, buf->len); if (buf->ref != 1) { - LOG_DBG("Expecting 1 ref, got %d", buf->ref); + LOG_WRN("Expecting 1 ref, got %d", buf->ref); return -EINVAL; } diff --git a/tests/bluetooth/buf/CMakeLists.txt b/tests/bluetooth/buf/CMakeLists.txt new file mode 100644 index 00000000000..3da24b0b551 --- /dev/null +++ b/tests/bluetooth/buf/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(buf) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/bluetooth/buf/prj.conf b/tests/bluetooth/buf/prj.conf new file mode 100644 index 00000000000..697529ffb9d --- /dev/null +++ b/tests/bluetooth/buf/prj.conf @@ -0,0 +1,10 @@ +CONFIG_TEST=y +CONFIG_ZTEST=y + +CONFIG_BT=y +CONFIG_BT_CTLR=n +CONFIG_BT_H4=n + +# Needed to enable and test the iso rx pool +CONFIG_BT_OBSERVER=y +CONFIG_BT_ISO_SYNC_RECEIVER=y diff --git a/tests/bluetooth/buf/src/main.c b/tests/bluetooth/buf/src/main.c new file mode 100644 index 00000000000..36b57a0e3f9 --- /dev/null +++ b/tests/bluetooth/buf/src/main.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +static enum bt_buf_type freed_buf_type; +static K_SEM_DEFINE(rx_sem, 0, 1); + +void bt_buf_rx_freed_cb(enum bt_buf_type type) +{ + freed_buf_type = type; + k_sem_give(&rx_sem); +} + +ZTEST_SUITE(test_buf_data_api, NULL, NULL, NULL, NULL, NULL); + +ZTEST(test_buf_data_api, test_buf_freed_cb) +{ + struct net_buf *buf; + int err; + + bt_buf_rx_freed_cb_set(bt_buf_rx_freed_cb); + + /* Test that the callback is called for the BT_BUF_EVT type */ + buf = bt_buf_get_rx(BT_BUF_EVT, K_NO_WAIT); + zassert_not_null(buf, "Failed to get event buffer"); + + net_buf_unref(buf); + /* The freed buf cb is called from net_buf_unref, therefore the semaphore should + * already by given. + */ + err = k_sem_take(&rx_sem, K_NO_WAIT); + zassert_equal(err, 0, "Timeout while waiting for event buffer to be freed"); + zassert_equal(BT_BUF_EVT, BT_BUF_EVT & freed_buf_type, "Event buffer wasn't freed"); + + /* Test that the callback is called for the BT_BUF_ACL_IN type */ + buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT); + zassert_not_null(buf, "Failed to get ACL buffer"); + + net_buf_unref(buf); + /* The freed buf cb is called from net_buf_unref, therefore the semaphore should + * already by given. + */ + err = k_sem_take(&rx_sem, K_NO_WAIT); + zassert_equal(err, 0, "Timeout while waiting for ACL buffer to be freed"); + zassert_equal(BT_BUF_ACL_IN, BT_BUF_ACL_IN & freed_buf_type, "ACL buffer wasn't freed"); + + /* Test that the callback is called for the BT_BUF_ISO_IN type */ + buf = bt_buf_get_rx(BT_BUF_ISO_IN, K_NO_WAIT); + zassert_not_null(buf, "Failed to get ISO buffer"); + + net_buf_unref(buf); + /* The freed buf cb is called from net_buf_unref, therefore the semaphore should + * already by given. + */ + err = k_sem_take(&rx_sem, K_NO_WAIT); + zassert_equal(err, 0, "Timeout while waiting for ISO buffer to be freed"); + zassert_equal(BT_BUF_ISO_IN, BT_BUF_ISO_IN & freed_buf_type, "ISO buffer wasn't freed"); +} diff --git a/tests/bluetooth/buf/testcase.yaml b/tests/bluetooth/buf/testcase.yaml new file mode 100644 index 00000000000..418d357d4fb --- /dev/null +++ b/tests/bluetooth/buf/testcase.yaml @@ -0,0 +1,30 @@ +common: + tags: + - bluetooth + - host + +tests: + bluetooth.buf: + platform_allow: + - native_sim + - native_sim/native/64 + integration_platforms: + - native_sim + extra_configs: + - CONFIG_BT_HCI_ACL_FLOW_CONTROL=y + bluetooth.buf.no_acl_flow_control: + platform_allow: + - native_sim + - native_sim/native/64 + integration_platforms: + - native_sim + extra_configs: + - CONFIG_BT_HCI_ACL_FLOW_CONTROL=n + bluetooth.buf.hci_raw: + platform_allow: + - native_sim + - native_sim/native/64 + integration_platforms: + - native_sim + extra_configs: + - CONFIG_BT_HCI_RAW=y diff --git a/tests/bluetooth/common/testlib/include/testlib/addr.h b/tests/bluetooth/common/testlib/include/testlib/addr.h new file mode 100644 index 00000000000..2f9e49488b7 --- /dev/null +++ b/tests/bluetooth/common/testlib/include/testlib/addr.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_ADDR_H_ +#define ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_ADDR_H_ + +#include + +#include +#include + +/** Bluetooth LE static random address */ +#define BT_TESTLIB_ADDR_LE_RANDOM_C0_00_00_00_00_(last) \ + ((bt_addr_le_t){ \ + .type = BT_ADDR_LE_RANDOM, \ + .a = {{last, 0x00, 0x00, 0x00, 0x00, 0xc0}}, \ + }) + +#endif /* ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_ADDR_H_ */ diff --git a/tests/bluetooth/tester/boards/frdm_rw612.conf b/tests/bluetooth/tester/boards/frdm_rw612.conf index 48958c6ac7c..ba1ae16dc7c 100644 --- a/tests/bluetooth/tester/boards/frdm_rw612.conf +++ b/tests/bluetooth/tester/boards/frdm_rw612.conf @@ -1,5 +1,4 @@ CONFIG_BT_MAX_CONN=16 -CONFIG_BT_BUF_ACL_RX_COUNT=17 # debug options # CONFIG_UART_CONSOLE=y diff --git a/tests/bluetooth/tester/boards/rd_rw612_bga.conf b/tests/bluetooth/tester/boards/rd_rw612_bga.conf index 48958c6ac7c..ba1ae16dc7c 100644 --- a/tests/bluetooth/tester/boards/rd_rw612_bga.conf +++ b/tests/bluetooth/tester/boards/rd_rw612_bga.conf @@ -1,5 +1,4 @@ CONFIG_BT_MAX_CONN=16 -CONFIG_BT_BUF_ACL_RX_COUNT=17 # debug options # CONFIG_UART_CONSOLE=y diff --git a/tests/bsim/bluetooth/host/l2cap/compile.sh b/tests/bsim/bluetooth/host/l2cap/compile.sh index 71d41a7f2e7..ddb7f5d14bc 100755 --- a/tests/bsim/bluetooth/host/l2cap/compile.sh +++ b/tests/bsim/bluetooth/host/l2cap/compile.sh @@ -19,6 +19,7 @@ app=tests/bsim/bluetooth/host/l2cap/stress conf_file=prj_nofrag.conf compile app=tests/bsim/bluetooth/host/l2cap/stress conf_file=prj_syswq.conf compile run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/l2cap/split/compile.sh run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/l2cap/reassembly/compile.sh +run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/l2cap/einprogress/compile.sh run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/l2cap/ecred/compile.sh app=tests/bsim/bluetooth/host/l2cap/credits compile app=tests/bsim/bluetooth/host/l2cap/credits conf_file=prj_ecred.conf compile diff --git a/tests/bsim/bluetooth/host/l2cap/einprogress/CMakeLists.txt b/tests/bsim/bluetooth/host/l2cap/einprogress/CMakeLists.txt new file mode 100644 index 00000000000..b6d0135f936 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/einprogress/CMakeLists.txt @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(test_l2cap_einprogress) + +add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/common/testlib testlib) +target_link_libraries(app PRIVATE testlib) + +add_subdirectory(${ZEPHYR_BASE}/tests/bsim/babblekit babblekit) +target_link_libraries(app PRIVATE babblekit) + +zephyr_include_directories( + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ +) + +target_sources(app PRIVATE + src/main.c + src/dut.c + src/tester.c +) diff --git a/tests/bsim/bluetooth/host/l2cap/einprogress/compile.sh b/tests/bsim/bluetooth/host/l2cap/einprogress/compile.sh new file mode 100755 index 00000000000..e717a4b2bbe --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/einprogress/compile.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 +set -eu +: "${ZEPHYR_BASE:?ZEPHYR_BASE must be defined}" + +INCR_BUILD=1 + +source ${ZEPHYR_BASE}/tests/bsim/compile.source + +app="$(guess_test_relpath)" compile + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/l2cap/einprogress/prj.conf b/tests/bsim/bluetooth/host/l2cap/einprogress/prj.conf new file mode 100644 index 00000000000..e2540cd6f6a --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/einprogress/prj.conf @@ -0,0 +1,25 @@ +CONFIG_LOG=y +CONFIG_ASSERT=y +CONFIG_THREAD_NAME=y +CONFIG_LOG_THREAD_ID_PREFIX=y +CONFIG_ARCH_POSIX_TRAP_ON_FATAL=y +CONFIG_BT_TESTING=y + +CONFIG_BT_HCI_ACL_FLOW_CONTROL=y + +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_PERIPHERAL=y + +# Dependency of testlib/adv and testlib/scan. +CONFIG_BT_EXT_ADV=y + +# Dynamic channel depends on SMP +CONFIG_BT_SMP=y +CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y + +# Disable auto-initiated procedures so they don't +# mess with the test's execution. +CONFIG_BT_AUTO_PHY_UPDATE=n +CONFIG_BT_AUTO_DATA_LEN_UPDATE=n +CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n diff --git a/tests/bsim/bluetooth/host/l2cap/einprogress/src/data.h b/tests/bsim/bluetooth/host/l2cap/einprogress/src/data.h new file mode 100644 index 00000000000..4920d909d08 --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/einprogress/src/data.h @@ -0,0 +1,11 @@ +/* Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_TESTS_BSIM_BLUETOOTH_HOST_L2CAP_EINPROGRESS_SRC_DATA_H_ +#define ZEPHYR_TESTS_BSIM_BLUETOOTH_HOST_L2CAP_EINPROGRESS_SRC_DATA_H_ + +#define TEST_DATA_L2CAP_PSM 0x0080 +#define TEST_DATA_DUT_ADDR BT_TESTLIB_ADDR_LE_RANDOM_C0_00_00_00_00_(0x01) + +#endif /* ZEPHYR_TESTS_BSIM_BLUETOOTH_HOST_L2CAP_EINPROGRESS_SRC_DATA_H_ */ diff --git a/tests/bsim/bluetooth/host/l2cap/einprogress/src/dut.c b/tests/bsim/bluetooth/host/l2cap/einprogress/src/dut.c new file mode 100644 index 00000000000..b3da048b8ca --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/einprogress/src/dut.c @@ -0,0 +1,124 @@ +/* Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "data.h" + +LOG_MODULE_REGISTER(dut, LOG_LEVEL_INF); + +/** Here we keep track of the reference count in the test + * application. This allows us to notice if the stack has freed + * references that were ours. + */ +static atomic_t acl_pool_refs_held[BT_BUF_ACL_RX_COUNT]; + +BUILD_ASSERT(IS_ENABLED(CONFIG_BT_TESTING)); +BUILD_ASSERT(IS_ENABLED(CONFIG_BT_HCI_ACL_FLOW_CONTROL)); +void bt_testing_trace_event_acl_pool_destroy(struct net_buf *destroyed_buf) +{ + int buf_id = net_buf_id(destroyed_buf); + + __ASSERT_NO_MSG(0 <= buf_id && buf_id < ARRAY_SIZE(acl_pool_refs_held)); + TEST_ASSERT(acl_pool_refs_held[buf_id] == 0, + "ACL buf was destroyed while tester still held a reference"); +} + +static void acl_pool_refs_held_add(struct net_buf *buf) +{ + int buf_id = net_buf_id(buf); + + __ASSERT_NO_MSG(0 <= buf_id && buf_id < BT_BUF_ACL_RX_COUNT); + atomic_inc(&acl_pool_refs_held[buf_id]); +} + +static void acl_pool_refs_held_remove(struct net_buf *buf) +{ + int buf_id = net_buf_id(buf); + + __ASSERT_NO_MSG(0 <= buf_id && buf_id < ARRAY_SIZE(acl_pool_refs_held)); + atomic_val_t old = atomic_dec(&acl_pool_refs_held[buf_id]); + + __ASSERT(old != 0, "Tester error: releasing a reference that was not held"); +} + +struct k_fifo ack_todo; + +static int dut_chan_recv_cb(struct bt_l2cap_chan *chan, struct net_buf *buf) +{ + /* Move buf. Ownership is ours if we return -EINPROGRESS. */ + acl_pool_refs_held_add(buf); + k_fifo_put(&ack_todo, buf); + + return -EINPROGRESS; +} + +static const struct bt_l2cap_chan_ops ops = { + .recv = dut_chan_recv_cb, +}; + +static struct bt_l2cap_le_chan le_chan = { + .chan.ops = &ops, +}; + +static int dut_server_accept_cb(struct bt_conn *conn, struct bt_l2cap_server *server, + struct bt_l2cap_chan **chan) +{ + *chan = &le_chan.chan; + return 0; +} + +static struct bt_l2cap_server test_l2cap_server = { + .accept = dut_server_accept_cb, + .psm = TEST_DATA_L2CAP_PSM, +}; + +void entrypoint_dut(void) +{ + struct net_buf *ack_buf; + struct bt_conn *conn = NULL; + int err; + + TEST_START("dut"); + + k_fifo_init(&ack_todo); + + err = bt_id_create(&TEST_DATA_DUT_ADDR, NULL); + __ASSERT_NO_MSG(!err); + + err = bt_enable(NULL); + __ASSERT_NO_MSG(!err); + + err = bt_l2cap_server_register(&test_l2cap_server); + __ASSERT_NO_MSG(!err); + + err = bt_testlib_adv_conn(&conn, BT_ID_DEFAULT, NULL); + __ASSERT_NO_MSG(!err); + + ack_buf = k_fifo_get(&ack_todo, K_FOREVER); + __ASSERT_NO_MSG(ack_buf); + + acl_pool_refs_held_remove(ack_buf); + err = bt_l2cap_chan_recv_complete(&le_chan.chan, ack_buf); + TEST_ASSERT(!err); + + TEST_PASS_AND_EXIT("dut"); +} diff --git a/tests/bsim/bluetooth/host/l2cap/einprogress/src/main.c b/tests/bsim/bluetooth/host/l2cap/einprogress/src/main.c new file mode 100644 index 00000000000..d6611e8f8dd --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/einprogress/src/main.c @@ -0,0 +1,47 @@ +/* Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "bstests.h" +#include "babblekit/testcase.h" + +extern void entrypoint_dut(void); +extern void entrypoint_tester(void); +extern enum bst_result_t bst_result; + +static void test_end_cb(void) +{ + if (bst_result != Passed) { + TEST_PRINT("Test has not passed."); + } +} + +static const struct bst_test_instance entrypoints[] = { + { + .test_id = "l2cap/einprogress/dut", + .test_delete_f = test_end_cb, + .test_main_f = entrypoint_dut, + }, + { + .test_id = "l2cap/einprogress/tester", + .test_delete_f = test_end_cb, + .test_main_f = entrypoint_tester, + }, + BSTEST_END_MARKER, +}; + +static struct bst_test_list *install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, entrypoints); +}; + +bst_test_install_t test_installers[] = {install, NULL}; + +int main(void) +{ + bst_main(); + + return 0; +} diff --git a/tests/bsim/bluetooth/host/l2cap/einprogress/src/tester.c b/tests/bsim/bluetooth/host/l2cap/einprogress/src/tester.c new file mode 100644 index 00000000000..2e2d000aa9c --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/einprogress/src/tester.c @@ -0,0 +1,72 @@ +/* Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "data.h" + +LOG_MODULE_REGISTER(tester, LOG_LEVEL_INF); + +static int tester_chan_recv_cb(struct bt_l2cap_chan *chan, struct net_buf *buf) +{ + __ASSERT(false, "Unexpected recv in tester"); + return 0; +}; + +static struct bt_l2cap_le_chan le_chan = { + .chan.ops = + &(const struct bt_l2cap_chan_ops){ + .recv = tester_chan_recv_cb, + }, +}; + +NET_BUF_POOL_DEFINE(test_pool, 1, BT_L2CAP_SDU_BUF_SIZE(0), CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); + +void entrypoint_tester(void) +{ + struct net_buf *sdu; + struct bt_conn *conn = NULL; + int err; + + TEST_START("tester"); + + err = bt_enable(NULL); + __ASSERT_NO_MSG(!err); + + err = bt_testlib_connect(&TEST_DATA_DUT_ADDR, &conn); + __ASSERT_NO_MSG(!err); + + err = bt_l2cap_chan_connect(conn, &le_chan.chan, TEST_DATA_L2CAP_PSM); + __ASSERT_NO_MSG(!err); + + /* Wait for async L2CAP connect */ + while (!atomic_test_bit(le_chan.chan.status, BT_L2CAP_STATUS_OUT)) { + k_sleep(K_MSEC(100)); + } + + sdu = net_buf_alloc(&test_pool, K_NO_WAIT); + __ASSERT_NO_MSG(sdu); + net_buf_reserve(sdu, BT_L2CAP_SDU_CHAN_SEND_RESERVE); + + err = bt_l2cap_chan_send(&le_chan.chan, sdu); + __ASSERT(!err, "err: %d", err); + + TEST_PASS("tester"); +} diff --git a/tests/bsim/bluetooth/host/l2cap/einprogress/test_scripts/run.sh b/tests/bsim/bluetooth/host/l2cap/einprogress/test_scripts/run.sh new file mode 100755 index 00000000000..b86db52d9df --- /dev/null +++ b/tests/bsim/bluetooth/host/l2cap/einprogress/test_scripts/run.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +set -eu + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +test_name="$(guess_test_long_name)" +simulation_id=${test_name} +verbosity_level=2 +EXECUTE_TIMEOUT=120 +SIM_LEN_US=$((2 * 1000 * 1000)) + +test_exe="${BSIM_OUT_PATH}/bin/bs_${BOARD_TS}_${test_name}_prj_conf" + +cd ${BSIM_OUT_PATH}/bin + +Execute "${test_exe}" -v=${verbosity_level} -s=${simulation_id} -d=0 \ + -testid=l2cap/einprogress/dut +Execute "${test_exe}" -v=${verbosity_level} -s=${simulation_id} -d=1 \ + -testid=l2cap/einprogress/tester + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} -D=2 -sim_length=${SIM_LEN_US} $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/l2cap/reassembly/dut/prj.conf b/tests/bsim/bluetooth/host/l2cap/reassembly/dut/prj.conf index 4f6ee8187bf..d913264f700 100644 --- a/tests/bsim/bluetooth/host/l2cap/reassembly/dut/prj.conf +++ b/tests/bsim/bluetooth/host/l2cap/reassembly/dut/prj.conf @@ -28,5 +28,5 @@ CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n # RX buffer pool, it is a good idea to constrain said buffer # pool. CONFIG_BT_MAX_CONN=1 -CONFIG_BT_BUF_ACL_RX_COUNT=6 +CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=4 CONFIG_BT_BUF_EVT_RX_COUNT=6 diff --git a/tests/bsim/bluetooth/host/l2cap/stress/prj.conf b/tests/bsim/bluetooth/host/l2cap/stress/prj.conf index 6f782ba157d..fecd8ba08d1 100644 --- a/tests/bsim/bluetooth/host/l2cap/stress/prj.conf +++ b/tests/bsim/bluetooth/host/l2cap/stress/prj.conf @@ -42,7 +42,6 @@ CONFIG_BT_CTLR_DATA_LENGTH_MAX=27 CONFIG_BT_CTLR_RX_BUFFERS=10 CONFIG_BT_MAX_CONN=10 -CONFIG_BT_BUF_ACL_RX_COUNT=11 CONFIG_LOG=y CONFIG_ASSERT=y diff --git a/tests/bsim/bluetooth/host/l2cap/stress/prj_nofrag.conf b/tests/bsim/bluetooth/host/l2cap/stress/prj_nofrag.conf index a4e71a58b64..ea9cda13529 100644 --- a/tests/bsim/bluetooth/host/l2cap/stress/prj_nofrag.conf +++ b/tests/bsim/bluetooth/host/l2cap/stress/prj_nofrag.conf @@ -34,7 +34,6 @@ CONFIG_BT_CTLR_DATA_LENGTH_MAX=81 CONFIG_BT_CTLR_RX_BUFFERS=10 CONFIG_BT_MAX_CONN=10 -CONFIG_BT_BUF_ACL_RX_COUNT=11 CONFIG_LOG=y CONFIG_ASSERT=y diff --git a/tests/bsim/bluetooth/host/l2cap/stress/prj_syswq.conf b/tests/bsim/bluetooth/host/l2cap/stress/prj_syswq.conf index 9c21c148cbf..3cddbe332cd 100644 --- a/tests/bsim/bluetooth/host/l2cap/stress/prj_syswq.conf +++ b/tests/bsim/bluetooth/host/l2cap/stress/prj_syswq.conf @@ -42,7 +42,6 @@ CONFIG_BT_CTLR_DATA_LENGTH_MAX=27 CONFIG_BT_CTLR_RX_BUFFERS=10 CONFIG_BT_MAX_CONN=10 -CONFIG_BT_BUF_ACL_RX_COUNT=11 CONFIG_LOG=y CONFIG_ASSERT=y diff --git a/tests/bsim/bluetooth/host/misc/conn_stress/central/prj.conf b/tests/bsim/bluetooth/host/misc/conn_stress/central/prj.conf index 0238e1e38eb..ff7d61dfb05 100644 --- a/tests/bsim/bluetooth/host/misc/conn_stress/central/prj.conf +++ b/tests/bsim/bluetooth/host/misc/conn_stress/central/prj.conf @@ -2,7 +2,6 @@ CONFIG_BT=y CONFIG_LOG=y CONFIG_BT_CENTRAL=y CONFIG_BT_MAX_CONN=12 -CONFIG_BT_BUF_ACL_RX_COUNT=13 CONFIG_BT_MAX_PAIRED=12 CONFIG_BT_SMP=y CONFIG_BT_PRIVACY=y diff --git a/tests/bsim/bluetooth/host/misc/hfc_multilink/dut/prj.conf b/tests/bsim/bluetooth/host/misc/hfc_multilink/dut/prj.conf index 114b8574b4e..daa5dd196ee 100644 --- a/tests/bsim/bluetooth/host/misc/hfc_multilink/dut/prj.conf +++ b/tests/bsim/bluetooth/host/misc/hfc_multilink/dut/prj.conf @@ -27,9 +27,5 @@ CONFIG_BT_AUTO_DATA_LEN_UPDATE=n CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n CONFIG_BT_MAX_CONN=3 -CONFIG_BT_BUF_ACL_RX_COUNT=4 - -# This test will fail when CONFIG_BT_MAX_CONN == CONFIG_BT_BUF_ACL_RX_COUNT -# CONFIG_BT_BUF_ACL_RX_COUNT=3 CONFIG_BT_HCI_ACL_FLOW_CONTROL=y diff --git a/tests/bsim/bluetooth/host/misc/hfc_multilink/dut/src/dut.c b/tests/bsim/bluetooth/host/misc/hfc_multilink/dut/src/dut.c index a8524a90b5e..410417563d1 100644 --- a/tests/bsim/bluetooth/host/misc/hfc_multilink/dut/src/dut.c +++ b/tests/bsim/bluetooth/host/misc/hfc_multilink/dut/src/dut.c @@ -24,7 +24,7 @@ LOG_MODULE_REGISTER(dut, CONFIG_APP_LOG_LEVEL); #define NUM_TESTERS CONFIG_BT_MAX_CONN /* Build with the minimum possible amount of RX buffers */ -BUILD_ASSERT(CONFIG_BT_BUF_ACL_RX_COUNT == (CONFIG_BT_MAX_CONN + 1)); +BUILD_ASSERT(BT_BUF_ACL_RX_COUNT >= (CONFIG_BT_MAX_CONN + 1)); struct tester { size_t sdu_count; diff --git a/tests/bsim/bluetooth/ll/multiple_id/prj.conf b/tests/bsim/bluetooth/ll/multiple_id/prj.conf index 8cd08356b3a..173fc296c7c 100644 --- a/tests/bsim/bluetooth/ll/multiple_id/prj.conf +++ b/tests/bsim/bluetooth/ll/multiple_id/prj.conf @@ -12,7 +12,6 @@ CONFIG_BT_AUTO_DATA_LEN_UPDATE=y CONFIG_BT_MAX_CONN=250 CONFIG_BT_ID_MAX=250 -CONFIG_BT_BUF_ACL_RX_COUNT=251 # L2CAP, ATT and SMP usage cause data transmission deadlock due to shortage # of buffers when transactions crossover amongst the connections in the same