1 /*
2  * Copyright (c) 2019 Bose Corporation
3  * Copyright (c) 2020-2024 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <string.h>
11 
12 #include <zephyr/autoconf.h>
13 #include <zephyr/bluetooth/audio/bap.h>
14 #include <zephyr/bluetooth/audio/csip.h>
15 #include <zephyr/bluetooth/addr.h>
16 #include <zephyr/bluetooth/bluetooth.h>
17 #include <zephyr/bluetooth/conn.h>
18 #include <zephyr/bluetooth/gap.h>
19 #include <zephyr/bluetooth/hci_types.h>
20 #include <zephyr/kernel.h>
21 #include <zephyr/net_buf.h>
22 #include <zephyr/sys/printk.h>
23 #include <zephyr/sys/util.h>
24 
25 #include "bstests.h"
26 #include "common.h"
27 
28 #ifdef CONFIG_BT_CSIP_SET_COORDINATOR
29 
30 static bool expect_rank = true;
31 static bool expect_set_size = true;
32 static bool expect_lockable = true;
33 
34 extern enum bst_result_t bst_result;
35 static volatile bool discovered;
36 static volatile bool discover_timed_out;
37 static volatile bool set_locked;
38 static volatile bool set_unlocked;
39 static volatile bool ordered_access_locked;
40 static volatile bool ordered_access_unlocked;
41 static const struct bt_csip_set_coordinator_csis_inst *primary_inst;
42 CREATE_FLAG(flag_sirk_changed);
43 CREATE_FLAG(flag_size_changed);
44 
45 static uint8_t connected_member_count;
46 static uint8_t members_found;
47 static struct k_work_delayable discover_members_timer;
48 static bt_addr_le_t addr_found[CONFIG_BT_MAX_CONN];
49 static struct bt_conn *conns[CONFIG_BT_MAX_CONN];
50 static const struct bt_csip_set_coordinator_set_member *set_members[CONFIG_BT_MAX_CONN];
51 
52 static void csip_set_coordinator_lock_set_cb(int err);
53 
csip_set_coordinator_lock_release_cb(int err)54 static void csip_set_coordinator_lock_release_cb(int err)
55 {
56 	printk("%s\n", __func__);
57 
58 	if (err != 0) {
59 		FAIL("Release sets failed (%d)\n", err);
60 		return;
61 	}
62 
63 	set_unlocked = true;
64 }
65 
csip_set_coordinator_lock_set_cb(int err)66 static void csip_set_coordinator_lock_set_cb(int err)
67 {
68 	printk("%s\n", __func__);
69 
70 	if (err != 0) {
71 		FAIL("Lock sets failed (%d)\n", err);
72 		return;
73 	}
74 
75 	set_locked = true;
76 }
77 
csip_discover_cb(struct bt_conn * conn,const struct bt_csip_set_coordinator_set_member * member,int err,size_t set_count)78 static void csip_discover_cb(struct bt_conn *conn,
79 			     const struct bt_csip_set_coordinator_set_member *member,
80 			     int err, size_t set_count)
81 {
82 	uint8_t conn_index;
83 
84 	printk("%s\n", __func__);
85 
86 	if (err != 0 || set_count == 0U) {
87 		FAIL("Discover failed (%d)\n", err);
88 		return;
89 	}
90 
91 	conn_index = bt_conn_index(conn);
92 
93 	for (size_t i = 0U; i < set_count; i++) {
94 		const uint8_t rank = member->insts[i].info.rank;
95 		const uint8_t set_size = member->insts[i].info.set_size;
96 		const uint8_t lockable = member->insts[i].info.lockable;
97 
98 		printk("CSIS[%zu]: %p\n", i, &member->insts[i]);
99 		printk("\tRank: %u\n", rank);
100 		printk("\tSet Size: %u\n", set_size);
101 		printk("\tLockable: %u\n", lockable);
102 
103 		if ((expect_rank && rank == 0U) || (!expect_rank && rank != 0U)) {
104 			FAIL("Unexpected rank: %u %u", expect_rank, rank);
105 
106 			return;
107 		}
108 
109 		if ((expect_set_size && set_size == 0U) || (!expect_set_size && set_size != 0U)) {
110 			FAIL("Unexpected set_size: %u %u", expect_set_size, set_size);
111 
112 			return;
113 		}
114 
115 		if (expect_lockable != lockable) {
116 			FAIL("Unexpected lockable: %u %u", expect_lockable, lockable);
117 
118 			return;
119 		}
120 	}
121 
122 	if (primary_inst == NULL) {
123 		primary_inst = &member->insts[0];
124 	}
125 
126 	set_members[conn_index] = member;
127 	discovered = true;
128 }
129 
csip_lock_changed_cb(struct bt_csip_set_coordinator_csis_inst * inst,bool locked)130 static void csip_lock_changed_cb(struct bt_csip_set_coordinator_csis_inst *inst,
131 				 bool locked)
132 {
133 	printk("inst %p %s\n", inst, locked ? "locked" : "released");
134 }
135 
csip_sirk_changed_cb(struct bt_csip_set_coordinator_csis_inst * inst)136 static void csip_sirk_changed_cb(struct bt_csip_set_coordinator_csis_inst *inst)
137 {
138 	printk("Inst %p SIRK changed\n", inst);
139 
140 	SET_FLAG(flag_sirk_changed);
141 }
142 
csip_size_changed_cb(struct bt_conn * conn,const struct bt_csip_set_coordinator_csis_inst * inst)143 static void csip_size_changed_cb(struct bt_conn *conn,
144 				 const struct bt_csip_set_coordinator_csis_inst *inst)
145 {
146 	printk("Inst %p size changed: %u\n", inst, inst->info.set_size);
147 
148 	SET_FLAG(flag_size_changed);
149 }
150 
csip_set_coordinator_ordered_access_cb(const struct bt_csip_set_coordinator_set_info * set_info,int err,bool locked,struct bt_csip_set_coordinator_set_member * member)151 static void csip_set_coordinator_ordered_access_cb(
152 	const struct bt_csip_set_coordinator_set_info *set_info, int err,
153 	bool locked,  struct bt_csip_set_coordinator_set_member *member)
154 {
155 	if (err) {
156 		FAIL("Ordered access failed with err %d\n", err);
157 	} else if (locked) {
158 		printk("Ordered access procedure locked member %p\n", member);
159 		ordered_access_locked = true;
160 	} else {
161 		printk("Ordered access procedure finished\n");
162 		ordered_access_unlocked = true;
163 	}
164 }
165 
166 static struct bt_csip_set_coordinator_cb cbs = {
167 	.lock_set = csip_set_coordinator_lock_set_cb,
168 	.release_set = csip_set_coordinator_lock_release_cb,
169 	.discover = csip_discover_cb,
170 	.lock_changed = csip_lock_changed_cb,
171 	.sirk_changed = csip_sirk_changed_cb,
172 	.size_changed = csip_size_changed_cb,
173 	.ordered_access = csip_set_coordinator_ordered_access_cb,
174 };
175 
csip_set_coordinator_oap_cb(const struct bt_csip_set_coordinator_set_info * set_info,struct bt_csip_set_coordinator_set_member * members[],size_t count)176 static bool csip_set_coordinator_oap_cb(const struct bt_csip_set_coordinator_set_info *set_info,
177 					struct bt_csip_set_coordinator_set_member *members[],
178 					size_t count)
179 {
180 	for (size_t i = 0; i < count; i++) {
181 		printk("Ordered access for members[%zu]: %p\n", i, members[i]);
182 	}
183 
184 	return true;
185 }
186 
is_discovered(const bt_addr_le_t * addr)187 static bool is_discovered(const bt_addr_le_t *addr)
188 {
189 	for (int i = 0; i < members_found; i++) {
190 		if (bt_addr_le_eq(addr, &addr_found[i])) {
191 			return true;
192 		}
193 	}
194 	return false;
195 }
196 
csip_found(struct bt_data * data,void * user_data)197 static bool csip_found(struct bt_data *data, void *user_data)
198 {
199 	if (primary_inst == NULL ||
200 	    bt_csip_set_coordinator_is_set_member(primary_inst->info.sirk, data)) {
201 		const bt_addr_le_t *addr = user_data;
202 		char addr_str[BT_ADDR_LE_STR_LEN];
203 
204 		bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
205 		printk("Found CSIP advertiser with address %s\n", addr_str);
206 
207 		if (is_discovered(addr)) {
208 			printk("Set member already found\n");
209 			/* Stop parsing */
210 			return false;
211 		}
212 
213 		bt_addr_le_copy(&addr_found[members_found++], addr);
214 
215 		if (primary_inst == NULL || primary_inst->info.set_size == 0) {
216 			printk("Found member %u\n", members_found);
217 		} else {
218 			printk("Found member (%u / %u)\n", members_found,
219 			       primary_inst->info.set_size);
220 		}
221 
222 		/* Stop parsing */
223 		return false;
224 	}
225 	/* Continue parsing */
226 	return true;
227 }
228 
csip_set_coordinator_scan_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * ad)229 static void csip_set_coordinator_scan_recv(const struct bt_le_scan_recv_info *info,
230 					   struct net_buf_simple *ad)
231 {
232 	/* We're only interested in connectable events */
233 	if ((info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) != 0U &&
234 	    (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0U) {
235 		bt_data_parse(ad, csip_found, (void *)info->addr);
236 	}
237 }
238 
239 static struct bt_le_scan_cb csip_set_coordinator_scan_callbacks = {
240 	.recv = csip_set_coordinator_scan_recv
241 };
242 
discover_members_timer_handler(struct k_work * work)243 static void discover_members_timer_handler(struct k_work *work)
244 {
245 	if (primary_inst->info.set_size > 0) {
246 		FAIL("Could not find all members (%u / %u)\n", members_found,
247 		     primary_inst->info.set_size);
248 	} else {
249 		discover_timed_out = true;
250 	}
251 }
252 
ordered_access(const struct bt_csip_set_coordinator_set_member ** members,size_t count,bool expect_locked)253 static void ordered_access(const struct bt_csip_set_coordinator_set_member **members,
254 			   size_t count, bool expect_locked)
255 {
256 	int err;
257 
258 	printk("Performing ordered access, expecting %s\n",
259 	       expect_locked ? "locked" : "unlocked");
260 
261 	if (expect_locked) {
262 		ordered_access_locked = false;
263 	} else {
264 		ordered_access_unlocked = false;
265 	}
266 
267 	err = bt_csip_set_coordinator_ordered_access(members, count, &primary_inst->info,
268 						     csip_set_coordinator_oap_cb);
269 	if (err != 0) {
270 		FAIL("Failed to do CSIP set coordinator ordered access (%d)",
271 		      err);
272 		return;
273 	}
274 
275 	if (expect_locked) {
276 		WAIT_FOR_COND(ordered_access_locked);
277 	} else {
278 		WAIT_FOR_COND(ordered_access_unlocked);
279 	}
280 }
281 
discover_csis(struct bt_conn * conn)282 static void discover_csis(struct bt_conn *conn)
283 {
284 	int err;
285 
286 	discovered = false;
287 
288 	err = bt_csip_set_coordinator_discover(conns[bt_conn_index(conn)]);
289 	if (err != 0) {
290 		FAIL("Failed to initialize set coordinator for connection %d\n", err);
291 		return;
292 	}
293 
294 	WAIT_FOR_COND(discovered);
295 }
296 
init(void)297 static void init(void)
298 {
299 	int err;
300 
301 	err = bt_enable(NULL);
302 	if (err != 0) {
303 		FAIL("Bluetooth init failed (err %d)\n", err);
304 		return;
305 	}
306 
307 	printk("Audio Client: Bluetooth initialized\n");
308 
309 	bt_csip_set_coordinator_register_cb(&cbs);
310 	k_work_init_delayable(&discover_members_timer,
311 			      discover_members_timer_handler);
312 	bt_le_scan_cb_register(&csip_set_coordinator_scan_callbacks);
313 }
314 
connect_set(void)315 static void connect_set(void)
316 {
317 	char addr[BT_ADDR_LE_STR_LEN];
318 	int err;
319 
320 	connected_member_count = 0U;
321 
322 	err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
323 	if (err != 0) {
324 		FAIL("Scanning failed to start (err %d)\n", err);
325 
326 		return;
327 	}
328 
329 	printk("Scanning successfully started\n");
330 
331 	WAIT_FOR_COND(members_found == 1U);
332 
333 	printk("Stopping scan\n");
334 	err = bt_le_scan_stop();
335 	if (err != 0) {
336 		FAIL("Could not stop scan");
337 
338 		return;
339 	}
340 
341 	bt_addr_le_to_str(&addr_found[0], addr, sizeof(addr));
342 	err = bt_conn_le_create(&addr_found[0], BT_CONN_LE_CREATE_CONN, BT_BAP_CONN_PARAM_RELAXED,
343 				&conns[0]);
344 	if (err != 0) {
345 		FAIL("Failed to connect to %s: %d\n", err);
346 
347 		return;
348 	}
349 	printk("Connecting to %s\n", addr);
350 
351 	WAIT_FOR_FLAG(flag_connected);
352 	connected_member_count++;
353 
354 	discover_csis(conns[0]);
355 	discover_csis(conns[0]); /* test that we can discover twice */
356 
357 	err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL);
358 	if (err != 0) {
359 		FAIL("Could not start scan: %d", err);
360 
361 		return;
362 	}
363 
364 	err = k_work_reschedule(&discover_members_timer,
365 				BT_CSIP_SET_COORDINATOR_DISCOVER_TIMER_VALUE);
366 	if (err < 0) { /* Can return 0, 1 and 2 for success */
367 		FAIL("Could not schedule discover_members_timer %d", err);
368 
369 		return;
370 	}
371 
372 	if (primary_inst->info.set_size > 0U) {
373 		WAIT_FOR_COND(members_found == primary_inst->info.set_size);
374 
375 		(void)k_work_cancel_delayable(&discover_members_timer);
376 	} else {
377 		WAIT_FOR_COND(discover_timed_out);
378 	}
379 
380 	err = bt_le_scan_stop();
381 	if (err != 0) {
382 		FAIL("Scanning failed to stop (err %d)\n", err);
383 
384 		return;
385 	}
386 
387 	for (uint8_t i = 1; i < members_found; i++) {
388 		bt_addr_le_to_str(&addr_found[i], addr, sizeof(addr));
389 
390 		UNSET_FLAG(flag_connected);
391 		printk("Connecting to member[%d] (%s)", i, addr);
392 		err = bt_conn_le_create(&addr_found[i], BT_CONN_LE_CREATE_CONN,
393 					BT_LE_CONN_PARAM_DEFAULT, &conns[i]);
394 		if (err != 0) {
395 			FAIL("Failed to connect to %s: %d\n", addr, err);
396 
397 			return;
398 		}
399 
400 		printk("Connected to %s\n", addr);
401 		WAIT_FOR_FLAG(flag_connected);
402 		connected_member_count++;
403 
404 		printk("Doing discovery on member[%u]", i);
405 		discover_csis(conns[i]);
406 	}
407 }
408 
disconnect_set(void)409 static void disconnect_set(void)
410 {
411 	for (uint8_t i = 0; i < connected_member_count; i++) {
412 		char addr[BT_ADDR_LE_STR_LEN];
413 		int err;
414 
415 		bt_addr_le_to_str(&addr_found[i], addr, sizeof(addr));
416 
417 		printk("Disconnecting member[%u] (%s)", i, addr);
418 		err = bt_conn_disconnect(conns[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
419 		(void)memset(&set_members[i], 0, sizeof(set_members[i]));
420 		if (err != 0) {
421 			FAIL("Failed to do disconnect\n", err);
422 			return;
423 		}
424 	}
425 }
426 
test_main(void)427 static void test_main(void)
428 {
429 	const struct bt_csip_set_coordinator_set_member *locked_members[CONFIG_BT_MAX_CONN];
430 	int err;
431 
432 	init();
433 	connect_set();
434 
435 	for (size_t i = 0; i < ARRAY_SIZE(locked_members); i++) {
436 		locked_members[i] = set_members[i];
437 	}
438 
439 	if (primary_inst->info.rank != 0U) {
440 		ordered_access(locked_members, connected_member_count, false);
441 	}
442 
443 	if (primary_inst->info.lockable) {
444 		printk("Locking set\n");
445 		err = bt_csip_set_coordinator_lock(locked_members, connected_member_count,
446 						   &primary_inst->info);
447 		if (err != 0) {
448 			FAIL("Failed to do set coordinator lock (%d)", err);
449 			return;
450 		}
451 
452 		WAIT_FOR_COND(set_locked);
453 	}
454 
455 	if (primary_inst->info.rank != 0U) {
456 		ordered_access(locked_members, connected_member_count, primary_inst->info.lockable);
457 	}
458 
459 	k_sleep(K_MSEC(1000)); /* Simulate doing stuff */
460 
461 	if (primary_inst->info.lockable) {
462 		printk("Releasing set\n");
463 		err = bt_csip_set_coordinator_release(locked_members, connected_member_count,
464 						      &primary_inst->info);
465 		if (err != 0) {
466 			FAIL("Failed to do set coordinator release (%d)", err);
467 			return;
468 		}
469 
470 		WAIT_FOR_COND(set_unlocked);
471 	}
472 
473 	if (primary_inst->info.rank != 0U) {
474 		ordered_access(locked_members, connected_member_count, false);
475 	}
476 
477 	if (primary_inst->info.lockable) {
478 		/* Lock and unlock again */
479 		set_locked = false;
480 		set_unlocked = false;
481 
482 		printk("Locking set\n");
483 		err = bt_csip_set_coordinator_lock(locked_members, connected_member_count,
484 						   &primary_inst->info);
485 		if (err != 0) {
486 			FAIL("Failed to do set coordinator lock (%d)", err);
487 			return;
488 		}
489 
490 		WAIT_FOR_COND(set_locked);
491 	}
492 
493 	k_sleep(K_MSEC(1000)); /* Simulate doing stuff */
494 
495 	if (primary_inst->info.lockable) {
496 		printk("Releasing set\n");
497 		err = bt_csip_set_coordinator_release(locked_members, connected_member_count,
498 						      &primary_inst->info);
499 		if (err != 0) {
500 			FAIL("Failed to do set coordinator release (%d)", err);
501 			return;
502 		}
503 
504 		WAIT_FOR_COND(set_unlocked);
505 	}
506 
507 	disconnect_set();
508 
509 	PASS("All members disconnected\n");
510 }
511 
test_new_sirk(void)512 static void test_new_sirk(void)
513 {
514 	init();
515 	connect_set();
516 
517 	backchannel_sync_send_all();
518 	backchannel_sync_wait_all();
519 
520 	WAIT_FOR_FLAG(flag_sirk_changed);
521 
522 	disconnect_set();
523 
524 	PASS("All members disconnected\n");
525 }
526 
test_new_size_and_rank(void)527 static void test_new_size_and_rank(void)
528 {
529 	init();
530 	connect_set();
531 
532 	backchannel_sync_send_all();
533 	backchannel_sync_wait_all();
534 
535 	/* We won't get a new rank in a notification. For this test we only verify that we get a new
536 	 * size
537 	 */
538 	WAIT_FOR_FLAG(flag_size_changed);
539 
540 	disconnect_set();
541 
542 	PASS("All members disconnected\n");
543 }
544 
test_args(int argc,char * argv[])545 static void test_args(int argc, char *argv[])
546 {
547 	for (int argn = 0; argn < argc; argn++) {
548 		const char *arg = argv[argn];
549 
550 		if (strcmp(arg, "no-size") == 0) {
551 			expect_set_size = false;
552 		} else if (strcmp(arg, "no-rank") == 0) {
553 			expect_rank = false;
554 		} else if (strcmp(arg, "no-lock") == 0) {
555 			expect_lockable = false;
556 		} else {
557 			FAIL("Invalid arg: %s", arg);
558 		}
559 	}
560 }
561 
562 static const struct bst_test_instance test_connect[] = {
563 	{
564 		.test_id = "csip_set_coordinator",
565 		.test_pre_init_f = test_init,
566 		.test_tick_f = test_tick,
567 		.test_main_f = test_main,
568 		.test_args_f = test_args,
569 	},
570 	{
571 		.test_id = "csip_set_coordinator_new_sirk",
572 		.test_pre_init_f = test_init,
573 		.test_tick_f = test_tick,
574 		.test_main_f = test_new_sirk,
575 		.test_args_f = test_args,
576 	},
577 	{
578 		.test_id = "csip_set_coordinator_new_size_and_rank",
579 		.test_pre_init_f = test_init,
580 		.test_tick_f = test_tick,
581 		.test_main_f = test_new_size_and_rank,
582 		.test_args_f = test_args,
583 	},
584 	BSTEST_END_MARKER,
585 };
586 
test_csip_set_coordinator_install(struct bst_test_list * tests)587 struct bst_test_list *test_csip_set_coordinator_install(struct bst_test_list *tests)
588 {
589 	return bst_add_tests(tests, test_connect);
590 }
591 #else
test_csip_set_coordinator_install(struct bst_test_list * tests)592 struct bst_test_list *test_csip_set_coordinator_install(struct bst_test_list *tests)
593 {
594 	return tests;
595 }
596 
597 #endif /* CONFIG_BT_CSIP_SET_COORDINATOR */
598