1 /* main_l2cap_stress.c - Application main entry point */
2
3 /*
4 * Copyright (c) 2022 Nordic Semiconductor
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <stddef.h>
10
11 #include <zephyr/types.h>
12 #include <zephyr/sys/util.h>
13 #include <zephyr/sys/byteorder.h>
14
15 #include <zephyr/bluetooth/bluetooth.h>
16 #include <zephyr/bluetooth/hci.h>
17 #include <zephyr/bluetooth/l2cap.h>
18 #include "babblekit/testcase.h"
19 #include "babblekit/flags.h"
20 #include "bsim_args_runner.h"
21
22 #define LOG_MODULE_NAME main
23 #include <zephyr/logging/log.h>
24 LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF);
25
26 DEFINE_FLAG_STATIC(is_connected);
27 DEFINE_FLAG_STATIC(flag_l2cap_connected);
28
29 #define NUM_PERIPHERALS 6
30 #define L2CAP_CHANS NUM_PERIPHERALS
31 #define SDU_NUM 20
32 #define SDU_LEN 3000
33 #define RESCHEDULE_DELAY K_MSEC(100)
34
35 /* The early_disconnect test has the peripheral disconnect at various
36 * times:
37 *
38 * Peripheral 1: disconnects after all 20 SDUs as before
39 * Peripheral 2: disconnects immediately before receiving anything
40 * Peripheral 3: disconnects after receiving first SDU
41 * Peripheral 4: disconnects after receiving first PDU in second SDU
42 * Peripheral 5: disconnects after receiving third PDU in third SDU
43 * Peripheral 6: disconnects atfer receiving tenth PDU in tenth SDU
44 */
45 static unsigned int device_nbr;
46
sdu_destroy(struct net_buf * buf)47 static void sdu_destroy(struct net_buf *buf)
48 {
49 LOG_DBG("%p", buf);
50
51 net_buf_destroy(buf);
52 }
53
rx_destroy(struct net_buf * buf)54 static void rx_destroy(struct net_buf *buf)
55 {
56 LOG_DBG("%p", buf);
57
58 net_buf_destroy(buf);
59 }
60
61 /* Only one SDU per link will be transmitted at a time */
62 NET_BUF_POOL_DEFINE(sdu_tx_pool,
63 CONFIG_BT_MAX_CONN, BT_L2CAP_SDU_BUF_SIZE(SDU_LEN),
64 CONFIG_BT_CONN_TX_USER_DATA_SIZE, sdu_destroy);
65
66 /* Only one SDU per link will be received at a time */
67 NET_BUF_POOL_DEFINE(sdu_rx_pool,
68 CONFIG_BT_MAX_CONN, BT_L2CAP_SDU_BUF_SIZE(SDU_LEN),
69 8, rx_destroy);
70
71 static uint8_t tx_data[SDU_LEN];
72 static uint16_t sdu_rx_cnt;
73 static uint8_t disconnect_counter;
74
75 struct test_ctx {
76 struct k_work_delayable work_item;
77 struct bt_l2cap_le_chan le_chan;
78 size_t tx_left;
79 };
80
81 static struct test_ctx contexts[L2CAP_CHANS];
82
get_ctx(struct bt_l2cap_chan * chan)83 struct test_ctx *get_ctx(struct bt_l2cap_chan *chan)
84 {
85 struct bt_l2cap_le_chan *le_chan = CONTAINER_OF(chan, struct bt_l2cap_le_chan, chan);
86 struct test_ctx *ctx = CONTAINER_OF(le_chan, struct test_ctx, le_chan);
87
88 TEST_ASSERT(ctx >= &contexts[0] && ctx <= &contexts[L2CAP_CHANS], "memory corruption");
89
90 return ctx;
91 }
92
l2cap_chan_send(struct bt_l2cap_chan * chan,uint8_t * data,size_t len)93 int l2cap_chan_send(struct bt_l2cap_chan *chan, uint8_t *data, size_t len)
94 {
95 LOG_DBG("chan %p conn %u data %p len %d", chan, bt_conn_index(chan->conn), data, len);
96
97 struct net_buf *buf = net_buf_alloc(&sdu_tx_pool, K_NO_WAIT);
98
99 if (buf == NULL) {
100 TEST_FAIL("No more memory");
101 return -ENOMEM;
102 }
103
104 net_buf_reserve(buf, BT_L2CAP_SDU_CHAN_SEND_RESERVE);
105 net_buf_add_mem(buf, data, len);
106
107 int ret = bt_l2cap_chan_send(chan, buf);
108
109 if (ret == -EAGAIN) {
110 LOG_DBG("L2CAP error %d, attempting to reschedule sending", ret);
111 net_buf_unref(buf);
112 k_work_reschedule(&(get_ctx(chan)->work_item), RESCHEDULE_DELAY);
113
114 return ret;
115 }
116
117 TEST_ASSERT(ret >= 0, "Failed sending: err %d", ret);
118
119 LOG_DBG("sent %d len %d", ret, len);
120 return ret;
121 }
122
alloc_buf_cb(struct bt_l2cap_chan * chan)123 struct net_buf *alloc_buf_cb(struct bt_l2cap_chan *chan)
124 {
125 return net_buf_alloc(&sdu_rx_pool, K_NO_WAIT);
126 }
127
continue_sending(struct test_ctx * ctx)128 void continue_sending(struct test_ctx *ctx)
129 {
130 struct bt_l2cap_chan *chan = &ctx->le_chan.chan;
131
132 LOG_DBG("%p, left %d", chan, ctx->tx_left);
133
134 if (ctx->tx_left) {
135 l2cap_chan_send(chan, tx_data, sizeof(tx_data));
136 } else {
137 LOG_DBG("Done sending %u", bt_conn_index(chan->conn));
138 }
139 }
140
sent_cb(struct bt_l2cap_chan * chan)141 void sent_cb(struct bt_l2cap_chan *chan)
142 {
143 struct test_ctx *ctx = get_ctx(chan);
144
145 LOG_DBG("%p", chan);
146
147 if (ctx->tx_left) {
148 ctx->tx_left--;
149 }
150
151 continue_sending(ctx);
152 }
153
154 #ifdef CONFIG_BT_L2CAP_SEG_RECV
disconnect_device_no_wait(struct bt_conn * conn,void * data)155 static void disconnect_device_no_wait(struct bt_conn *conn, void *data)
156 {
157 int err;
158
159 err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
160 TEST_ASSERT(!err, "Failed to initate disconnect (err %d)", err);
161
162 UNSET_FLAG(is_connected);
163 }
164
seg_recv_cb(struct bt_l2cap_chan * chan,size_t sdu_len,off_t seg_offset,struct net_buf_simple * seg)165 static void seg_recv_cb(struct bt_l2cap_chan *chan, size_t sdu_len, off_t seg_offset,
166 struct net_buf_simple *seg)
167 {
168 static size_t pdu_rx_cnt;
169
170 if ((seg_offset + seg->len) == sdu_len) {
171 /* last segment/PDU of a SDU */
172 LOG_DBG("len %d", seg->len);
173 sdu_rx_cnt++;
174 pdu_rx_cnt = 0;
175 } else {
176 LOG_DBG("SDU %u, pdu %u at seg_offset %u, len %u",
177 sdu_rx_cnt, pdu_rx_cnt, seg_offset, seg->len);
178 pdu_rx_cnt++;
179 }
180
181 /* Verify SDU data matches TX'd data. */
182 int pos = memcmp(seg->data, &tx_data[seg_offset], seg->len);
183
184 if (pos != 0) {
185 LOG_ERR("RX data doesn't match TX: pos %d", seg_offset);
186 LOG_HEXDUMP_ERR(seg->data, seg->len, "RX data");
187 LOG_HEXDUMP_INF(tx_data, seg->len, "TX data");
188
189 for (uint16_t p = 0; p < seg->len; p++) {
190 __ASSERT(seg->data[p] == tx_data[p + seg_offset],
191 "Failed rx[%d]=%x != expect[%d]=%x",
192 p, seg->data[p], p, tx_data[p + seg_offset]);
193 }
194 }
195
196 if (((device_nbr == 4) && (sdu_rx_cnt >= 1) && (pdu_rx_cnt == 1)) ||
197 ((device_nbr == 5) && (sdu_rx_cnt >= 2) && (pdu_rx_cnt == 3)) ||
198 ((device_nbr == 6) && (sdu_rx_cnt >= 9) && (pdu_rx_cnt == 10))) {
199 LOG_INF("disconnecting after receiving PDU %u of SDU %u",
200 pdu_rx_cnt - 1, sdu_rx_cnt);
201 bt_conn_foreach(BT_CONN_TYPE_LE, disconnect_device_no_wait, NULL);
202 return;
203 }
204
205 if (is_connected) {
206 bt_l2cap_chan_give_credits(chan, 1);
207 }
208 }
209 #else /* CONFIG_BT_L2CAP_SEG_RECV */
recv_cb(struct bt_l2cap_chan * chan,struct net_buf * buf)210 int recv_cb(struct bt_l2cap_chan *chan, struct net_buf *buf)
211 {
212 LOG_DBG("len %d", buf->len);
213 sdu_rx_cnt++;
214
215 /* Verify SDU data matches TX'd data. */
216 int pos = memcmp(buf->data, tx_data, buf->len);
217
218 if (pos != 0) {
219 LOG_ERR("RX data doesn't match TX: pos %d", pos);
220 LOG_HEXDUMP_ERR(buf->data, buf->len, "RX data");
221 LOG_HEXDUMP_INF(tx_data, buf->len, "TX data");
222
223 for (uint16_t p = 0; p < buf->len; p++) {
224 __ASSERT(buf->data[p] == tx_data[p],
225 "Failed rx[%d]=%x != expect[%d]=%x",
226 p, buf->data[p], p, tx_data[p]);
227 }
228 }
229
230 return 0;
231 }
232 #endif /* CONFIG_BT_L2CAP_SEG_RECV */
233
l2cap_chan_connected_cb(struct bt_l2cap_chan * l2cap_chan)234 void l2cap_chan_connected_cb(struct bt_l2cap_chan *l2cap_chan)
235 {
236 struct bt_l2cap_le_chan *chan =
237 CONTAINER_OF(l2cap_chan, struct bt_l2cap_le_chan, chan);
238
239 SET_FLAG(flag_l2cap_connected);
240 LOG_DBG("%x (tx mtu %d mps %d cr %ld) (tx mtu %d mps %d cr %ld)",
241 l2cap_chan,
242 chan->tx.mtu,
243 chan->tx.mps,
244 atomic_get(&chan->tx.credits),
245 chan->rx.mtu,
246 chan->rx.mps,
247 atomic_get(&chan->rx.credits));
248 }
249
l2cap_chan_disconnected_cb(struct bt_l2cap_chan * l2cap_chan)250 void l2cap_chan_disconnected_cb(struct bt_l2cap_chan *l2cap_chan)
251 {
252 UNSET_FLAG(flag_l2cap_connected);
253 LOG_DBG("%p", l2cap_chan);
254 for (int i = 0; i < L2CAP_CHANS; i++) {
255 if (&contexts[i].le_chan == CONTAINER_OF(l2cap_chan,
256 struct bt_l2cap_le_chan, chan)) {
257 if (contexts[i].tx_left > 0) {
258 LOG_INF("setting tx_left to 0 because of disconnect");
259 contexts[i].tx_left = 0;
260 }
261 break;
262 }
263 }
264 }
265
266 static struct bt_l2cap_chan_ops ops = {
267 .connected = l2cap_chan_connected_cb,
268 .disconnected = l2cap_chan_disconnected_cb,
269 .alloc_buf = alloc_buf_cb,
270 #ifdef CONFIG_BT_L2CAP_SEG_RECV
271 .seg_recv = seg_recv_cb,
272 #else
273 .recv = recv_cb,
274 #endif
275 .sent = sent_cb,
276 };
277
deferred_send(struct k_work * item)278 void deferred_send(struct k_work *item)
279 {
280 struct test_ctx *ctx = CONTAINER_OF(k_work_delayable_from_work(item),
281 struct test_ctx, work_item);
282
283 struct bt_l2cap_chan *chan = &ctx->le_chan.chan;
284
285 LOG_DBG("continue %u left %d", bt_conn_index(chan->conn), ctx->tx_left);
286
287 continue_sending(ctx);
288 }
289
alloc_test_context(void)290 struct test_ctx *alloc_test_context(void)
291 {
292 for (int i = 0; i < L2CAP_CHANS; i++) {
293 struct bt_l2cap_le_chan *le_chan = &contexts[i].le_chan;
294
295 if (le_chan->state != BT_L2CAP_DISCONNECTED) {
296 continue;
297 }
298
299 memset(&contexts[i], 0, sizeof(struct test_ctx));
300 k_work_init_delayable(&contexts[i].work_item, deferred_send);
301
302 return &contexts[i];
303 }
304
305 return NULL;
306 }
307
server_accept_cb(struct bt_conn * conn,struct bt_l2cap_server * server,struct bt_l2cap_chan ** chan)308 int server_accept_cb(struct bt_conn *conn, struct bt_l2cap_server *server,
309 struct bt_l2cap_chan **chan)
310 {
311 struct test_ctx *ctx = NULL;
312
313 ctx = alloc_test_context();
314 if (ctx == NULL) {
315 return -ENOMEM;
316 }
317
318 struct bt_l2cap_le_chan *le_chan = &ctx->le_chan;
319
320 memset(le_chan, 0, sizeof(*le_chan));
321 le_chan->chan.ops = &ops;
322 le_chan->rx.mtu = SDU_LEN;
323 #ifdef CONFIG_BT_L2CAP_SEG_RECV
324 le_chan->rx.mps = BT_L2CAP_RX_MTU;
325 le_chan->rx.credits = CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA;
326 #endif
327 *chan = &le_chan->chan;
328
329 return 0;
330 }
331
332 static struct bt_l2cap_server test_l2cap_server = {
333 .accept = server_accept_cb
334 };
335
l2cap_server_register(bt_security_t sec_level)336 static int l2cap_server_register(bt_security_t sec_level)
337 {
338 test_l2cap_server.psm = 0;
339 test_l2cap_server.sec_level = sec_level;
340
341 int err = bt_l2cap_server_register(&test_l2cap_server);
342
343 TEST_ASSERT(err == 0, "Failed to register l2cap server.");
344
345 return test_l2cap_server.psm;
346 }
347
connected(struct bt_conn * conn,uint8_t conn_err)348 static void connected(struct bt_conn *conn, uint8_t conn_err)
349 {
350 char addr[BT_ADDR_LE_STR_LEN];
351
352 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
353
354 if (conn_err) {
355 TEST_FAIL("Failed to connect to %s (%u)", addr, conn_err);
356 return;
357 }
358
359 LOG_DBG("%s", addr);
360
361 SET_FLAG(is_connected);
362 }
363
disconnected(struct bt_conn * conn,uint8_t reason)364 static void disconnected(struct bt_conn *conn, uint8_t reason)
365 {
366 char addr[BT_ADDR_LE_STR_LEN];
367
368 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
369
370 LOG_DBG("%p %s (reason 0x%02x)", conn, addr, reason);
371
372 UNSET_FLAG(is_connected);
373 disconnect_counter++;
374 }
375
376 BT_CONN_CB_DEFINE(conn_callbacks) = {
377 .connected = connected,
378 .disconnected = disconnected,
379 };
380
disconnect_device(struct bt_conn * conn,void * data)381 static void disconnect_device(struct bt_conn *conn, void *data)
382 {
383 int err;
384
385 SET_FLAG(is_connected);
386
387 err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
388 TEST_ASSERT(!err, "Failed to initate disconnect (err %d)", err);
389
390 LOG_DBG("Waiting for disconnection...");
391 WAIT_FOR_FLAG_UNSET(is_connected);
392 }
393
test_peripheral_main(void)394 static void test_peripheral_main(void)
395 {
396 LOG_DBG("*L2CAP STRESS Peripheral started*");
397 int err;
398
399 /* Prepare tx_data */
400 for (size_t i = 0; i < sizeof(tx_data); i++) {
401 tx_data[i] = (uint8_t)i;
402 }
403
404 err = bt_enable(NULL);
405 if (err) {
406 TEST_FAIL("Can't enable Bluetooth (err %d)", err);
407 return;
408 }
409
410 LOG_DBG("Peripheral Bluetooth initialized.");
411 LOG_DBG("Connectable advertising...");
412 err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, NULL, 0, NULL, 0);
413 if (err) {
414 TEST_FAIL("Advertising failed to start (err %d)", err);
415 return;
416 }
417
418 LOG_DBG("Advertising started.");
419 LOG_DBG("Peripheral waiting for connection...");
420 WAIT_FOR_FLAG(is_connected);
421 LOG_DBG("Peripheral Connected.");
422
423 int psm = l2cap_server_register(BT_SECURITY_L1);
424
425 LOG_DBG("Registered server PSM %x", psm);
426
427 LOG_DBG("Peripheral waiting for transfer completion");
428 while (sdu_rx_cnt < SDU_NUM) {
429 k_msleep(100);
430 }
431
432 bt_conn_foreach(BT_CONN_TYPE_LE, disconnect_device, NULL);
433
434 WAIT_FOR_FLAG_UNSET(is_connected);
435 LOG_INF("Total received: %d", sdu_rx_cnt);
436
437 /* check that all buffers returned to pool */
438 TEST_ASSERT(atomic_get(&sdu_tx_pool.avail_count) == CONFIG_BT_MAX_CONN,
439 "sdu_tx_pool has non returned buffers, should be %u but is %u",
440 CONFIG_BT_MAX_CONN, atomic_get(&sdu_tx_pool.avail_count));
441 TEST_ASSERT(atomic_get(&sdu_rx_pool.avail_count) == CONFIG_BT_MAX_CONN,
442 "sdu_rx_pool has non returned buffers, should be %u but is %u",
443 CONFIG_BT_MAX_CONN, atomic_get(&sdu_rx_pool.avail_count));
444
445 TEST_PASS("L2CAP STRESS Peripheral passed");
446 }
447
test_peripheral_early_disconnect_main(void)448 static void test_peripheral_early_disconnect_main(void)
449 {
450 device_nbr = bsim_args_get_global_device_nbr();
451 LOG_DBG("*L2CAP STRESS EARLY DISCONNECT Peripheral started*");
452 int err;
453
454 /* Prepare tx_data */
455 for (size_t i = 0; i < sizeof(tx_data); i++) {
456 tx_data[i] = (uint8_t)i;
457 }
458
459 err = bt_enable(NULL);
460 if (err) {
461 TEST_FAIL("Can't enable Bluetooth (err %d)", err);
462 return;
463 }
464
465 LOG_DBG("Peripheral Bluetooth initialized.");
466 LOG_DBG("Connectable advertising...");
467 err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, NULL, 0, NULL, 0);
468 if (err) {
469 TEST_FAIL("Advertising failed to start (err %d)", err);
470 return;
471 }
472
473 LOG_DBG("Advertising started.");
474 LOG_DBG("Peripheral waiting for connection...");
475 WAIT_FOR_FLAG(is_connected);
476 LOG_DBG("Peripheral Connected.");
477
478 int psm = l2cap_server_register(BT_SECURITY_L1);
479
480 LOG_DBG("Registered server PSM %x", psm);
481
482 if (device_nbr == 2) {
483 LOG_INF("disconnecting before receiving any SDU");
484 k_msleep(1000);
485 goto disconnect;
486 }
487
488 LOG_DBG("Peripheral waiting for transfer completion");
489 while (sdu_rx_cnt < SDU_NUM) {
490 if ((device_nbr == 3) && (sdu_rx_cnt >= 1)) {
491 LOG_INF("disconnecting after receiving SDU %u", sdu_rx_cnt);
492 break;
493 }
494
495 k_msleep(100);
496 if (!is_connected) {
497 goto done;
498 }
499 }
500
501 disconnect:
502 bt_conn_foreach(BT_CONN_TYPE_LE, disconnect_device, NULL);
503 done:
504
505 WAIT_FOR_FLAG_UNSET(is_connected);
506 LOG_INF("Total received: %d", sdu_rx_cnt);
507
508 /* check that all buffers returned to pool */
509 TEST_ASSERT(atomic_get(&sdu_tx_pool.avail_count) == CONFIG_BT_MAX_CONN,
510 "sdu_tx_pool has non returned buffers, should be %u but is %u",
511 CONFIG_BT_MAX_CONN, atomic_get(&sdu_tx_pool.avail_count));
512 TEST_ASSERT(atomic_get(&sdu_rx_pool.avail_count) == CONFIG_BT_MAX_CONN,
513 "sdu_rx_pool has non returned buffers, should be %u but is %u",
514 CONFIG_BT_MAX_CONN, atomic_get(&sdu_rx_pool.avail_count));
515
516 TEST_PASS("L2CAP STRESS Peripheral passed");
517 }
518
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)519 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
520 struct net_buf_simple *ad)
521 {
522 struct bt_le_conn_param *param;
523 struct bt_conn *conn;
524 int err;
525
526 err = bt_le_scan_stop();
527 if (err) {
528 TEST_FAIL("Stop LE scan failed (err %d)", err);
529 return;
530 }
531
532 char str[BT_ADDR_LE_STR_LEN];
533
534 bt_addr_le_to_str(addr, str, sizeof(str));
535
536 LOG_DBG("Connecting to %s", str);
537
538 param = BT_LE_CONN_PARAM_DEFAULT;
539 err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &conn);
540 if (err) {
541 TEST_FAIL("Create conn failed (err %d)", err);
542 return;
543 }
544 }
545
connect_peripheral(void)546 static void connect_peripheral(void)
547 {
548 struct bt_le_scan_param scan_param = {
549 .type = BT_LE_SCAN_TYPE_ACTIVE,
550 .options = BT_LE_SCAN_OPT_NONE,
551 .interval = BT_GAP_SCAN_FAST_INTERVAL,
552 .window = BT_GAP_SCAN_FAST_WINDOW,
553 };
554
555 UNSET_FLAG(is_connected);
556
557 int err = bt_le_scan_start(&scan_param, device_found);
558
559 TEST_ASSERT(!err, "Scanning failed to start (err %d)", err);
560
561 LOG_DBG("Central initiating connection...");
562 WAIT_FOR_FLAG(is_connected);
563 }
564
connect_l2cap_channel(struct bt_conn * conn,void * data)565 static void connect_l2cap_channel(struct bt_conn *conn, void *data)
566 {
567 int err;
568 struct test_ctx *ctx = alloc_test_context();
569
570 TEST_ASSERT(ctx, "No more available test contexts");
571
572 struct bt_l2cap_le_chan *le_chan = &ctx->le_chan;
573
574 le_chan->chan.ops = &ops;
575 le_chan->rx.mtu = SDU_LEN;
576 #ifdef CONFIG_BT_L2CAP_SEG_RECV
577 le_chan->rx.mps = BT_L2CAP_RX_MTU;
578 le_chan->rx.credits = CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA;
579 #endif
580
581 UNSET_FLAG(flag_l2cap_connected);
582
583 err = bt_l2cap_chan_connect(conn, &le_chan->chan, 0x0080);
584 TEST_ASSERT(!err, "Error connecting l2cap channel (err %d)", err);
585
586 WAIT_FOR_FLAG(flag_l2cap_connected);
587 }
588
test_central_main(void)589 static void test_central_main(void)
590 {
591 LOG_DBG("*L2CAP STRESS Central started*");
592 int err;
593
594 /* Prepare tx_data */
595 for (size_t i = 0; i < sizeof(tx_data); i++) {
596 tx_data[i] = (uint8_t)i;
597 }
598
599 err = bt_enable(NULL);
600 TEST_ASSERT(err == 0, "Can't enable Bluetooth (err %d)", err);
601 LOG_DBG("Central Bluetooth initialized.");
602
603 /* Connect all peripherals */
604 for (int i = 0; i < NUM_PERIPHERALS; i++) {
605 connect_peripheral();
606 }
607
608 /* Connect L2CAP channels */
609 LOG_DBG("Connect L2CAP channels");
610 bt_conn_foreach(BT_CONN_TYPE_LE, connect_l2cap_channel, NULL);
611
612 /* Send SDU_NUM SDUs to each peripheral */
613 for (int i = 0; i < NUM_PERIPHERALS; i++) {
614 contexts[i].tx_left = SDU_NUM;
615 l2cap_chan_send(&contexts[i].le_chan.chan, tx_data, sizeof(tx_data));
616 }
617
618 LOG_DBG("Wait until all transfers are completed.");
619 int remaining_tx_total;
620
621 do {
622 k_msleep(100);
623
624 remaining_tx_total = 0;
625 for (int i = 0; i < L2CAP_CHANS; i++) {
626 remaining_tx_total += contexts[i].tx_left;
627 }
628 } while (remaining_tx_total);
629
630 LOG_DBG("Waiting until all peripherals are disconnected..");
631 while (disconnect_counter < NUM_PERIPHERALS) {
632 k_msleep(100);
633 }
634 LOG_DBG("All peripherals disconnected.");
635
636 /* check that all buffers returned to pool */
637 TEST_ASSERT(atomic_get(&sdu_tx_pool.avail_count) == CONFIG_BT_MAX_CONN,
638 "sdu_tx_pool has non returned buffers, should be %u but is %u",
639 CONFIG_BT_MAX_CONN, atomic_get(&sdu_tx_pool.avail_count));
640 TEST_ASSERT(atomic_get(&sdu_rx_pool.avail_count) == CONFIG_BT_MAX_CONN,
641 "sdu_rx_pool has non returned buffers, should be %u but is %u",
642 CONFIG_BT_MAX_CONN, atomic_get(&sdu_rx_pool.avail_count));
643
644 TEST_PASS("L2CAP STRESS Central passed");
645 }
646
647 static const struct bst_test_instance test_def[] = {
648 {
649 .test_id = "peripheral",
650 .test_descr = "Peripheral L2CAP STRESS",
651 .test_main_f = test_peripheral_main
652 },
653 {
654 .test_id = "peripheral_early_disconnect",
655 .test_descr = "Peripheral L2CAP STRESS EARLY DISCONNECT",
656 .test_main_f = test_peripheral_early_disconnect_main,
657 },
658 {
659 .test_id = "central",
660 .test_descr = "Central L2CAP STRESS",
661 .test_main_f = test_central_main
662 },
663 BSTEST_END_MARKER
664 };
665
test_main_l2cap_stress_install(struct bst_test_list * tests)666 struct bst_test_list *test_main_l2cap_stress_install(struct bst_test_list *tests)
667 {
668 return bst_add_tests(tests, test_def);
669 }
670
671 extern struct bst_test_list *test_main_l2cap_stress_install(struct bst_test_list *tests);
672
673 bst_test_install_t test_installers[] = {
674 test_main_l2cap_stress_install,
675 NULL
676 };
677
main(void)678 int main(void)
679 {
680 bst_main();
681 return 0;
682 }
683