1 /* main_l2cap_ecred.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 "common.h"
10
11 #define LOG_MODULE_NAME main_l2cap_ecred
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_DBG);
14
15 extern enum bst_result_t bst_result;
16
17 static struct bt_conn *default_conn;
18
19 static const struct bt_data ad[] = {
20 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
21 };
22
23 #define DATA_MTU CONFIG_BT_L2CAP_TX_MTU
24 #define DATA_MPS 65
25 #define DATA_BUF_SIZE BT_L2CAP_SDU_BUF_SIZE(DATA_MTU)
26 #define L2CAP_CHANNELS 2
27 #define SERVERS 1
28 #define SDU_SEND_COUNT 200
29 #define ECRED_CHAN_MAX 5
30 #define LONG_MSG (DATA_MTU - 500)
31 #define SHORT_MSG (DATA_MPS - 2)
32 #define LONG_MSG_CHAN_IDX 0
33 #define SHORT_MSG_CHAN_IDX 1
34
35 NET_BUF_POOL_FIXED_DEFINE(rx_data_pool, L2CAP_CHANNELS, BT_L2CAP_BUF_SIZE(DATA_BUF_SIZE), 8, NULL);
36 NET_BUF_POOL_FIXED_DEFINE(tx_data_pool_0, 1, BT_L2CAP_SDU_BUF_SIZE(DATA_MTU),
37 CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
38 NET_BUF_POOL_FIXED_DEFINE(tx_data_pool_1, 1, BT_L2CAP_SDU_BUF_SIZE(DATA_MTU),
39 CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
40
41 static struct bt_l2cap_server servers[SERVERS];
42 void send_sdu_chan_worker(struct k_work *item);
43 struct channel {
44 uint8_t chan_id; /* Internal number that identifies L2CAP channel. */
45 struct bt_l2cap_le_chan le;
46 bool in_use;
47 size_t sdus_received;
48 size_t bytes_to_send;
49 uint8_t iteration;
50 struct net_buf *buf;
51 struct k_work work;
52 struct k_work_q work_queue;
53 uint8_t payload[DATA_MTU];
54 };
55 static struct channel channels[L2CAP_CHANNELS];
56
57 CREATE_FLAG(is_connected);
58 CREATE_FLAG(unsequenced_data);
59
60 #define T_STACK_SIZE 512
61 #define T_PRIORITY 5
62
63 static K_THREAD_STACK_ARRAY_DEFINE(stack_area, L2CAP_CHANNELS, T_STACK_SIZE);
64 static K_SEM_DEFINE(chan_conn_sem, 0, L2CAP_CHANNELS);
65 static K_SEM_DEFINE(all_chan_conn_sem, 0, 1);
66 static K_SEM_DEFINE(all_chan_disconn_sem, 0, 1);
67 static K_SEM_DEFINE(sent_sem, 0, L2CAP_CHANNELS);
68
init_workqs(void)69 static void init_workqs(void)
70 {
71 for (int i = 0; i < L2CAP_CHANNELS; i++) {
72 k_work_queue_init(&channels[i].work_queue);
73 k_work_queue_start(&channels[i].work_queue, stack_area[i],
74 K_THREAD_STACK_SIZEOF(*stack_area), T_PRIORITY, NULL);
75 }
76 }
77
chan_alloc_buf_cb(struct bt_l2cap_chan * chan)78 static struct net_buf *chan_alloc_buf_cb(struct bt_l2cap_chan *chan)
79 {
80 LOG_DBG("Allocated on chan %p", chan);
81 return net_buf_alloc(&rx_data_pool, K_FOREVER);
82 }
83
chan_recv_cb(struct bt_l2cap_chan * l2cap_chan,struct net_buf * buf)84 static int chan_recv_cb(struct bt_l2cap_chan *l2cap_chan, struct net_buf *buf)
85 {
86 struct bt_l2cap_le_chan *l2cap_le_chan = CONTAINER_OF(
87 l2cap_chan, struct bt_l2cap_le_chan, chan);
88 struct channel *chan = CONTAINER_OF(l2cap_le_chan, struct channel, le);
89 const uint32_t received_iterration = net_buf_pull_le32(buf);
90
91 LOG_DBG("received_iterration %i sdus_received %i, chan_id: %d, data_length: %d",
92 received_iterration, chan->sdus_received, chan->chan_id, buf->len);
93 if (!TEST_FLAG(unsequenced_data) && received_iterration != chan->sdus_received) {
94 FAIL("Received out of sequence data.");
95 }
96
97 const int retval = memcmp(buf->data + sizeof(received_iterration),
98 chan->payload + sizeof(received_iterration),
99 buf->len - sizeof(received_iterration));
100 if (retval) {
101 FAIL("Payload received didn't match expected value memcmp returned %i", retval);
102 }
103
104 /*By the time we rx on long msg channel we should have already rx on short msg channel*/
105 if (chan->chan_id == 0) {
106 if (channels[SHORT_MSG_CHAN_IDX].sdus_received !=
107 (channels[LONG_MSG_CHAN_IDX].sdus_received + 1)) {
108 FAIL("Didn't receive on short msg channel first");
109 }
110 }
111
112 chan->sdus_received++;
113
114 return 0;
115 }
116
chan_sent_cb(struct bt_l2cap_chan * l2cap_chan)117 static void chan_sent_cb(struct bt_l2cap_chan *l2cap_chan)
118 {
119 struct bt_l2cap_le_chan *l2cap_le_chan = CONTAINER_OF(
120 l2cap_chan, struct bt_l2cap_le_chan, chan);
121 struct channel *chan = CONTAINER_OF(l2cap_le_chan, struct channel, le);
122
123 chan->buf = 0;
124 k_sem_give(&sent_sem);
125
126 LOG_DBG("chan_id: %d", chan->chan_id);
127 }
128
chan_connected_cb(struct bt_l2cap_chan * l2cap_chan)129 static void chan_connected_cb(struct bt_l2cap_chan *l2cap_chan)
130 {
131 struct bt_l2cap_le_chan *l2cap_le_chan = CONTAINER_OF(
132 l2cap_chan, struct bt_l2cap_le_chan, chan);
133 struct channel *chan = CONTAINER_OF(l2cap_le_chan, struct channel, le);
134
135 LOG_DBG("chan_id: %d", chan->chan_id);
136
137 LOG_DBG("tx.mtu %d, tx.mps: %d, rx.mtu: %d, rx.mps %d", sys_cpu_to_le16(chan->le.tx.mtu),
138 sys_cpu_to_le16(chan->le.tx.mps), sys_cpu_to_le16(chan->le.rx.mtu),
139 sys_cpu_to_le16(chan->le.rx.mps));
140
141 k_sem_give(&chan_conn_sem);
142
143 if (k_sem_count_get(&chan_conn_sem) == L2CAP_CHANNELS) {
144 k_sem_give(&all_chan_conn_sem);
145 k_sem_reset(&all_chan_disconn_sem);
146 }
147 }
148
chan_disconnected_cb(struct bt_l2cap_chan * l2cap_chan)149 static void chan_disconnected_cb(struct bt_l2cap_chan *l2cap_chan)
150 {
151 struct bt_l2cap_le_chan *l2cap_le_chan = CONTAINER_OF(
152 l2cap_chan, struct bt_l2cap_le_chan, chan);
153 struct channel *chan = CONTAINER_OF(l2cap_le_chan, struct channel, le);
154
155 LOG_DBG("chan_id: %d", chan->chan_id);
156
157 chan->in_use = false;
158 k_sem_take(&chan_conn_sem, K_FOREVER);
159
160 if (k_sem_count_get(&chan_conn_sem) == 0) {
161 k_sem_give(&all_chan_disconn_sem);
162 k_sem_reset(&all_chan_conn_sem);
163 }
164 }
165
chan_status_cb(struct bt_l2cap_chan * l2cap_chan,atomic_t * status)166 static void chan_status_cb(struct bt_l2cap_chan *l2cap_chan, atomic_t *status)
167 {
168 struct bt_l2cap_le_chan *l2cap_le_chan = CONTAINER_OF(
169 l2cap_chan, struct bt_l2cap_le_chan, chan);
170 struct channel *chan = CONTAINER_OF(l2cap_le_chan, struct channel, le);
171
172 LOG_DBG("chan_id: %d, status: %ld", chan->chan_id, *status);
173 }
174
chan_released_cb(struct bt_l2cap_chan * l2cap_chan)175 static void chan_released_cb(struct bt_l2cap_chan *l2cap_chan)
176 {
177 struct bt_l2cap_le_chan *l2cap_le_chan = CONTAINER_OF(
178 l2cap_chan, struct bt_l2cap_le_chan, chan);
179 struct channel *chan = CONTAINER_OF(l2cap_le_chan, struct channel, le);
180
181 LOG_DBG("chan_id: %d", chan->chan_id);
182 }
183
chan_reconfigured_cb(struct bt_l2cap_chan * l2cap_chan)184 static void chan_reconfigured_cb(struct bt_l2cap_chan *l2cap_chan)
185 {
186 struct bt_l2cap_le_chan *l2cap_le_chan = CONTAINER_OF(
187 l2cap_chan, struct bt_l2cap_le_chan, chan);
188 struct channel *chan = CONTAINER_OF(l2cap_le_chan, struct channel, le);
189
190 LOG_DBG("chan_id: %d", chan->chan_id);
191 }
192
193 static const struct bt_l2cap_chan_ops l2cap_ops = {
194 .alloc_buf = chan_alloc_buf_cb,
195 .recv = chan_recv_cb,
196 .sent = chan_sent_cb,
197 .connected = chan_connected_cb,
198 .disconnected = chan_disconnected_cb,
199 .status = chan_status_cb,
200 .released = chan_released_cb,
201 .reconfigured = chan_reconfigured_cb,
202 };
203
get_free_channel(void)204 static struct channel *get_free_channel(void)
205 {
206 for (int idx = 0; idx < L2CAP_CHANNELS; idx++) {
207 struct channel *chan = &channels[idx];
208
209 if (chan->in_use) {
210 continue;
211 }
212
213 chan->chan_id = idx;
214 channels[idx].in_use = true;
215 (void)memset(chan->payload, idx, sizeof(chan->payload));
216 k_work_init(&chan->work, send_sdu_chan_worker);
217 chan->le.chan.ops = &l2cap_ops;
218 chan->le.rx.mtu = DATA_MTU;
219 chan->le.rx.mps = DATA_MPS;
220
221 return chan;
222 }
223
224 return NULL;
225 }
226
connect_num_channels(uint8_t num_l2cap_channels)227 static void connect_num_channels(uint8_t num_l2cap_channels)
228 {
229 struct bt_l2cap_chan *allocated_channels[ECRED_CHAN_MAX] = { NULL };
230
231 for (int i = 0; i < num_l2cap_channels; i++) {
232 struct channel *chan = get_free_channel();
233
234 if (!chan) {
235 FAIL("failed, chan not free");
236 return;
237 }
238
239 allocated_channels[i] = &chan->le.chan;
240 }
241
242 const int err = bt_l2cap_ecred_chan_connect(default_conn, allocated_channels,
243 servers[0].psm);
244
245 if (err) {
246 FAIL("can't connect ecred %d ", err);
247 }
248 }
249
disconnect_all_channels(void)250 static void disconnect_all_channels(void)
251 {
252 for (int i = 0; i < ARRAY_SIZE(channels); i++) {
253 if (channels[i].in_use) {
254 LOG_DBG("Disconnecting channel: %d)", channels[i].chan_id);
255 const int err = bt_l2cap_chan_disconnect(&channels[i].le.chan);
256
257 if (err) {
258 LOG_DBG("can't disconnect channel (err: %d)", err);
259 }
260
261 channels[i].in_use = false;
262 }
263 }
264 }
265
accept(struct bt_conn * conn,struct bt_l2cap_server * server,struct bt_l2cap_chan ** l2cap_chan)266 static int accept(struct bt_conn *conn, struct bt_l2cap_server *server,
267 struct bt_l2cap_chan **l2cap_chan)
268 {
269 struct channel *chan;
270
271 chan = get_free_channel();
272 if (!chan) {
273 return -ENOMEM;
274 }
275
276 *l2cap_chan = &chan->le.chan;
277
278 return 0;
279 }
280
get_free_server(void)281 static struct bt_l2cap_server *get_free_server(void)
282 {
283 for (int i = 0; i < SERVERS; i++) {
284 if (servers[i].psm) {
285 continue;
286 }
287
288 return &servers[i];
289 }
290
291 return NULL;
292 }
293
register_l2cap_server(void)294 static void register_l2cap_server(void)
295 {
296 struct bt_l2cap_server *server;
297
298 server = get_free_server();
299 if (!server) {
300 FAIL("Failed to get free server");
301 return;
302 }
303
304 server->accept = accept;
305 server->psm = 0;
306
307 if (bt_l2cap_server_register(server) < 0) {
308 FAIL("Failed to get free server");
309 return;
310 }
311
312 LOG_DBG("L2CAP server registered, PSM:0x%X", server->psm);
313 }
314
connected(struct bt_conn * conn,uint8_t conn_err)315 static void connected(struct bt_conn *conn, uint8_t conn_err)
316 {
317 char addr[BT_ADDR_LE_STR_LEN];
318
319 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
320
321 if (conn_err) {
322 FAIL("Failed to connect to %s (%u)", addr, conn_err);
323 bt_conn_unref(default_conn);
324 default_conn = NULL;
325 return;
326 }
327
328 default_conn = bt_conn_ref(conn);
329 LOG_DBG("%s", addr);
330
331 SET_FLAG(is_connected);
332 }
333
disconnected(struct bt_conn * conn,uint8_t reason)334 static void disconnected(struct bt_conn *conn, uint8_t reason)
335 {
336 char addr[BT_ADDR_LE_STR_LEN];
337
338 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
339
340 LOG_DBG("%s (reason 0x%02x)", addr, reason);
341
342 if (default_conn != conn) {
343 FAIL("Conn mismatch disconnect %s %s)", default_conn, conn);
344 return;
345 }
346
347 bt_conn_unref(default_conn);
348 default_conn = NULL;
349 UNSET_FLAG(is_connected);
350 }
351
352 BT_CONN_CB_DEFINE(conn_callbacks) = {
353 .connected = connected,
354 .disconnected = disconnected,
355 };
356
send_sdu(int iteration,int chan_idx,int bytes)357 static void send_sdu(int iteration, int chan_idx, int bytes)
358 {
359 struct bt_l2cap_chan *chan = &channels[chan_idx].le.chan;
360 struct net_buf *buf;
361
362 /* First 4 bytes in sent payload is iteration count */
363 sys_put_le32(iteration, channels[chan_idx].payload);
364
365 if (channels[chan_idx].buf != 0) {
366 FAIL("Buf should have been deallocated by now");
367 return;
368 }
369
370 if (chan_idx == 0) {
371 buf = net_buf_alloc(&tx_data_pool_0, K_NO_WAIT);
372 } else {
373 buf = net_buf_alloc(&tx_data_pool_1, K_NO_WAIT);
374 }
375
376 if (buf == NULL) {
377 FAIL("Failed to get buff on ch %i, iteration %i should never happen", chan_idx,
378 chan_idx);
379 }
380
381 channels[chan_idx].buf = buf;
382 net_buf_reserve(buf, BT_L2CAP_SDU_CHAN_SEND_RESERVE);
383 net_buf_add_mem(buf, channels[chan_idx].payload, bytes);
384
385 LOG_DBG("bt_l2cap_chan_sending ch: %i bytes: %i iteration: %i", chan_idx, bytes, iteration);
386 const int ret = bt_l2cap_chan_send(chan, buf);
387
388 LOG_DBG("bt_l2cap_chan_send returned: %i", ret);
389
390 if (ret < 0) {
391 FAIL("Error: send failed error: %i", ret);
392 channels[chan_idx].buf = 0;
393 net_buf_unref(buf);
394 }
395 }
396
send_sdu_chan_worker(struct k_work * item)397 void send_sdu_chan_worker(struct k_work *item)
398 {
399 const struct channel *ch = CONTAINER_OF(item, struct channel, work);
400
401 send_sdu(ch->iteration, ch->chan_id, ch->bytes_to_send);
402 }
403
send_sdu_concurrently(void)404 static void send_sdu_concurrently(void)
405 {
406 for (int i = 0; i < SDU_SEND_COUNT; i++) {
407 for (int k = 0; k < L2CAP_CHANNELS; k++) {
408 channels[k].iteration = i;
409 /* Assign the right msg to the right channel */
410 channels[k].bytes_to_send = (k == LONG_MSG_CHAN_IDX) ? LONG_MSG : SHORT_MSG;
411 const int err = k_work_submit_to_queue(&channels[k].work_queue,
412 &channels[k].work);
413
414 if (err < 0) {
415 FAIL("Failed to submit work to the queue, error: %d", err);
416 }
417 }
418
419 /* Wait until messages on all of the channels has been sent */
420 for (int l = 0; l < L2CAP_CHANNELS; l++) {
421 k_sem_take(&sent_sem, K_FOREVER);
422 }
423 }
424 }
425
change_mtu_on_channels(int num_channels,int new_mtu)426 static int change_mtu_on_channels(int num_channels, int new_mtu)
427 {
428 struct bt_l2cap_chan *reconf_channels[ECRED_CHAN_MAX] = { NULL };
429
430 for (int i = 0; i < num_channels; i++) {
431 reconf_channels[i] = &(&channels[i])->le.chan;
432 }
433
434 return bt_l2cap_ecred_chan_reconfigure(reconf_channels, new_mtu);
435 }
436
test_peripheral_main(void)437 static void test_peripheral_main(void)
438 {
439 device_sync_init(PERIPHERAL_ID);
440 LOG_DBG("*L2CAP ECRED Peripheral started*");
441 init_workqs();
442 int err;
443
444 err = bt_enable(NULL);
445 if (err) {
446 FAIL("Can't enable Bluetooth (err %d)", err);
447 return;
448 }
449
450 LOG_DBG("Peripheral Bluetooth initialized.");
451 LOG_DBG("Connectable advertising...");
452 err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, ARRAY_SIZE(ad), NULL, 0);
453 if (err) {
454 FAIL("Advertising failed to start (err %d)", err);
455 return;
456 }
457
458 LOG_DBG("Advertising started.");
459 LOG_DBG("Peripheral waiting for connection...");
460 WAIT_FOR_FLAG_SET(is_connected);
461 LOG_DBG("Peripheral Connected.");
462 register_l2cap_server();
463 connect_num_channels(L2CAP_CHANNELS);
464 k_sem_take(&all_chan_conn_sem, K_FOREVER);
465
466 /* Disconnect and reconnect channels *****************************************************/
467 LOG_DBG("############# Disconnect and reconnect channels");
468 disconnect_all_channels();
469 k_sem_take(&all_chan_disconn_sem, K_FOREVER);
470
471 connect_num_channels(L2CAP_CHANNELS);
472 k_sem_take(&all_chan_conn_sem, K_FOREVER);
473
474 LOG_DBG("Send sync after reconnection");
475 device_sync_send();
476
477 /* Send bytes on both channels and expect ch 1 to receive all of them before ch 0 *********/
478 LOG_DBG("############# Send bytes on both channels concurrently");
479 send_sdu_concurrently();
480
481 /* Change mtu size on all connected channels *********************************************/
482 LOG_DBG("############# Change MTU of the channels");
483 err = change_mtu_on_channels(L2CAP_CHANNELS, CONFIG_BT_L2CAP_TX_MTU + 10);
484
485 if (err) {
486 FAIL("MTU change failed (err %d)\n", err);
487 }
488
489 /* Read from both devices (Central and Peripheral) at the same time **********************/
490 LOG_DBG("############# Read from both devices (Central and Peripheral) at the same time");
491 LOG_DBG("Wait for sync before sending the msg");
492 device_sync_wait();
493 LOG_DBG("Received sync");
494 send_sdu(0, 1, 10);
495
496 k_sem_take(&sent_sem, K_FOREVER);
497 disconnect_all_channels();
498 WAIT_FOR_FLAG_UNSET(is_connected);
499 PASS("L2CAP ECRED Peripheral tests Passed");
500 bs_trace_silent_exit(0);
501 }
502
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)503 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
504 struct net_buf_simple *ad)
505 {
506 struct bt_le_conn_param *param;
507 int err;
508
509 err = bt_le_scan_stop();
510 if (err) {
511 FAIL("Stop LE scan failed (err %d)", err);
512 return;
513 }
514
515 param = BT_LE_CONN_PARAM_DEFAULT;
516 err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &default_conn);
517 if (err) {
518 FAIL("Create conn failed (err %d)", err);
519 return;
520 }
521 }
522
test_central_main(void)523 static void test_central_main(void)
524 {
525 struct bt_le_scan_param scan_param = {
526 .type = BT_LE_SCAN_TYPE_ACTIVE,
527 .options = BT_LE_SCAN_OPT_NONE,
528 .interval = BT_GAP_SCAN_FAST_INTERVAL,
529 .window = BT_GAP_SCAN_FAST_WINDOW,
530 };
531
532 device_sync_init(CENTRAL_ID);
533
534 LOG_DBG("*L2CAP ECRED Central started*");
535 int err;
536
537 err = bt_enable(NULL);
538 if (err) {
539 FAIL("Can't enable Bluetooth (err %d)\n", err);
540 return;
541 }
542 LOG_DBG("Central Bluetooth initialized.\n");
543
544 err = bt_le_scan_start(&scan_param, device_found);
545 if (err) {
546 FAIL("Scanning failed to start (err %d)\n", err);
547 return;
548 }
549
550 LOG_DBG("Scanning successfully started\n");
551
552 LOG_DBG("Central waiting for connection...\n");
553 WAIT_FOR_FLAG_SET(is_connected);
554 LOG_DBG("Central Connected.\n");
555 register_l2cap_server();
556
557 LOG_DBG("Wait for sync after reconnection");
558 device_sync_wait();
559 LOG_DBG("Received sync");
560
561 /* Read from both devices (Central and Peripheral) at the same time **********************/
562 LOG_DBG("############# Read from both devices (Central and Peripheral) at the same time");
563 LOG_DBG("Send sync for SDU send");
564 SET_FLAG(unsequenced_data);
565 device_sync_send();
566 send_sdu(0, 1, 10);
567
568 /* Wait until all of the channels are disconnected */
569 k_sem_take(&all_chan_disconn_sem, K_FOREVER);
570
571 LOG_DBG("Both l2cap channels disconnected, test over\n");
572
573 UNSET_FLAG(unsequenced_data);
574 LOG_DBG("received PDUs on long msg channel %i and short msg channel %i",
575 channels[LONG_MSG_CHAN_IDX].sdus_received,
576 channels[SHORT_MSG_CHAN_IDX].sdus_received);
577
578 if (channels[LONG_MSG_CHAN_IDX].sdus_received < SDU_SEND_COUNT ||
579 channels[SHORT_MSG_CHAN_IDX].sdus_received < SDU_SEND_COUNT) {
580 FAIL("received less than %i", SDU_SEND_COUNT);
581 }
582
583 /* Disconnect */
584 LOG_DBG("Central Disconnecting....");
585 err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
586 bt_conn_unref(default_conn);
587 LOG_DBG("Central tried to disconnect");
588
589 if (err) {
590 FAIL("Disconnection failed (err %d)", err);
591 return;
592 }
593
594 LOG_DBG("Central Disconnected.");
595
596 PASS("L2CAP ECRED Central tests Passed\n");
597 }
598
599 static const struct bst_test_instance test_def[] = {
600 {
601 .test_id = "peripheral",
602 .test_descr = "Peripheral L2CAP ECRED",
603 .test_pre_init_f = test_init,
604 .test_tick_f = test_tick,
605 .test_main_f = test_peripheral_main
606 },
607 {
608 .test_id = "central",
609 .test_descr = "Central L2CAP ECRED",
610 .test_pre_init_f = test_init,
611 .test_tick_f = test_tick,
612 .test_main_f = test_central_main
613 },
614 BSTEST_END_MARKER
615 };
616
test_main_l2cap_ecred_install(struct bst_test_list * tests)617 struct bst_test_list *test_main_l2cap_ecred_install(struct bst_test_list *tests)
618 {
619 return bst_add_tests(tests, test_def);
620 }
621