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 "bstests.h"
10 #include "common.h"
11 
12 #define LOG_MODULE_NAME main
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF);
15 
16 CREATE_FLAG(is_connected);
17 CREATE_FLAG(flag_l2cap_connected);
18 
19 #define NUM_PERIPHERALS 6
20 #define L2CAP_CHANS     NUM_PERIPHERALS
21 #define SDU_NUM         20
22 #define SDU_LEN         3000
23 #define RESCHEDULE_DELAY K_MSEC(100)
24 
sdu_destroy(struct net_buf * buf)25 static void sdu_destroy(struct net_buf *buf)
26 {
27 	LOG_DBG("%p", buf);
28 
29 	net_buf_destroy(buf);
30 }
31 
rx_destroy(struct net_buf * buf)32 static void rx_destroy(struct net_buf *buf)
33 {
34 	LOG_DBG("%p", buf);
35 
36 	net_buf_destroy(buf);
37 }
38 
39 /* Only one SDU per link will be transmitted at a time */
40 NET_BUF_POOL_DEFINE(sdu_tx_pool,
41 		    CONFIG_BT_MAX_CONN, BT_L2CAP_SDU_BUF_SIZE(SDU_LEN),
42 		    CONFIG_BT_CONN_TX_USER_DATA_SIZE, sdu_destroy);
43 
44 /* Only one SDU per link will be received at a time */
45 NET_BUF_POOL_DEFINE(sdu_rx_pool,
46 		    CONFIG_BT_MAX_CONN, BT_L2CAP_SDU_BUF_SIZE(SDU_LEN),
47 		    8, rx_destroy);
48 
49 static uint8_t tx_data[SDU_LEN];
50 static uint16_t rx_cnt;
51 static uint8_t disconnect_counter;
52 
53 struct test_ctx {
54 	struct k_work_delayable work_item;
55 	struct bt_l2cap_le_chan le_chan;
56 	size_t tx_left;
57 };
58 
59 static struct test_ctx contexts[L2CAP_CHANS];
60 
get_ctx(struct bt_l2cap_chan * chan)61 struct test_ctx *get_ctx(struct bt_l2cap_chan *chan)
62 {
63 	struct bt_l2cap_le_chan *le_chan = CONTAINER_OF(chan, struct bt_l2cap_le_chan, chan);
64 	struct test_ctx *ctx = CONTAINER_OF(le_chan, struct test_ctx, le_chan);
65 
66 	ASSERT(ctx >= &contexts[0] &&
67 	       ctx <= &contexts[L2CAP_CHANS], "memory corruption");
68 
69 	return ctx;
70 }
71 
l2cap_chan_send(struct bt_l2cap_chan * chan,uint8_t * data,size_t len)72 int l2cap_chan_send(struct bt_l2cap_chan *chan, uint8_t *data, size_t len)
73 {
74 	LOG_DBG("chan %p conn %u data %p len %d", chan, bt_conn_index(chan->conn), data, len);
75 
76 	struct net_buf *buf = net_buf_alloc(&sdu_tx_pool, K_NO_WAIT);
77 
78 	if (buf == NULL) {
79 		FAIL("No more memory\n");
80 		return -ENOMEM;
81 	}
82 
83 	net_buf_reserve(buf, BT_L2CAP_SDU_CHAN_SEND_RESERVE);
84 	net_buf_add_mem(buf, data, len);
85 
86 	int ret = bt_l2cap_chan_send(chan, buf);
87 
88 	if (ret == -EAGAIN) {
89 		LOG_DBG("L2CAP error %d, attempting to reschedule sending", ret);
90 		net_buf_unref(buf);
91 		k_work_reschedule(&(get_ctx(chan)->work_item), RESCHEDULE_DELAY);
92 
93 		return ret;
94 	}
95 
96 	ASSERT(ret >= 0, "Failed sending: err %d", ret);
97 
98 	LOG_DBG("sent %d len %d", ret, len);
99 	return ret;
100 }
101 
alloc_buf_cb(struct bt_l2cap_chan * chan)102 struct net_buf *alloc_buf_cb(struct bt_l2cap_chan *chan)
103 {
104 	return net_buf_alloc(&sdu_rx_pool, K_NO_WAIT);
105 }
106 
continue_sending(struct test_ctx * ctx)107 void continue_sending(struct test_ctx *ctx)
108 {
109 	struct bt_l2cap_chan *chan = &ctx->le_chan.chan;
110 
111 	LOG_DBG("%p, left %d", chan, ctx->tx_left);
112 
113 	if (ctx->tx_left) {
114 		l2cap_chan_send(chan, tx_data, sizeof(tx_data));
115 	} else {
116 		LOG_DBG("Done sending %u", bt_conn_index(chan->conn));
117 	}
118 }
119 
sent_cb(struct bt_l2cap_chan * chan)120 void sent_cb(struct bt_l2cap_chan *chan)
121 {
122 	struct test_ctx *ctx = get_ctx(chan);
123 
124 	LOG_DBG("%p", chan);
125 
126 	if (ctx->tx_left) {
127 		ctx->tx_left--;
128 	}
129 
130 	continue_sending(ctx);
131 }
132 
recv_cb(struct bt_l2cap_chan * chan,struct net_buf * buf)133 int recv_cb(struct bt_l2cap_chan *chan, struct net_buf *buf)
134 {
135 	LOG_DBG("len %d", buf->len);
136 	rx_cnt++;
137 
138 	/* Verify SDU data matches TX'd data. */
139 	int pos = memcmp(buf->data, tx_data, buf->len);
140 
141 	if (pos != 0) {
142 		LOG_ERR("RX data doesn't match TX: pos %d", pos);
143 		LOG_HEXDUMP_ERR(buf->data, buf->len, "RX data");
144 		LOG_HEXDUMP_INF(tx_data, buf->len, "TX data");
145 
146 		for (uint16_t p = 0; p < buf->len; p++) {
147 			__ASSERT(buf->data[p] == tx_data[p],
148 				 "Failed rx[%d]=%x != expect[%d]=%x",
149 				 p, buf->data[p], p, tx_data[p]);
150 		}
151 	}
152 
153 	return 0;
154 }
155 
l2cap_chan_connected_cb(struct bt_l2cap_chan * l2cap_chan)156 void l2cap_chan_connected_cb(struct bt_l2cap_chan *l2cap_chan)
157 {
158 	struct bt_l2cap_le_chan *chan =
159 		CONTAINER_OF(l2cap_chan, struct bt_l2cap_le_chan, chan);
160 
161 	SET_FLAG(flag_l2cap_connected);
162 	LOG_DBG("%x (tx mtu %d mps %d) (tx mtu %d mps %d)",
163 		l2cap_chan,
164 		chan->tx.mtu,
165 		chan->tx.mps,
166 		chan->rx.mtu,
167 		chan->rx.mps);
168 }
169 
l2cap_chan_disconnected_cb(struct bt_l2cap_chan * chan)170 void l2cap_chan_disconnected_cb(struct bt_l2cap_chan *chan)
171 {
172 	UNSET_FLAG(flag_l2cap_connected);
173 	LOG_DBG("%p", chan);
174 }
175 
176 static struct bt_l2cap_chan_ops ops = {
177 	.connected = l2cap_chan_connected_cb,
178 	.disconnected = l2cap_chan_disconnected_cb,
179 	.alloc_buf = alloc_buf_cb,
180 	.recv = recv_cb,
181 	.sent = sent_cb,
182 };
183 
deferred_send(struct k_work * item)184 void deferred_send(struct k_work *item)
185 {
186 	struct test_ctx *ctx = CONTAINER_OF(k_work_delayable_from_work(item),
187 					    struct test_ctx, work_item);
188 
189 	struct bt_l2cap_chan *chan = &ctx->le_chan.chan;
190 
191 	LOG_DBG("continue %u left %d", bt_conn_index(chan->conn), ctx->tx_left);
192 
193 	continue_sending(ctx);
194 }
195 
alloc_test_context(void)196 struct test_ctx *alloc_test_context(void)
197 {
198 	for (int i = 0; i < L2CAP_CHANS; i++) {
199 		struct bt_l2cap_le_chan *le_chan = &contexts[i].le_chan;
200 
201 		if (le_chan->state != BT_L2CAP_DISCONNECTED) {
202 			continue;
203 		}
204 
205 		memset(&contexts[i], 0, sizeof(struct test_ctx));
206 		k_work_init_delayable(&contexts[i].work_item, deferred_send);
207 
208 		return &contexts[i];
209 	}
210 
211 	return NULL;
212 }
213 
server_accept_cb(struct bt_conn * conn,struct bt_l2cap_server * server,struct bt_l2cap_chan ** chan)214 int server_accept_cb(struct bt_conn *conn, struct bt_l2cap_server *server,
215 		     struct bt_l2cap_chan **chan)
216 {
217 	struct test_ctx *ctx = NULL;
218 
219 	ctx = alloc_test_context();
220 	if (ctx == NULL) {
221 		return -ENOMEM;
222 	}
223 
224 	struct bt_l2cap_le_chan *le_chan = &ctx->le_chan;
225 
226 	memset(le_chan, 0, sizeof(*le_chan));
227 	le_chan->chan.ops = &ops;
228 	le_chan->rx.mtu = SDU_LEN;
229 	*chan = &le_chan->chan;
230 
231 	return 0;
232 }
233 
234 static struct bt_l2cap_server test_l2cap_server = {
235 	.accept = server_accept_cb
236 };
237 
l2cap_server_register(bt_security_t sec_level)238 static int l2cap_server_register(bt_security_t sec_level)
239 {
240 	test_l2cap_server.psm = 0;
241 	test_l2cap_server.sec_level = sec_level;
242 
243 	int err = bt_l2cap_server_register(&test_l2cap_server);
244 
245 	ASSERT(err == 0, "Failed to register l2cap server.");
246 
247 	return test_l2cap_server.psm;
248 }
249 
connected(struct bt_conn * conn,uint8_t conn_err)250 static void connected(struct bt_conn *conn, uint8_t conn_err)
251 {
252 	char addr[BT_ADDR_LE_STR_LEN];
253 
254 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
255 
256 	if (conn_err) {
257 		FAIL("Failed to connect to %s (%u)", addr, conn_err);
258 		return;
259 	}
260 
261 	LOG_DBG("%s", addr);
262 
263 	SET_FLAG(is_connected);
264 }
265 
disconnected(struct bt_conn * conn,uint8_t reason)266 static void disconnected(struct bt_conn *conn, uint8_t reason)
267 {
268 	char addr[BT_ADDR_LE_STR_LEN];
269 
270 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
271 
272 	LOG_DBG("%p %s (reason 0x%02x)", conn, addr, reason);
273 
274 	UNSET_FLAG(is_connected);
275 	disconnect_counter++;
276 }
277 
278 BT_CONN_CB_DEFINE(conn_callbacks) = {
279 	.connected = connected,
280 	.disconnected = disconnected,
281 };
282 
disconnect_device(struct bt_conn * conn,void * data)283 static void disconnect_device(struct bt_conn *conn, void *data)
284 {
285 	int err;
286 
287 	SET_FLAG(is_connected);
288 
289 	err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
290 	ASSERT(!err, "Failed to initate disconnect (err %d)", err);
291 
292 	LOG_DBG("Waiting for disconnection...");
293 	WAIT_FOR_FLAG_UNSET(is_connected);
294 }
295 
test_peripheral_main(void)296 static void test_peripheral_main(void)
297 {
298 	LOG_DBG("*L2CAP STRESS Peripheral started*");
299 	int err;
300 
301 	/* Prepare tx_data */
302 	for (size_t i = 0; i < sizeof(tx_data); i++) {
303 		tx_data[i] = (uint8_t)i;
304 	}
305 
306 	err = bt_enable(NULL);
307 	if (err) {
308 		FAIL("Can't enable Bluetooth (err %d)", err);
309 		return;
310 	}
311 
312 	LOG_DBG("Peripheral Bluetooth initialized.");
313 	LOG_DBG("Connectable advertising...");
314 	err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, NULL, 0, NULL, 0);
315 	if (err) {
316 		FAIL("Advertising failed to start (err %d)", err);
317 		return;
318 	}
319 
320 	LOG_DBG("Advertising started.");
321 	LOG_DBG("Peripheral waiting for connection...");
322 	WAIT_FOR_FLAG_SET(is_connected);
323 	LOG_DBG("Peripheral Connected.");
324 
325 	int psm = l2cap_server_register(BT_SECURITY_L1);
326 
327 	LOG_DBG("Registered server PSM %x", psm);
328 
329 	LOG_DBG("Peripheral waiting for transfer completion");
330 	while (rx_cnt < SDU_NUM) {
331 		k_msleep(100);
332 	}
333 
334 	bt_conn_foreach(BT_CONN_TYPE_LE, disconnect_device, NULL);
335 	WAIT_FOR_FLAG_UNSET(is_connected);
336 	LOG_INF("Total received: %d", rx_cnt);
337 
338 	ASSERT(rx_cnt == SDU_NUM, "Did not receive expected no of SDUs\n");
339 
340 	PASS("L2CAP STRESS Peripheral passed\n");
341 }
342 
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)343 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
344 			 struct net_buf_simple *ad)
345 {
346 	struct bt_le_conn_param *param;
347 	struct bt_conn *conn;
348 	int err;
349 
350 	err = bt_le_scan_stop();
351 	if (err) {
352 		FAIL("Stop LE scan failed (err %d)", err);
353 		return;
354 	}
355 
356 	char str[BT_ADDR_LE_STR_LEN];
357 
358 	bt_addr_le_to_str(addr, str, sizeof(str));
359 
360 	LOG_DBG("Connecting to %s", str);
361 
362 	param = BT_LE_CONN_PARAM_DEFAULT;
363 	err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &conn);
364 	if (err) {
365 		FAIL("Create conn failed (err %d)", err);
366 		return;
367 	}
368 }
369 
connect_peripheral(void)370 static void connect_peripheral(void)
371 {
372 	struct bt_le_scan_param scan_param = {
373 		.type = BT_LE_SCAN_TYPE_ACTIVE,
374 		.options = BT_LE_SCAN_OPT_NONE,
375 		.interval = BT_GAP_SCAN_FAST_INTERVAL,
376 		.window = BT_GAP_SCAN_FAST_WINDOW,
377 	};
378 
379 	UNSET_FLAG(is_connected);
380 
381 	int err = bt_le_scan_start(&scan_param, device_found);
382 
383 	ASSERT(!err, "Scanning failed to start (err %d)\n", err);
384 
385 	LOG_DBG("Central initiating connection...");
386 	WAIT_FOR_FLAG_SET(is_connected);
387 }
388 
connect_l2cap_channel(struct bt_conn * conn,void * data)389 static void connect_l2cap_channel(struct bt_conn *conn, void *data)
390 {
391 	int err;
392 	struct test_ctx *ctx = alloc_test_context();
393 
394 	ASSERT(ctx, "No more available test contexts\n");
395 
396 	struct bt_l2cap_le_chan *le_chan = &ctx->le_chan;
397 
398 	le_chan->chan.ops = &ops;
399 	le_chan->rx.mtu = SDU_LEN;
400 
401 	UNSET_FLAG(flag_l2cap_connected);
402 
403 	err = bt_l2cap_chan_connect(conn, &le_chan->chan, 0x0080);
404 	ASSERT(!err, "Error connecting l2cap channel (err %d)\n", err);
405 
406 	WAIT_FOR_FLAG_SET(flag_l2cap_connected);
407 }
408 
test_central_main(void)409 static void test_central_main(void)
410 {
411 	LOG_DBG("*L2CAP STRESS Central started*");
412 	int err;
413 
414 	/* Prepare tx_data */
415 	for (size_t i = 0; i < sizeof(tx_data); i++) {
416 		tx_data[i] = (uint8_t)i;
417 	}
418 
419 	err = bt_enable(NULL);
420 	ASSERT(err == 0, "Can't enable Bluetooth (err %d)\n", err);
421 	LOG_DBG("Central Bluetooth initialized.");
422 
423 	/* Connect all peripherals */
424 	for (int i = 0; i < NUM_PERIPHERALS; i++) {
425 		connect_peripheral();
426 	}
427 
428 	/* Connect L2CAP channels */
429 	LOG_DBG("Connect L2CAP channels");
430 	bt_conn_foreach(BT_CONN_TYPE_LE, connect_l2cap_channel, NULL);
431 
432 	/* Send SDU_NUM SDUs to each peripheral */
433 	for (int i = 0; i < NUM_PERIPHERALS; i++) {
434 		contexts[i].tx_left = SDU_NUM;
435 		l2cap_chan_send(&contexts[i].le_chan.chan, tx_data, sizeof(tx_data));
436 	}
437 
438 	LOG_DBG("Wait until all transfers are completed.");
439 	int remaining_tx_total;
440 
441 	do {
442 		k_msleep(100);
443 
444 		remaining_tx_total = 0;
445 		for (int i = 0; i < L2CAP_CHANS; i++) {
446 			remaining_tx_total += contexts[i].tx_left;
447 		}
448 	} while (remaining_tx_total);
449 
450 	LOG_DBG("Waiting until all peripherals are disconnected..");
451 	while (disconnect_counter < NUM_PERIPHERALS) {
452 		k_msleep(100);
453 	}
454 	LOG_DBG("All peripherals disconnected.");
455 
456 	PASS("L2CAP STRESS Central passed\n");
457 }
458 
459 static const struct bst_test_instance test_def[] = {
460 	{
461 		.test_id = "peripheral",
462 		.test_descr = "Peripheral L2CAP STRESS",
463 		.test_pre_init_f = test_init,
464 		.test_tick_f = test_tick,
465 		.test_main_f = test_peripheral_main
466 	},
467 	{
468 		.test_id = "central",
469 		.test_descr = "Central L2CAP STRESS",
470 		.test_pre_init_f = test_init,
471 		.test_tick_f = test_tick,
472 		.test_main_f = test_central_main
473 	},
474 	BSTEST_END_MARKER
475 };
476 
test_main_l2cap_stress_install(struct bst_test_list * tests)477 struct bst_test_list *test_main_l2cap_stress_install(struct bst_test_list *tests)
478 {
479 	return bst_add_tests(tests, test_def);
480 }
481 
482 extern struct bst_test_list *test_main_l2cap_stress_install(struct bst_test_list *tests);
483 
484 bst_test_install_t test_installers[] = {
485 	test_main_l2cap_stress_install,
486 	NULL
487 };
488 
main(void)489 int main(void)
490 {
491 	bst_main();
492 	return 0;
493 }
494