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