Skip to content

Commit f3dcaae

Browse files
theob-profabiobaltieri
authored andcommitted
Tests: Bluetooth: Add another ISO frag test
This test create a setup where an ISO broadcaster will send fragmented data and get stopped after sending the first fragment and repeating that operation multiple time to verify that buffers are not leaked. Signed-off-by: Théo Battrel <[email protected]>
1 parent 3a098c9 commit f3dcaae

File tree

8 files changed

+417
-1
lines changed

8 files changed

+417
-1
lines changed

subsys/bluetooth/host/hci_core.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4310,7 +4310,14 @@ k_tid_t bt_testing_tx_tid_get(void)
43104310
/* We now TX everything from the syswq */
43114311
return &k_sys_work_q.thread;
43124312
}
4313-
#endif
4313+
4314+
#if defined(CONFIG_BT_ISO)
4315+
void bt_testing_set_iso_mtu(uint16_t mtu)
4316+
{
4317+
bt_dev.le.iso_mtu = mtu;
4318+
}
4319+
#endif /* CONFIG_BT_ISO */
4320+
#endif /* CONFIG_BT_TESTING */
43144321

43154322
int bt_enable(bt_ready_cb_t cb)
43164323
{

tests/bsim/bluetooth/host/compile.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/security/compile.sh
2121
app=tests/bsim/bluetooth/host/iso/cis compile
2222
app=tests/bsim/bluetooth/host/iso/bis compile
2323
app=tests/bsim/bluetooth/host/iso/frag compile
24+
app=tests/bsim/bluetooth/host/iso/frag_2 compile
2425

2526
app=tests/bsim/bluetooth/host/misc/disable compile
2627
run_in_background ${ZEPHYR_BASE}/tests/bsim/bluetooth/host/misc/disconnect/compile.sh
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
5+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
6+
7+
project(bsim_test_iso_frag_2)
8+
9+
add_subdirectory(${ZEPHYR_BASE}/tests/bsim/babblekit babblekit)
10+
target_link_libraries(app PRIVATE babblekit)
11+
12+
target_sources(app PRIVATE
13+
src/broadcaster.c
14+
src/main.c
15+
)
16+
17+
zephyr_include_directories(
18+
${BSIM_COMPONENTS_PATH}/libUtilv1/src/
19+
${BSIM_COMPONENTS_PATH}/libPhyComv1/src/
20+
)
21+
22+
target_link_options(app PUBLIC -Wl,--wrap=bt_send)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
CONFIG_LOG=y
2+
CONFIG_BT_ISO_LOG_LEVEL_DBG=y
3+
# CONFIG_BT_CONN_LOG_LEVEL_DBG=y
4+
5+
CONFIG_ASSERT=y
6+
CONFIG_BT_TESTING=y
7+
CONFIG_ARCH_POSIX_TRAP_ON_FATAL=y
8+
9+
CONFIG_BT=y
10+
CONFIG_BT_DEVICE_NAME="ISO frag test 2"
11+
12+
CONFIG_BT_EXT_ADV=y
13+
CONFIG_BT_PER_ADV=y
14+
CONFIG_BT_PER_ADV_SYNC=y
15+
16+
CONFIG_BT_ISO_BROADCASTER=y
17+
CONFIG_BT_ISO_TX_BUF_COUNT=2
18+
CONFIG_BT_ISO_MAX_CHAN=2
19+
CONFIG_BT_ISO_TX_MTU=100
20+
CONFIG_BT_ISO_RX_MTU=100
21+
22+
# Controller ISO configs
23+
CONFIG_BT_CTLR_ADV_ISO=y
24+
CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=255
25+
CONFIG_BT_CTLR_ISO_TX_BUFFERS=10
26+
27+
# Controller Extended Advertising configs
28+
CONFIG_BT_CTLR_ADV_EXT=y
29+
CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191
30+
31+
# ISO Broadcaster Controller
32+
CONFIG_BT_CTLR_ADV_PERIODIC=y
33+
CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=247
Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/sys/byteorder.h>
8+
#include <zephyr/bluetooth/bluetooth.h>
9+
#include <zephyr/bluetooth/iso.h>
10+
#include <zephyr/logging/log.h>
11+
#include <zephyr/sys/byteorder.h>
12+
13+
#include "babblekit/flags.h"
14+
#include "babblekit/testcase.h"
15+
16+
LOG_MODULE_REGISTER(broadcaster, LOG_LEVEL_INF);
17+
18+
static struct bt_iso_chan iso_chans[CONFIG_BT_ISO_MAX_CHAN];
19+
static struct bt_iso_chan *default_chan = &iso_chans[0];
20+
21+
NET_BUF_POOL_FIXED_DEFINE(tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT,
22+
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU),
23+
CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
24+
25+
static DEFINE_FLAG(iso_connected);
26+
static DEFINE_FLAG(first_frag);
27+
static DEFINE_FLAG(sdu_sent);
28+
29+
extern void bt_conn_suspend_tx(bool suspend);
30+
extern void bt_testing_set_iso_mtu(uint16_t mtu);
31+
32+
static int send_data(struct bt_iso_chan *chan)
33+
{
34+
static uint16_t seq;
35+
struct net_buf *buf;
36+
int err;
37+
38+
if (!IS_FLAG_SET(iso_connected)) {
39+
/* TX has been aborted */
40+
return -ENOTCONN;
41+
}
42+
43+
buf = net_buf_alloc(&tx_pool, K_NO_WAIT);
44+
TEST_ASSERT(buf != NULL, "Failed to allocate buffer");
45+
46+
net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
47+
48+
net_buf_add(buf, 40);
49+
50+
LOG_INF("Sending SDU (headroom %d)", net_buf_headroom(buf));
51+
LOG_HEXDUMP_INF(buf->data, buf->len, "SDU payload");
52+
53+
err = bt_iso_chan_send(default_chan, buf, seq++);
54+
55+
return err;
56+
}
57+
58+
static void iso_connected_cb(struct bt_iso_chan *chan)
59+
{
60+
LOG_INF("ISO Channel %p connected", chan);
61+
62+
SET_FLAG(iso_connected);
63+
}
64+
65+
static void iso_disconnected_cb(struct bt_iso_chan *chan, uint8_t reason)
66+
{
67+
LOG_INF("ISO Channel %p disconnected (reason 0x%02x)", chan, reason);
68+
69+
UNSET_FLAG(iso_connected);
70+
}
71+
72+
static void sdu_sent_cb(struct bt_iso_chan *chan)
73+
{
74+
SET_FLAG(sdu_sent);
75+
}
76+
77+
static void create_ext_adv(struct bt_le_ext_adv **adv)
78+
{
79+
int err;
80+
81+
LOG_INF("Creating extended advertising set with periodic advertising");
82+
83+
/* Create a non-connectable advertising set */
84+
err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN, NULL, adv);
85+
TEST_ASSERT(err == 0, "Unable to create extended advertising set: %d", err);
86+
87+
/* Set periodic advertising parameters */
88+
err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_PARAM(BT_GAP_PER_ADV_FAST_INT_MIN_2,
89+
BT_GAP_PER_ADV_FAST_INT_MAX_2,
90+
BT_LE_PER_ADV_OPT_NONE));
91+
TEST_ASSERT(err == 0, "Failed to set periodic advertising parameters: %d", err);
92+
}
93+
94+
static void start_ext_adv(struct bt_le_ext_adv *adv)
95+
{
96+
int err;
97+
98+
LOG_INF("Starting extended and periodic advertising");
99+
100+
/* Start extended advertising */
101+
err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
102+
TEST_ASSERT(err == 0, "Failed to start extended advertising: %d", err);
103+
104+
/* FIXME: Temporary workaround to get around an assert in the controller
105+
* Open issue: https://github.com/zephyrproject-rtos/zephyr/issues/72852
106+
*/
107+
k_sleep(K_MSEC(100));
108+
109+
/* Enable Periodic Advertising */
110+
err = bt_le_per_adv_start(adv);
111+
TEST_ASSERT(err == 0, "Failed to enable periodic advertising: %d", err);
112+
}
113+
114+
static void create_big(struct bt_le_ext_adv *adv, size_t cnt, struct bt_iso_big **out_big)
115+
{
116+
const uint16_t latency_ms = 10U;
117+
const uint16_t sdu_interval_us = 10U * USEC_PER_MSEC;
118+
119+
struct bt_iso_chan *channels[ARRAY_SIZE(iso_chans)];
120+
struct bt_iso_big_create_param param = {
121+
.packing = BT_ISO_PACKING_SEQUENTIAL,
122+
.framing = BT_ISO_FRAMING_UNFRAMED,
123+
.interval = sdu_interval_us,
124+
.bis_channels = channels,
125+
.latency = latency_ms,
126+
.encryption = false,
127+
.num_bis = cnt,
128+
};
129+
int err;
130+
131+
for (size_t i = 0U; i < cnt; i++) {
132+
channels[i] = &iso_chans[i];
133+
}
134+
135+
LOG_INF("Creating BIG");
136+
137+
err = bt_iso_big_create(adv, &param, out_big);
138+
TEST_ASSERT(err == 0, "Failed to create BIG: %d", err);
139+
140+
WAIT_FOR_FLAG(iso_connected);
141+
}
142+
143+
struct bt_le_ext_adv *adv;
144+
struct bt_iso_big *big;
145+
146+
static struct bt_iso_chan_ops iso_ops = {
147+
.disconnected = iso_disconnected_cb,
148+
.connected = iso_connected_cb,
149+
.sent = sdu_sent_cb,
150+
};
151+
static struct bt_iso_chan_io_qos iso_tx = {
152+
.sdu = CONFIG_BT_ISO_TX_MTU,
153+
.phy = BT_GAP_LE_PHY_2M,
154+
.rtn = 1,
155+
.path = NULL,
156+
};
157+
static struct bt_iso_chan_qos iso_qos = {
158+
.tx = &iso_tx,
159+
.rx = NULL,
160+
};
161+
162+
static void init(void)
163+
{
164+
int err;
165+
166+
err = bt_enable(NULL);
167+
TEST_ASSERT(err == 0, "Bluetooth enable failed: %d", err);
168+
}
169+
170+
static void connect_iso(void)
171+
{
172+
bt_testing_set_iso_mtu(10);
173+
174+
for (size_t i = 0U; i < ARRAY_SIZE(iso_chans); i++) {
175+
iso_chans[i].ops = &iso_ops;
176+
iso_chans[i].qos = &iso_qos;
177+
}
178+
179+
create_ext_adv(&adv);
180+
create_big(adv, 1U, &big);
181+
start_ext_adv(adv);
182+
}
183+
184+
static void disconnect_iso(void)
185+
{
186+
int err;
187+
188+
err = bt_iso_big_terminate(big);
189+
TEST_ASSERT(err == 0, "bt_iso_big_terminate failed (%d)", err);
190+
err = bt_le_per_adv_stop(adv);
191+
TEST_ASSERT(err == 0, "bt_le_per_adv_stop failed (%d)", err);
192+
k_msleep(100);
193+
err = bt_le_ext_adv_stop(adv);
194+
TEST_ASSERT(err == 0, "bt_le_ext_adv_stop failed (%d)", err);
195+
k_msleep(100);
196+
err = bt_le_ext_adv_delete(adv);
197+
TEST_ASSERT(err == 0, "bt_le_ext_adv_delete failed (%d)", err);
198+
199+
big = NULL;
200+
adv = NULL;
201+
}
202+
203+
void entrypoint_broadcaster(void)
204+
{
205+
/* Test purpose:
206+
*
207+
* Verifies that we are not leaking buffers when getting disconnected
208+
* while sending fragmented ISO SDU.
209+
*
210+
* One device:
211+
* - `broadcaster`: sends fragmented ISO SDUs
212+
*
213+
* Procedure:
214+
* - initialize Bluetooth and a BIS
215+
* - send a fragmented SDU
216+
* - disconnect when the first fragment is sent
217+
* - repeat TEST_ITERATIONS time
218+
*
219+
* [verdict]
220+
* - no buffer is leaked and repeating the operation success
221+
*/
222+
int err;
223+
uint8_t TEST_ITERATIONS = 4;
224+
225+
LOG_INF("Starting ISO HCI fragmentation test 2");
226+
227+
init();
228+
229+
for (size_t i = 0; i < TEST_ITERATIONS; i++) {
230+
connect_iso();
231+
232+
/* Send an SDU */
233+
err = send_data(default_chan);
234+
TEST_ASSERT(!err, "Failed to send data w/o TS (err %d)", err);
235+
236+
/* Wait until we have sent the first SDU fragment. */
237+
WAIT_FOR_FLAG(first_frag);
238+
239+
disconnect_iso();
240+
bt_conn_suspend_tx(false);
241+
242+
k_msleep(1000);
243+
}
244+
245+
TEST_PASS_AND_EXIT("Test passed");
246+
}
247+
248+
void validate_no_iso_frag(struct net_buf *buf)
249+
{
250+
struct bt_hci_iso_hdr *hci_hdr = (void *)buf->data;
251+
252+
uint16_t handle = sys_le16_to_cpu(hci_hdr->handle);
253+
uint8_t flags = bt_iso_flags(handle);
254+
uint8_t pb_flag = bt_iso_flags_pb(flags);
255+
256+
TEST_ASSERT(pb_flag == BT_ISO_SINGLE, "Packet was fragmented");
257+
}
258+
259+
int __real_bt_send(struct net_buf *buf);
260+
261+
int __wrap_bt_send(struct net_buf *buf)
262+
{
263+
struct bt_hci_iso_hdr *hci_hdr = (void *)buf->data;
264+
265+
if (bt_buf_get_type(buf) == BT_BUF_ISO_OUT) {
266+
uint16_t handle = sys_le16_to_cpu(hci_hdr->handle);
267+
uint8_t flags = bt_iso_flags(handle);
268+
uint8_t pb_flag = bt_iso_flags_pb(flags);
269+
270+
if (pb_flag == BT_ISO_START) {
271+
SET_FLAG(first_frag);
272+
bt_conn_suspend_tx(true);
273+
}
274+
}
275+
276+
return __real_bt_send(buf);
277+
}

0 commit comments

Comments
 (0)