-
Notifications
You must be signed in to change notification settings - Fork 6.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bluetooth: Host: Test L2CAP -EINPROGRESS feature
The test implementation is based on a copy of the HFC multilink test. The test verifies that the stack respects the reference counting of SDU buffers when the L2CAP -EINPROGRESS feature is used. Signed-off-by: Aleksander Wasaznik <[email protected]>
- Loading branch information
1 parent
9f2dc36
commit 2da64d7
Showing
16 changed files
with
1,238 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/* | ||
* Copyright (c) 2024 Nordic Semiconductor ASA | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#ifndef ZEPHYR_TESTS_BSIM_BLUETOOTH_HOST_MISC_HFC_MULTILINK_SRC_DATA_H_ | ||
#define ZEPHYR_TESTS_BSIM_BLUETOOTH_HOST_MISC_HFC_MULTILINK_SRC_DATA_H_ | ||
|
||
#define TESTER_NAME "tester" | ||
#define SDU_NUM 1 | ||
#define L2CAP_TEST_PSM 0x0080 | ||
/* use the first dynamic channel ID */ | ||
#define L2CAP_TEST_CID 0x0040 | ||
#define PAYLOAD_LEN 50 | ||
|
||
#define EXPECTED_CONN_INTERVAL 50 | ||
#define CONN_INTERVAL_TOL 20 | ||
|
||
#endif /* ZEPHYR_TESTS_BSIM_BLUETOOTH_HOST_MISC_HFC_MULTILINK_SRC_DATA_H_ */ |
28 changes: 28 additions & 0 deletions
28
tests/bsim/bluetooth/host/l2cap/einprogress/dut/CMakeLists.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
cmake_minimum_required(VERSION 3.20.0) | ||
|
||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) | ||
|
||
project(hfc_multilink) | ||
|
||
# This contains a variety of helper functions that abstract away common tasks, | ||
# like scanning, setting up a connection, querying the peer for a given | ||
# characteristic, etc.. | ||
add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/common/testlib testlib) | ||
target_link_libraries(app PRIVATE testlib) | ||
|
||
# This contains babblesim-specific helpers, e.g. device synchronization. | ||
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 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Kconfig options for the test | ||
# | ||
# Copyright (c) 2024 Nordic Semiconductor ASA | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
menu "Test configuration" | ||
|
||
module = APP | ||
module-str = app | ||
|
||
source "subsys/logging/Kconfig.template.log_config" | ||
|
||
endmenu | ||
|
||
source "Kconfig.zephyr" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
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_APP_LOG_LEVEL_DBG=y | ||
# CONFIG_BT_CONN_LOG_LEVEL_DBG=y | ||
# CONFIG_BT_ATT_LOG_LEVEL_DBG=y | ||
# CONFIG_BT_GATT_LOG_LEVEL_DBG=y | ||
|
||
CONFIG_BT=y | ||
CONFIG_BT_DEVICE_NAME="sample-test" | ||
CONFIG_BT_CENTRAL=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 | ||
|
||
CONFIG_BT_MAX_CONN=3 | ||
CONFIG_BT_BUF_ACL_RX_COUNT=4 | ||
|
||
CONFIG_BT_HCI_ACL_FLOW_CONTROL=y |
223 changes: 223 additions & 0 deletions
223
tests/bsim/bluetooth/host/l2cap/einprogress/dut/src/dut.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
/* | ||
* Copyright (c) 2024 Nordic Semiconductor ASA | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include <zephyr/kernel.h> | ||
#include <zephyr/bluetooth/bluetooth.h> | ||
#include <zephyr/bluetooth/conn.h> | ||
#include <zephyr/bluetooth/l2cap.h> | ||
#include <zephyr/logging/log.h> | ||
#include <zephyr/net/buf.h> | ||
#include <zephyr/sys/__assert.h> | ||
#include <zephyr/sys/atomic.h> | ||
#include <zephyr/sys/util_macro.h> | ||
|
||
#include "testlib/conn.h" | ||
#include "testlib/scan.h" | ||
|
||
#include "babblekit/flags.h" | ||
#include "babblekit/testcase.h" | ||
|
||
/* local includes */ | ||
#include "data.h" | ||
|
||
LOG_MODULE_REGISTER(dut, CONFIG_APP_LOG_LEVEL); | ||
|
||
struct tester { | ||
size_t sdu_count; | ||
struct bt_conn *conn; | ||
struct bt_l2cap_le_chan le_chan; | ||
struct k_fifo ack_todo; | ||
}; | ||
|
||
static atomic_t acl_pool_refs_held[CONFIG_BT_BUF_ACL_RX_COUNT]; | ||
static struct tester tester; | ||
|
||
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 < CONFIG_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"); | ||
} | ||
|
||
static struct tester *get_tester(struct bt_conn *conn) | ||
{ | ||
if (tester.conn == conn) { | ||
return &tester; | ||
} | ||
|
||
return NULL; | ||
} | ||
|
||
static int recv_cb(struct bt_l2cap_chan *chan, struct net_buf *buf) | ||
{ | ||
char addr[BT_ADDR_LE_STR_LEN]; | ||
struct tester *tester = get_tester(chan->conn); | ||
|
||
tester->sdu_count += 1; | ||
|
||
bt_addr_le_to_str(bt_conn_get_dst(chan->conn), addr, sizeof(addr)); | ||
|
||
LOG_INF("Received SDU %d / %d from (%s)", tester->sdu_count, SDU_NUM, addr); | ||
|
||
/* Move buf. Ownership is ours if we return -EINPROGRESS. */ | ||
acl_pool_refs_held_add(buf); | ||
net_buf_put(&tester->ack_todo, buf); | ||
|
||
return -EINPROGRESS; | ||
} | ||
|
||
static int server_accept_cb(struct bt_conn *conn, struct bt_l2cap_server *server, | ||
struct bt_l2cap_chan **chan) | ||
{ | ||
static struct bt_l2cap_chan_ops ops = { | ||
.recv = recv_cb, | ||
}; | ||
|
||
struct tester *tester = get_tester(conn); | ||
struct bt_l2cap_le_chan *le_chan = &tester->le_chan; | ||
|
||
k_fifo_init(&tester->ack_todo); | ||
memset(le_chan, 0, sizeof(*le_chan)); | ||
le_chan->chan.ops = &ops; | ||
*chan = &le_chan->chan; | ||
|
||
return 0; | ||
} | ||
|
||
static int l2cap_server_register(bt_security_t sec_level) | ||
{ | ||
static struct bt_l2cap_server test_l2cap_server = {.accept = server_accept_cb}; | ||
|
||
test_l2cap_server.psm = L2CAP_TEST_PSM; | ||
test_l2cap_server.sec_level = sec_level; | ||
|
||
int err = bt_l2cap_server_register(&test_l2cap_server); | ||
|
||
TEST_ASSERT(err == 0, "Failed to register l2cap server (err %d)", err); | ||
|
||
return test_l2cap_server.psm; | ||
} | ||
|
||
static struct bt_conn *connect_tester(void) | ||
{ | ||
int err; | ||
bt_addr_le_t tester = {}; | ||
struct bt_conn *conn = NULL; | ||
char addr[BT_ADDR_LE_STR_LEN]; | ||
|
||
/* The device address will not change. Scan only once in order to reduce | ||
* test time. | ||
*/ | ||
err = bt_testlib_scan_find_name(&tester, TESTER_NAME); | ||
TEST_ASSERT(!err, "Failed to start scan (err %d)", err); | ||
|
||
/* Create a connection using that address */ | ||
err = bt_testlib_connect(&tester, &conn); | ||
TEST_ASSERT(!err, "Failed to initiate connection (err %d)", err); | ||
|
||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); | ||
LOG_DBG("Connected to %s", addr); | ||
|
||
return conn; | ||
} | ||
|
||
static bool all_data_transferred(void) | ||
{ | ||
size_t total_sdu_count = 0; | ||
|
||
total_sdu_count += tester.sdu_count; | ||
|
||
TEST_ASSERT(total_sdu_count <= SDU_NUM, "Received more SDUs than expected"); | ||
|
||
return total_sdu_count == SDU_NUM; | ||
} | ||
|
||
void entrypoint_dut(void) | ||
{ | ||
/* Test reference counting in Host when using L2CAP -EINPROGRESS feature. | ||
* | ||
* Devices: | ||
* - `dut`: receives L2CAP PDUs from tester | ||
* - `tester`: send L2CAP packets | ||
* | ||
* Procedure: | ||
* | ||
* DUT: | ||
* - establish connection to tester | ||
* - [acl connected] | ||
* - establish L2CAP channel | ||
* - [l2 connected] | ||
* - receive one L2CAP SDU, returning EINPROGRESS | ||
* - monitor that our SDU reference is respected | ||
* - return the buf to the stack using bt_l2cap_chan_recv_complete | ||
* - mark test as passed and terminate simulation | ||
* | ||
* tester 0: | ||
* - scan & connect ACL | ||
* - [acl connected] | ||
* - [l2cap dynamic channel connected] | ||
* (and then in a loop) | ||
* - send part of L2CAP PDU | ||
* - wait a set amount of time | ||
* - exit loop when SDU_NUM sent | ||
* | ||
* [verdict] | ||
* - retained SDU buffer reference from recv() is respected by stack | ||
*/ | ||
int err; | ||
|
||
/* Mark test as in progress. */ | ||
TEST_START("dut"); | ||
|
||
/* Initialize Bluetooth */ | ||
err = bt_enable(NULL); | ||
TEST_ASSERT(err == 0, "Can't enable Bluetooth (err %d)", err); | ||
|
||
LOG_DBG("Bluetooth initialized"); | ||
|
||
int psm = l2cap_server_register(BT_SECURITY_L1); | ||
|
||
LOG_DBG("Registered server PSM %x", psm); | ||
|
||
LOG_DBG("Connecting tester"); | ||
tester.sdu_count = 0; | ||
tester.conn = connect_tester(); | ||
|
||
LOG_DBG("Connected all testers"); | ||
|
||
while (!all_data_transferred()) { | ||
/* Wait until we have received all expected data. */ | ||
k_sleep(K_MSEC(100)); | ||
|
||
struct net_buf *ack_buf = net_buf_get(&tester.ack_todo, K_NO_WAIT); | ||
if (ack_buf) { | ||
acl_pool_refs_held_remove(ack_buf); | ||
err = bt_l2cap_chan_recv_complete(&tester.le_chan.chan, ack_buf); | ||
TEST_ASSERT(!err); | ||
} | ||
} | ||
|
||
TEST_PASS_AND_EXIT("dut"); | ||
} |
Oops, something went wrong.