From 043de7da2a8aa9bd35d514f7192a9e3a159e04c0 Mon Sep 17 00:00:00 2001 From: Jonathan Rico Date: Thu, 8 Aug 2024 15:07:55 +0200 Subject: [PATCH] Bluetooth: Host: Add disconnection during TX fragmentation test Verifies that we don't leak connection references when the peer goes out of range whilst we are fragmenting and sending data to the controller. Signed-off-by: Jonathan Rico --- tests/bsim/bluetooth/host/compile.sh | 1 + .../host/misc/acl_tx_frag/CMakeLists.txt | 24 ++ .../host/misc/acl_tx_frag/compile.sh | 13 + .../bluetooth/host/misc/acl_tx_frag/prj.conf | 50 ++++ .../host/misc/acl_tx_frag/src/data.h | 22 ++ .../bluetooth/host/misc/acl_tx_frag/src/dut.c | 272 ++++++++++++++++++ .../host/misc/acl_tx_frag/src/main.c | 74 +++++ .../host/misc/acl_tx_frag/src/peer.c | 175 +++++++++++ .../host/misc/acl_tx_frag/test_scripts/run.sh | 29 ++ 9 files changed, 660 insertions(+) create mode 100644 tests/bsim/bluetooth/host/misc/acl_tx_frag/CMakeLists.txt create mode 100755 tests/bsim/bluetooth/host/misc/acl_tx_frag/compile.sh create mode 100644 tests/bsim/bluetooth/host/misc/acl_tx_frag/prj.conf create mode 100644 tests/bsim/bluetooth/host/misc/acl_tx_frag/src/data.h create mode 100644 tests/bsim/bluetooth/host/misc/acl_tx_frag/src/dut.c create mode 100644 tests/bsim/bluetooth/host/misc/acl_tx_frag/src/main.c create mode 100644 tests/bsim/bluetooth/host/misc/acl_tx_frag/src/peer.c create mode 100755 tests/bsim/bluetooth/host/misc/acl_tx_frag/test_scripts/run.sh diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index dfb637078c1..c78c7a735a3 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -31,6 +31,7 @@ run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/misc/hfc/compile.sh run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/misc/hfc_multilink/compile.sh app=tests/bsim/bluetooth/host/misc/unregister_conn_cb compile run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/misc/sample_test/compile.sh +run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/misc/acl_tx_frag/compile.sh run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/privacy/central/compile.sh run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/privacy/peripheral/compile.sh diff --git a/tests/bsim/bluetooth/host/misc/acl_tx_frag/CMakeLists.txt b/tests/bsim/bluetooth/host/misc/acl_tx_frag/CMakeLists.txt new file mode 100644 index 00000000000..cab9cacea3c --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/acl_tx_frag/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(acl_tx_frag) + +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/peer.c +) diff --git a/tests/bsim/bluetooth/host/misc/acl_tx_frag/compile.sh b/tests/bsim/bluetooth/host/misc/acl_tx_frag/compile.sh new file mode 100755 index 00000000000..e717a4b2bbe --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/acl_tx_frag/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/misc/acl_tx_frag/prj.conf b/tests/bsim/bluetooth/host/misc/acl_tx_frag/prj.conf new file mode 100644 index 00000000000..6bd02c8b645 --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/acl_tx_frag/prj.conf @@ -0,0 +1,50 @@ +CONFIG_BT=y +CONFIG_BT_DEVICE_NAME="acl_tx_frag" +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y + +# Dependency of testlib/adv and testlib/scan. +CONFIG_BT_EXT_ADV=y + +CONFIG_BT_GATT_CLIENT=y +CONFIG_BT_GATT_AUTO_DISCOVER_CCC=y + +CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION=n + +CONFIG_ASSERT=y +CONFIG_LOG=y +CONFIG_LOG_RUNTIME_FILTERING=y +CONFIG_THREAD_NAME=y +CONFIG_LOG_THREAD_ID_PREFIX=y +CONFIG_ARCH_POSIX_TRAP_ON_FATAL=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=1 + +# We don't want to be constrained on the number of TX +# contexts, rather on the number of LL TX buffers. +CONFIG_BT_CONN_TX_MAX=10 + +# Outgoing ATT buffers +CONFIG_BT_ATT_TX_COUNT=1 + +# Allow big ATT MTU +CONFIG_BT_BUF_ACL_RX_SIZE=100 +CONFIG_BT_L2CAP_TX_MTU=100 + +# Controller buffers +CONFIG_BT_BUF_ACL_TX_COUNT=1 +CONFIG_BT_BUF_ACL_TX_SIZE=27 + +# If we don't define this, it will inherit +# CONFIG_BT_BUF_ACL_TX_COUNT and fail a build assert that +# expects >= 3. +CONFIG_BT_L2CAP_TX_BUF_COUNT=3 + +# For indication param structs. It's fine, we run on native. +CONFIG_HEAP_MEM_POOL_SIZE=1024 diff --git a/tests/bsim/bluetooth/host/misc/acl_tx_frag/src/data.h b/tests/bsim/bluetooth/host/misc/acl_tx_frag/src/data.h new file mode 100644 index 00000000000..59912b25eef --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/acl_tx_frag/src/data.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_TESTS_BSIM_BLUETOOTH_HOST_MISC_ACL_TX_FRAG_SRC_DATA_H_ +#define ZEPHYR_TESTS_BSIM_BLUETOOTH_HOST_MISC_ACL_TX_FRAG_SRC_DATA_H_ + +#include + +#define TEST_ITERATIONS 3 + +/* overhead: opcode + ATT handle + L2CAP PDU header */ +#define GATT_PAYLOAD_SIZE (CONFIG_BT_L2CAP_TX_MTU - 1 - 2 - 4) + +#define test_service_uuid \ + BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0xf0debc9a, 0x7856, 0x3412, 0x7856, 0x341278563412)) +#define test_characteristic_uuid \ + BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0xf2debc9a, 0x7856, 0x3412, 0x7856, 0x341278563412)) + +#endif /* ZEPHYR_TESTS_BSIM_BLUETOOTH_HOST_MISC_ACL_TX_FRAG_SRC_DATA_H_ */ diff --git a/tests/bsim/bluetooth/host/misc/acl_tx_frag/src/dut.c b/tests/bsim/bluetooth/host/misc/acl_tx_frag/src/dut.c new file mode 100644 index 00000000000..6fe11230201 --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/acl_tx_frag/src/dut.c @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "testlib/conn.h" +#include "testlib/scan.h" +#include "testlib/log_utils.h" + +#include "babblekit/flags.h" +#include "babblekit/testcase.h" + +/* For the radio shenanigans */ +#include "hw_testcheat_if.h" + +/* local includes */ +#include "data.h" + +LOG_MODULE_REGISTER(dut, LOG_LEVEL_DBG); + +static DEFINE_FLAG(is_subscribed); +static DEFINE_FLAG(mtu_has_been_exchanged); +static DEFINE_FLAG(conn_recycled); +static DEFINE_FLAG(conn_param_updated); +static DEFINE_FLAG(indicated); + +extern unsigned long runtime_log_level; + +static void recycled(void) +{ + LOG_DBG(""); + SET_FLAG(conn_recycled); +} + +static void params_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, + uint16_t timeout) +{ + LOG_DBG(""); + SET_FLAG(conn_param_updated); +} + +static struct bt_conn_cb conn_cbs = { + .recycled = recycled, + .le_param_updated = params_updated, +}; + +static void ccc_changed(const struct bt_gatt_attr *attr, uint16_t value) +{ + /* assume we only get it for the `test_gatt_service` */ + if (value != 0) { + SET_FLAG(is_subscribed); + } else { + UNSET_FLAG(is_subscribed); + } +} + +BT_GATT_SERVICE_DEFINE(test_gatt_service, BT_GATT_PRIMARY_SERVICE(test_service_uuid), + BT_GATT_CHARACTERISTIC(test_characteristic_uuid, + (BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | + BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_INDICATE), + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, NULL, NULL, + NULL), + BT_GATT_CCC(ccc_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE)); + +static void _mtu_exchanged(struct bt_conn *conn, uint8_t err, + struct bt_gatt_exchange_params *params) +{ + LOG_DBG("MTU exchanged"); + SET_FLAG(mtu_has_been_exchanged); +} + +static void exchange_mtu(struct bt_conn *conn) +{ + int err; + struct bt_gatt_exchange_params params = { + .func = _mtu_exchanged, + }; + + UNSET_FLAG(mtu_has_been_exchanged); + + err = bt_gatt_exchange_mtu(conn, ¶ms); + TEST_ASSERT(!err, "Failed MTU exchange (err %d)", err); + + WAIT_FOR_FLAG(mtu_has_been_exchanged); +} + +#define UPDATE_PARAM_INTERVAL_MIN 500 +#define UPDATE_PARAM_INTERVAL_MAX 500 +#define UPDATE_PARAM_LATENCY 1 +#define UPDATE_PARAM_TIMEOUT 1000 + +static struct bt_le_conn_param update_params = { + .interval_min = UPDATE_PARAM_INTERVAL_MIN, + .interval_max = UPDATE_PARAM_INTERVAL_MAX, + .latency = UPDATE_PARAM_LATENCY, + .timeout = UPDATE_PARAM_TIMEOUT, +}; + +void slow_down_conn(struct bt_conn *conn) +{ + int err; + + UNSET_FLAG(conn_param_updated); + err = bt_conn_le_param_update(conn, &update_params); + TEST_ASSERT(!err, "Parameter update failed (err %d)", err); + WAIT_FOR_FLAG(conn_param_updated); +} + +static void make_peer_go_out_of_range(void) +{ + hw_radio_testcheat_set_tx_power_gain(-300); + hw_radio_testcheat_set_rx_power_gain(-300); +} + +static void make_peer_go_back_in_range(void) +{ + hw_radio_testcheat_set_tx_power_gain(+300); + hw_radio_testcheat_set_rx_power_gain(+300); +} + +void indicated_cb(struct bt_conn *conn, struct bt_gatt_indicate_params *params, uint8_t err) +{ + SET_FLAG(indicated); +} + +static void params_struct_freed_cb(struct bt_gatt_indicate_params *params) +{ + k_free(params); +} + +static int send_indication(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *data, + uint16_t len) +{ + struct bt_gatt_indicate_params *params = k_malloc(sizeof(struct bt_gatt_indicate_params)); + + params->attr = attr; + params->func = indicated_cb; + params->destroy = params_struct_freed_cb; + params->data = data; + params->len = len; + + return bt_gatt_indicate(conn, params); +} + +static const uint8_t notification_data[GATT_PAYLOAD_SIZE]; + +static void test_iteration(bt_addr_le_t *peer) +{ + int err; + struct bt_conn *conn = NULL; + const struct bt_gatt_attr *attr; + + /* Create a connection using that address */ + err = bt_testlib_connect(peer, &conn); + TEST_ASSERT(!err, "Failed to initiate connection (err %d)", err); + + LOG_DBG("Connected"); + + LOG_INF("Wait until peer subscribes"); + UNSET_FLAG(is_subscribed); + WAIT_FOR_FLAG(is_subscribed); + + /* Prepare data for notifications + * attrs[0] is our service declaration + * attrs[1] is our characteristic declaration + * attrs[2] is our characteristic value + * + * We store a pointer for the characteristic value as that is the + * value we want to notify later. + * + * We could alternatively use `bt_gatt_notify_uuid()`. + */ + attr = &test_gatt_service.attrs[2]; + + exchange_mtu(conn); + + slow_down_conn(conn); + LOG_DBG("Updated params"); + + LOG_INF("Send indication #1"); + UNSET_FLAG(indicated); + err = send_indication(conn, attr, notification_data, sizeof(notification_data)); + TEST_ASSERT(!err, "Failed to send notification: err %d", err); + LOG_DBG("Wait until peer confirms our first indication"); + WAIT_FOR_FLAG(indicated); + + LOG_INF("Send indication #2"); + UNSET_FLAG(indicated); + err = send_indication(conn, attr, notification_data, sizeof(notification_data)); + TEST_ASSERT(!err, "Failed to send notification: err %d", err); + + LOG_DBG("Simulate RF connection loss"); + UNSET_FLAG(conn_recycled); + make_peer_go_out_of_range(); + + /* We will not access conn after this: give back our initial ref. */ + bt_testlib_conn_unref(&conn); + WAIT_FOR_FLAG(conn_recycled); + + LOG_DBG("Connection object has been destroyed as expected"); + make_peer_go_back_in_range(); +} + +void entrypoint_dut(void) +{ + /* Test purpose: + * + * Verifies that we don't leak resources or mess up host state when a + * disconnection happens whilst the host is transmitting ACL fragments. + * + * To achieve that, we use the BabbleSim magic modem (see run.sh) to cut + * the RF link before we have sent all the ACL fragments the peer. We do + * want to send multiple fragments to the controller though, the + * important part is that the peer does not acknowledge them, so that + * the disconnection happens while the controller has its TX buffers + * full. + * + * Two devices: + * - `dut`: the device whose host we are testing + * - `peer`: anime side-character. not important. + * + * Procedure (for n iterations): + * - [dut] establish connection to `peer` + * - [peer] discover GATT and subscribe to the test characteristic + * - [dut] send long indication + * - [peer] wait for confirmation of indication + * - [dut] send another long indication + * - [dut] disconnect + * + * [verdict] + * - All test cycles complete + */ + int err; + bt_addr_le_t peer = {}; + + /* Mark test as in progress. */ + TEST_START("dut"); + + /* Set the log level given by the `log_level` CLI argument */ + bt_testlib_log_level_set("dut", runtime_log_level); + + /* Initialize Bluetooth */ + bt_conn_cb_register(&conn_cbs); + err = bt_enable(NULL); + TEST_ASSERT(err == 0, "Can't enable Bluetooth (err %d)", err); + + LOG_DBG("Bluetooth initialized"); + + /* Find the address of the peer. In our case, both devices are actually + * the same executable (with the same config) but executed with + * different arguments. We can then just use CONFIG_BT_DEVICE_NAME which + * contains our device name in string form. + */ + err = bt_testlib_scan_find_name(&peer, CONFIG_BT_DEVICE_NAME); + TEST_ASSERT(!err, "Failed to start scan (err %d)", err); + + for (int i = 0; i < TEST_ITERATIONS; i++) { + LOG_INF("## Iteration %d", i); + test_iteration(&peer); + } + + TEST_PASS("dut"); +} diff --git a/tests/bsim/bluetooth/host/misc/acl_tx_frag/src/main.c b/tests/bsim/bluetooth/host/misc/acl_tx_frag/src/main.c new file mode 100644 index 00000000000..9afd99d7355 --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/acl_tx_frag/src/main.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "bs_tracing.h" +#include "bstests.h" +#include "babblekit/testcase.h" +#include "testlib/log_utils.h" + +extern void entrypoint_dut(void); +extern void entrypoint_peer(void); +extern enum bst_result_t bst_result; + +unsigned long runtime_log_level = LOG_LEVEL_INF; + +static void test_args(int argc, char *argv[]) +{ + size_t argn = 0; + const char *arg = argv[argn]; + + if (strcmp(arg, "log_level") == 0) { + + runtime_log_level = strtoul(argv[++argn], NULL, 10); + + if (runtime_log_level >= LOG_LEVEL_NONE && runtime_log_level <= LOG_LEVEL_DBG) { + TEST_PRINT("Runtime log level configuration: %d", runtime_log_level); + } else { + TEST_FAIL("Invalid arguments to set log level: %d", runtime_log_level); + } + } else { + TEST_PRINT("Default runtime log level configuration: INFO"); + } +} + +static void test_end_cb(void) +{ + if (bst_result != Passed) { + TEST_FAIL("Test has not passed."); + } +} + +static const struct bst_test_instance entrypoints[] = { + { + .test_id = "dut", + .test_delete_f = test_end_cb, + .test_main_f = entrypoint_dut, + .test_args_f = test_args, + }, + { + .test_id = "peer", + .test_delete_f = test_end_cb, + .test_main_f = entrypoint_peer, + .test_args_f = test_args, + }, + 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/misc/acl_tx_frag/src/peer.c b/tests/bsim/bluetooth/host/misc/acl_tx_frag/src/peer.c new file mode 100644 index 00000000000..7b40d995b9d --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/acl_tx_frag/src/peer.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "testlib/adv.h" +#include "testlib/att_read.h" +#include "testlib/att_write.h" +#include "testlib/conn.h" +#include "testlib/log_utils.h" + +#include "babblekit/flags.h" +#include "babblekit/testcase.h" + +/* local includes */ +#include "data.h" + +LOG_MODULE_REGISTER(peer, LOG_LEVEL_DBG); + +static DEFINE_FLAG(is_subscribed); +static DEFINE_FLAG(got_notification_1); + +extern unsigned long runtime_log_level; + +int find_characteristic(struct bt_conn *conn, const struct bt_uuid *svc, const struct bt_uuid *chrc, + uint16_t *chrc_value_handle) +{ + uint16_t svc_handle; + uint16_t svc_end_handle; + uint16_t chrc_end_handle; + int err; + + LOG_DBG(""); + + err = bt_testlib_gatt_discover_primary(&svc_handle, &svc_end_handle, conn, svc, + BT_ATT_FIRST_ATTRIBUTE_HANDLE, + BT_ATT_LAST_ATTRIBUTE_HANDLE); + if (err != 0) { + LOG_ERR("Failed to discover service: %d", err); + + return err; + } + + LOG_DBG("svc_handle: %u, svc_end_handle: %u", svc_handle, svc_end_handle); + + err = bt_testlib_gatt_discover_characteristic(chrc_value_handle, &chrc_end_handle, NULL, + conn, chrc, (svc_handle + 1), svc_end_handle); + if (err != 0) { + LOG_ERR("Failed to get value handle: %d", err); + + return err; + } + + LOG_DBG("chrc_value_handle: %u, chrc_end_handle: %u", *chrc_value_handle, chrc_end_handle); + + return err; +} + +static uint8_t received_notification(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, + const void *data, uint16_t length) +{ + if (length) { + LOG_INF("RX notification"); + LOG_HEXDUMP_DBG(data, length, "payload"); + SET_FLAG(got_notification_1); + + TEST_ASSERT(length == GATT_PAYLOAD_SIZE, "Unexpected length: %d", length); + } + + return BT_GATT_ITER_CONTINUE; +} + +static void sub_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_subscribe_params *params) +{ + TEST_ASSERT(!err, "Subscribe failed (err %d)", err); + + TEST_ASSERT(params, "params is NULL"); + TEST_ASSERT(params->value, "Host shouldn't know we have unsubscribed"); + + LOG_DBG("Subscribed to handle 0x%04x", params->value_handle); + SET_FLAG(is_subscribed); +} + +/* Subscription parameters have the same lifetime as a subscription. + * That is the backing struct should stay valid until a call to + * `bt_gatt_unsubscribe()` is made. Hence the `static`. + */ +static struct bt_gatt_subscribe_params sub_params; + +/* This is "working memory" used by the `CONFIG_BT_GATT_AUTO_DISCOVER_CCC` + * feature. It also has to stay valid until the end of the async call. + */ +static struct bt_gatt_discover_params ccc_disc_params; + +static void subscribe(struct bt_conn *conn, uint16_t handle, bt_gatt_notify_func_t cb) +{ + int err; + + /* Subscribe to notifications */ + sub_params.notify = cb; + sub_params.subscribe = sub_cb; + sub_params.value = BT_GATT_CCC_INDICATE; + sub_params.value_handle = handle; + + /* Set-up auto-discovery of the CCC handle */ + sub_params.ccc_handle = 0; + sub_params.disc_params = &ccc_disc_params; + sub_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + + err = bt_gatt_subscribe(conn, &sub_params); + TEST_ASSERT(!err, "Subscribe failed (err %d)", err); + + WAIT_FOR_FLAG(is_subscribed); +} + +static uint16_t g_handle; + +static void test_iteration(void) +{ + struct bt_conn *conn; + int err; + + err = bt_testlib_adv_conn(&conn, BT_ID_DEFAULT, bt_get_name()); + TEST_ASSERT(!err, "Failed to start connectable advertising (err %d)", err); + + if (g_handle) { + LOG_DBG("Re-use cached characteristic"); + } else { + LOG_DBG("Discover test characteristic"); + err = find_characteristic(conn, test_service_uuid, test_characteristic_uuid, + &g_handle); + TEST_ASSERT(!err, "Failed to find characteristic: %d", err); + } + + LOG_DBG("Subscribe to test characteristic: handle 0x%04x", g_handle); + subscribe(conn, g_handle, received_notification); + + WAIT_FOR_FLAG(got_notification_1); + + bt_testlib_wait_disconnected(conn); + bt_testlib_conn_unref(&conn); +} + +/* Read the comments on `entrypoint_dut()` first. */ +void entrypoint_peer(void) +{ + int err; + + /* Mark test as in progress. */ + TEST_START("peer"); + + /* Set the log level given by the `log_level` CLI argument */ + bt_testlib_log_level_set("peer", runtime_log_level); + + /* Initialize Bluetooth */ + err = bt_enable(NULL); + TEST_ASSERT(err == 0, "Can't enable Bluetooth (err %d)", err); + + LOG_DBG("Bluetooth initialized"); + + for (int i = 0; i < TEST_ITERATIONS; i++) { + LOG_INF("## Iteration %d", i); + test_iteration(); + } + + TEST_PASS_AND_EXIT("peer"); +} diff --git a/tests/bsim/bluetooth/host/misc/acl_tx_frag/test_scripts/run.sh b/tests/bsim/bluetooth/host/misc/acl_tx_frag/test_scripts/run.sh new file mode 100755 index 00000000000..91eee9a078e --- /dev/null +++ b/tests/bsim/bluetooth/host/misc/acl_tx_frag/test_scripts/run.sh @@ -0,0 +1,29 @@ +#!/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 + +# sixty-second (maximum) sim time. +# The test will exit simulation as soon as it has passed. +SIM_LEN_US=$((60 * 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 -rs=420 -testid=dut \ + -argstest log_level 3 +Execute "${test_exe}" -v=${verbosity_level} -s=${simulation_id} -d=1 -rs=69 -testid=peer \ + -argstest log_level 3 >/dev/null + +Execute ./bs_2G4_phy_v1 -defmodem=BLE_simple \ + -v=${verbosity_level} -s=${simulation_id} -D=2 -sim_length=${SIM_LEN_US} $@ + +wait_for_background_jobs