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 <jonathan.rico@nordicsemi.no>
This commit is contained in:
parent
9347887b33
commit
043de7da2a
9 changed files with 660 additions and 0 deletions
|
@ -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
|
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/misc/hfc_multilink/compile.sh
|
||||||
app=tests/bsim/bluetooth/host/misc/unregister_conn_cb compile
|
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/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/central/compile.sh
|
||||||
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/privacy/peripheral/compile.sh
|
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/privacy/peripheral/compile.sh
|
||||||
|
|
24
tests/bsim/bluetooth/host/misc/acl_tx_frag/CMakeLists.txt
Normal file
24
tests/bsim/bluetooth/host/misc/acl_tx_frag/CMakeLists.txt
Normal file
|
@ -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
|
||||||
|
)
|
13
tests/bsim/bluetooth/host/misc/acl_tx_frag/compile.sh
Executable file
13
tests/bsim/bluetooth/host/misc/acl_tx_frag/compile.sh
Executable file
|
@ -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
|
50
tests/bsim/bluetooth/host/misc/acl_tx_frag/prj.conf
Normal file
50
tests/bsim/bluetooth/host/misc/acl_tx_frag/prj.conf
Normal file
|
@ -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
|
22
tests/bsim/bluetooth/host/misc/acl_tx_frag/src/data.h
Normal file
22
tests/bsim/bluetooth/host/misc/acl_tx_frag/src/data.h
Normal file
|
@ -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 <zephyr/bluetooth/uuid.h>
|
||||||
|
|
||||||
|
#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_ */
|
272
tests/bsim/bluetooth/host/misc/acl_tx_frag/src/dut.c
Normal file
272
tests/bsim/bluetooth/host/misc/acl_tx_frag/src/dut.c
Normal file
|
@ -0,0 +1,272 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/sys/byteorder.h>
|
||||||
|
#include <zephyr/bluetooth/bluetooth.h>
|
||||||
|
#include <zephyr/bluetooth/conn.h>
|
||||||
|
#include <zephyr/bluetooth/l2cap.h>
|
||||||
|
#include <zephyr/bluetooth/gatt.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
|
#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");
|
||||||
|
}
|
74
tests/bsim/bluetooth/host/misc/acl_tx_frag/src/main.c
Normal file
74
tests/bsim/bluetooth/host/misc/acl_tx_frag/src/main.c
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
175
tests/bsim/bluetooth/host/misc/acl_tx_frag/src/peer.c
Normal file
175
tests/bsim/bluetooth/host/misc/acl_tx_frag/src/peer.c
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* 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/att.h>
|
||||||
|
#include <zephyr/bluetooth/gatt.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
|
#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");
|
||||||
|
}
|
29
tests/bsim/bluetooth/host/misc/acl_tx_frag/test_scripts/run.sh
Executable file
29
tests/bsim/bluetooth/host/misc/acl_tx_frag/test_scripts/run.sh
Executable file
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue