Skip to content

Commit

Permalink
Bluetooth: Host: Test L2CAP -EINPROGRESS feature
Browse files Browse the repository at this point in the history
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
alwa-nordic authored and henrikbrixandersen committed Oct 26, 2024
1 parent abeca24 commit 47325f8
Show file tree
Hide file tree
Showing 9 changed files with 343 additions and 0 deletions.
1 change: 1 addition & 0 deletions tests/bsim/bluetooth/host/l2cap/compile.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 24 additions & 0 deletions tests/bsim/bluetooth/host/l2cap/einprogress/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
)
13 changes: 13 additions & 0 deletions tests/bsim/bluetooth/host/l2cap/einprogress/compile.sh
Original file line number Diff line number Diff line change
@@ -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
25 changes: 25 additions & 0 deletions tests/bsim/bluetooth/host/l2cap/einprogress/prj.conf
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions tests/bsim/bluetooth/host/l2cap/einprogress/src/data.h
Original file line number Diff line number Diff line change
@@ -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_ */
124 changes: 124 additions & 0 deletions tests/bsim/bluetooth/host/l2cap/einprogress/src/dut.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/* 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/bluetooth/testing.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/addr.h>
#include <testlib/adv.h>
#include <testlib/conn.h>
#include <testlib/scan.h>

#include <babblekit/flags.h>
#include <babblekit/testcase.h>

#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[CONFIG_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 < 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");
}

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");
}
47 changes: 47 additions & 0 deletions tests/bsim/bluetooth/host/l2cap/einprogress/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* Copyright (c) 2024 Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/kernel.h>

#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;
}
72 changes: 72 additions & 0 deletions tests/bsim/bluetooth/host/l2cap/einprogress/src/tester.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/* 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/addr.h>
#include <testlib/adv.h>
#include <testlib/conn.h>
#include <testlib/scan.h>

#include <babblekit/flags.h>
#include <babblekit/testcase.h>

#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");
}
26 changes: 26 additions & 0 deletions tests/bsim/bluetooth/host/l2cap/einprogress/test_scripts/run.sh
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 47325f8

Please sign in to comment.