1 /**
2  * @file
3  * @brief Shell APIs for Bluetooth BAP scan delegator
4  *
5  * Copyright (c) 2020-2022 Nordic Semiconductor ASA
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 
10 #include <errno.h>
11 #include <stdbool.h>
12 #include <stddef.h>
13 #include <stdint.h>
14 #include <string.h>
15 
16 #include <zephyr/autoconf.h>
17 #include <zephyr/bluetooth/audio/audio.h>
18 #include <zephyr/bluetooth/audio/bap.h>
19 #include <zephyr/bluetooth/addr.h>
20 #include <zephyr/bluetooth/bluetooth.h>
21 #include <zephyr/bluetooth/conn.h>
22 #include <zephyr/bluetooth/gap.h>
23 #include <zephyr/bluetooth/gatt.h>
24 #include <zephyr/bluetooth/iso.h>
25 #include <zephyr/bluetooth/uuid.h>
26 #include <zephyr/kernel.h>
27 #include <zephyr/shell/shell.h>
28 #include <zephyr/shell/shell_string_conv.h>
29 #include <zephyr/sys/__assert.h>
30 #include <zephyr/sys/printk.h>
31 #include <zephyr/sys/util.h>
32 #include <zephyr/types.h>
33 
34 #include <audio/bap_internal.h>
35 #include "host/shell/bt.h"
36 
37 #define PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO 20 /* Set the timeout relative to interval */
38 #define PA_SYNC_SKIP              5
39 
40 static struct sync_state {
41 	bool pa_syncing;
42 	bool past_avail;
43 	uint8_t src_id;
44 	uint16_t pa_interval;
45 	struct k_work_delayable pa_timer;
46 	struct bt_conn *conn;
47 	struct bt_le_per_adv_sync *pa_sync;
48 	const struct bt_bap_scan_delegator_recv_state *recv_state;
49 	uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE];
50 } sync_states[CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT];
51 
52 static bool past_preference = true;
53 
bap_scan_delegator_ad_data_add(struct bt_data data[],size_t data_size)54 size_t bap_scan_delegator_ad_data_add(struct bt_data data[], size_t data_size)
55 {
56 	static uint8_t ad_bap_scan_delegator[2] = {
57 		BT_UUID_16_ENCODE(BT_UUID_BASS_VAL),
58 	};
59 
60 	__ASSERT(data_size > 0, "No space for ad_bap_scan_delegator");
61 	data[0].type = BT_DATA_SVC_DATA16;
62 	data[0].data_len = ARRAY_SIZE(ad_bap_scan_delegator);
63 	data[0].data = &ad_bap_scan_delegator[0];
64 
65 	return 1U;
66 }
67 
sync_state_get(const struct bt_bap_scan_delegator_recv_state * recv_state)68 static struct sync_state *sync_state_get(const struct bt_bap_scan_delegator_recv_state *recv_state)
69 {
70 	for (size_t i = 0U; i < ARRAY_SIZE(sync_states); i++) {
71 		if (sync_states[i].recv_state == recv_state) {
72 			return &sync_states[i];
73 		}
74 	}
75 
76 	return NULL;
77 }
78 
sync_state_get_or_new(const struct bt_bap_scan_delegator_recv_state * recv_state)79 static struct sync_state *sync_state_get_or_new(
80 	const struct bt_bap_scan_delegator_recv_state *recv_state)
81 {
82 	struct sync_state *free_state = NULL;
83 
84 	for (size_t i = 0U; i < ARRAY_SIZE(sync_states); i++) {
85 		if (sync_states[i].recv_state == NULL &&
86 		    free_state == NULL) {
87 			free_state = &sync_states[i];
88 		}
89 
90 		if (sync_states[i].recv_state == recv_state) {
91 			return &sync_states[i];
92 		}
93 	}
94 
95 	return free_state;
96 }
97 
sync_state_get_by_pa(struct bt_le_per_adv_sync * sync)98 static struct sync_state *sync_state_get_by_pa(struct bt_le_per_adv_sync *sync)
99 {
100 	for (size_t i = 0U; i < ARRAY_SIZE(sync_states); i++) {
101 		if (sync_states[i].pa_sync == sync) {
102 			return &sync_states[i];
103 		}
104 	}
105 
106 	return NULL;
107 }
108 
109 static struct sync_state *
sync_state_get_by_sync_info(const struct bt_le_per_adv_sync_synced_info * info)110 sync_state_get_by_sync_info(const struct bt_le_per_adv_sync_synced_info *info)
111 {
112 	for (size_t i = 0U; i < ARRAY_SIZE(sync_states); i++) {
113 		if (sync_states[i].recv_state != NULL &&
114 		    bt_addr_le_eq(info->addr, &sync_states[i].recv_state->addr) &&
115 		    info->sid == sync_states[i].recv_state->adv_sid) {
116 
117 			return &sync_states[i];
118 		}
119 	}
120 
121 	return NULL;
122 }
123 
sync_state_new(void)124 static struct sync_state *sync_state_new(void)
125 {
126 	for (size_t i = 0U; i < ARRAY_SIZE(sync_states); i++) {
127 		if (sync_states[i].recv_state == NULL) {
128 			return &sync_states[i];
129 		}
130 	}
131 
132 	return NULL;
133 }
134 
sync_state_get_by_src_id(uint8_t src_id)135 static struct sync_state *sync_state_get_by_src_id(uint8_t src_id)
136 {
137 	for (size_t i = 0U; i < ARRAY_SIZE(sync_states); i++) {
138 		if (sync_states[i].src_id == src_id) {
139 			return &sync_states[i];
140 		}
141 	}
142 
143 	return NULL;
144 }
145 
interval_to_sync_timeout(uint16_t pa_interval)146 static uint16_t interval_to_sync_timeout(uint16_t pa_interval)
147 {
148 	uint16_t pa_timeout;
149 
150 	if (pa_interval == BT_BAP_PA_INTERVAL_UNKNOWN) {
151 		/* Use maximum value to maximize chance of success */
152 		pa_timeout = BT_GAP_PER_ADV_MAX_TIMEOUT;
153 	} else {
154 		uint32_t interval_us;
155 		uint32_t timeout;
156 
157 		/* Add retries and convert to unit in 10's of ms */
158 		interval_us = BT_GAP_PER_ADV_INTERVAL_TO_US(pa_interval);
159 		timeout = BT_GAP_US_TO_PER_ADV_SYNC_TIMEOUT(interval_us) *
160 			  PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO;
161 
162 		/* Enforce restraints */
163 		pa_timeout = CLAMP(timeout, BT_GAP_PER_ADV_MIN_TIMEOUT, BT_GAP_PER_ADV_MAX_TIMEOUT);
164 	}
165 
166 	return pa_timeout;
167 }
168 
pa_timer_handler(struct k_work * work)169 static void pa_timer_handler(struct k_work *work)
170 {
171 	struct k_work_delayable *dwork = k_work_delayable_from_work(work);
172 	struct sync_state *state = CONTAINER_OF(dwork, struct sync_state, pa_timer);
173 
174 	state->pa_syncing = false;
175 
176 	if (state->recv_state != NULL) {
177 		enum bt_bap_pa_state pa_state;
178 
179 		if (state->recv_state->pa_sync_state == BT_BAP_PA_STATE_INFO_REQ) {
180 			pa_state = BT_BAP_PA_STATE_NO_PAST;
181 		} else {
182 			pa_state = BT_BAP_PA_STATE_FAILED;
183 		}
184 
185 		bt_bap_scan_delegator_set_pa_state(state->recv_state->src_id,
186 						   pa_state);
187 
188 		shell_info(ctx_shell, "PA timeout for %p", state->recv_state);
189 	}
190 }
191 
192 #if defined(CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER)
pa_sync_past(struct bt_conn * conn,struct sync_state * state,uint16_t pa_interval)193 static int pa_sync_past(struct bt_conn *conn,
194 			struct sync_state *state,
195 			uint16_t pa_interval)
196 {
197 	struct bt_le_per_adv_sync_transfer_param param = { 0 };
198 	int err;
199 
200 	param.skip = PA_SYNC_SKIP;
201 	param.timeout = interval_to_sync_timeout(pa_interval);
202 
203 	err = bt_le_per_adv_sync_transfer_subscribe(conn, &param);
204 	if (err != 0) {
205 		shell_info(ctx_shell, "Could not do PAST subscribe: %d", err);
206 	} else {
207 		shell_info(ctx_shell, "Syncing with PAST: %d", err);
208 		state->pa_syncing = true;
209 		k_work_init_delayable(&state->pa_timer, pa_timer_handler);
210 		(void)k_work_reschedule(&state->pa_timer,
211 					K_MSEC(param.timeout * 10));
212 	}
213 
214 	return err;
215 }
216 #endif /* CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER */
217 
pa_sync_no_past(struct sync_state * state,uint16_t pa_interval)218 static int pa_sync_no_past(struct sync_state *state,
219 			    uint16_t pa_interval)
220 {
221 	const struct bt_bap_scan_delegator_recv_state *recv_state;
222 	struct bt_le_per_adv_sync_param param = { 0 };
223 	int err;
224 
225 	recv_state = state->recv_state;
226 
227 	bt_addr_le_copy(&param.addr, &recv_state->addr);
228 	param.options = BT_LE_PER_ADV_SYNC_OPT_FILTER_DUPLICATE;
229 	param.sid = recv_state->adv_sid;
230 	param.skip = PA_SYNC_SKIP;
231 	param.timeout = interval_to_sync_timeout(pa_interval);
232 
233 	/* TODO: Validate that the advertise is broadcasting the same
234 	 * broadcast_id that the receive state has
235 	 */
236 	err = bt_le_per_adv_sync_create(&param, &state->pa_sync);
237 	if (err != 0) {
238 		shell_info(ctx_shell, "Could not sync per adv: %d", err);
239 	} else {
240 		char addr_str[BT_ADDR_LE_STR_LEN];
241 
242 		bt_addr_le_to_str(&recv_state->addr, addr_str, sizeof(addr_str));
243 		shell_info(ctx_shell, "PA sync pending for addr %s", addr_str);
244 		state->pa_syncing = true;
245 		k_work_init_delayable(&state->pa_timer, pa_timer_handler);
246 		(void)k_work_reschedule(&state->pa_timer,
247 					K_MSEC(param.timeout * 10));
248 	}
249 
250 	return err;
251 }
252 
pa_sync_term(struct sync_state * state)253 static int pa_sync_term(struct sync_state *state)
254 {
255 	int err;
256 
257 	(void)k_work_cancel_delayable(&state->pa_timer);
258 
259 	if (state->pa_sync == NULL) {
260 		return -1;
261 	}
262 
263 	shell_info(ctx_shell, "Deleting PA sync");
264 
265 	err = bt_le_per_adv_sync_delete(state->pa_sync);
266 	if (err != 0) {
267 		shell_error(ctx_shell, "Could not delete per adv sync: %d",
268 			    err);
269 	} else {
270 		state->pa_syncing = false;
271 		state->pa_sync = NULL;
272 	}
273 
274 	return err;
275 }
276 
recv_state_updated_cb(struct bt_conn * conn,const struct bt_bap_scan_delegator_recv_state * recv_state)277 static void recv_state_updated_cb(struct bt_conn *conn,
278 				  const struct bt_bap_scan_delegator_recv_state *recv_state)
279 {
280 	shell_info(ctx_shell, "Receive state with ID %u updated", recv_state->src_id);
281 }
282 
pa_sync_req_cb(struct bt_conn * conn,const struct bt_bap_scan_delegator_recv_state * recv_state,bool past_avail,uint16_t pa_interval)283 static int pa_sync_req_cb(struct bt_conn *conn,
284 			  const struct bt_bap_scan_delegator_recv_state *recv_state,
285 			  bool past_avail, uint16_t pa_interval)
286 {
287 	struct sync_state *state;
288 
289 	shell_info(ctx_shell,
290 		   "PA Sync request: past_avail %u, broadcast_id 0x%06X, pa_interval 0x%04x: %p",
291 		   past_avail, recv_state->broadcast_id, pa_interval,
292 		   recv_state);
293 
294 	state = sync_state_get_or_new(recv_state);
295 	if (state == NULL) {
296 		shell_error(ctx_shell, "Could not get state");
297 
298 		return -1;
299 	}
300 
301 	state->recv_state = recv_state;
302 	state->src_id = recv_state->src_id;
303 
304 	if (recv_state->pa_sync_state == BT_BAP_PA_STATE_SYNCED ||
305 	    recv_state->pa_sync_state == BT_BAP_PA_STATE_INFO_REQ) {
306 		/* Already syncing */
307 		/* TODO: Terminate existing sync and then sync to new?*/
308 		return -1;
309 	}
310 
311 	if (past_avail) {
312 		state->past_avail = past_preference;
313 		state->conn = bt_conn_ref(conn);
314 	} else {
315 		state->past_avail = false;
316 	}
317 
318 	return 0;
319 }
320 
pa_sync_term_req_cb(struct bt_conn * conn,const struct bt_bap_scan_delegator_recv_state * recv_state)321 static int pa_sync_term_req_cb(struct bt_conn *conn,
322 			       const struct bt_bap_scan_delegator_recv_state *recv_state)
323 {
324 	struct sync_state *state;
325 
326 	shell_info(ctx_shell, "PA Sync term request for %p", recv_state);
327 
328 	state = sync_state_get(recv_state);
329 	if (state == NULL) {
330 		shell_error(ctx_shell, "Could not get state");
331 
332 		return -1;
333 	}
334 
335 	return pa_sync_term(state);
336 }
337 
broadcast_code_cb(struct bt_conn * conn,const struct bt_bap_scan_delegator_recv_state * recv_state,const uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE])338 static void broadcast_code_cb(struct bt_conn *conn,
339 			      const struct bt_bap_scan_delegator_recv_state *recv_state,
340 			      const uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE])
341 {
342 	struct sync_state *state;
343 
344 	shell_info(ctx_shell, "Broadcast code received for %p", recv_state);
345 	shell_hexdump(ctx_shell, broadcast_code, BT_ISO_BROADCAST_CODE_SIZE);
346 
347 	state = sync_state_get(recv_state);
348 	if (state == NULL) {
349 		shell_error(ctx_shell, "Could not get state");
350 
351 		return;
352 	}
353 
354 	(void)memcpy(state->broadcast_code, broadcast_code, BT_ISO_BROADCAST_CODE_SIZE);
355 }
356 
bis_sync_req_cb(struct bt_conn * conn,const struct bt_bap_scan_delegator_recv_state * recv_state,const uint32_t bis_sync_req[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS])357 static int bis_sync_req_cb(struct bt_conn *conn,
358 			   const struct bt_bap_scan_delegator_recv_state *recv_state,
359 			   const uint32_t bis_sync_req[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS])
360 {
361 	printk("BIS sync request received for %p\n", recv_state);
362 
363 	for (int i = 0; i < CONFIG_BT_BAP_BASS_MAX_SUBGROUPS; i++) {
364 		printk("  [%d]: 0x%08x\n", i, bis_sync_req[i]);
365 	}
366 
367 	return 0;
368 }
369 
370 static struct bt_bap_scan_delegator_cb scan_delegator_cb = {
371 	.recv_state_updated = recv_state_updated_cb,
372 	.pa_sync_req = pa_sync_req_cb,
373 	.pa_sync_term_req = pa_sync_term_req_cb,
374 	.broadcast_code = broadcast_code_cb,
375 	.bis_sync_req = bis_sync_req_cb,
376 };
377 
pa_synced_cb(struct bt_le_per_adv_sync * sync,struct bt_le_per_adv_sync_synced_info * info)378 static void pa_synced_cb(struct bt_le_per_adv_sync *sync,
379 			 struct bt_le_per_adv_sync_synced_info *info)
380 {
381 	struct sync_state *state;
382 
383 	shell_info(ctx_shell, "PA %p synced", sync);
384 
385 	if (info->conn == NULL) {
386 		state = sync_state_get_by_pa(sync);
387 	} else {
388 		/* In case of PAST we need to use the addr instead */
389 		state = sync_state_get_by_sync_info(info);
390 	}
391 
392 	if (state == NULL) {
393 		shell_info(ctx_shell,
394 			   "Could not get sync state from PA sync %p",
395 			   sync);
396 		return;
397 	}
398 
399 	if (state->conn != NULL) {
400 		bt_conn_unref(state->conn);
401 		state->conn = NULL;
402 	}
403 
404 	k_work_cancel_delayable(&state->pa_timer);
405 }
406 
pa_term_cb(struct bt_le_per_adv_sync * sync,const struct bt_le_per_adv_sync_term_info * info)407 static void pa_term_cb(struct bt_le_per_adv_sync *sync,
408 		       const struct bt_le_per_adv_sync_term_info *info)
409 {
410 	struct sync_state *state;
411 
412 	shell_info(ctx_shell, "PA %p sync terminated", sync);
413 
414 	state = sync_state_get_by_pa(sync);
415 	if (state == NULL) {
416 		shell_error(ctx_shell,
417 			    "Could not get sync state from PA sync %p",
418 			    sync);
419 		return;
420 	}
421 
422 	if (state->conn != NULL) {
423 		bt_conn_unref(state->conn);
424 		state->conn = NULL;
425 	}
426 
427 	k_work_cancel_delayable(&state->pa_timer);
428 }
429 
430 static struct bt_le_per_adv_sync_cb pa_sync_cb =  {
431 	.synced = pa_synced_cb,
432 	.term = pa_term_cb,
433 };
434 
cmd_bap_scan_delegator_init(const struct shell * sh,size_t argc,char ** argv)435 static int cmd_bap_scan_delegator_init(const struct shell *sh, size_t argc,
436 				       char **argv)
437 {
438 	static bool registered;
439 
440 	if (!registered) {
441 		int err;
442 
443 		err = bt_bap_scan_delegator_register(&scan_delegator_cb);
444 		if (err) {
445 			shell_error(sh, "Failed to register scan delegator (err: %d)", err);
446 			return -ENOEXEC;
447 		}
448 
449 		err = bt_le_per_adv_sync_cb_register(&pa_sync_cb);
450 		if (err) {
451 			shell_error(sh, "Failed to register PA sync callbacks (err: %d)", err);
452 			return -ENOEXEC;
453 		}
454 
455 		registered = true;
456 	}
457 
458 	return 0;
459 }
cmd_bap_scan_delegator_set_past_pref(const struct shell * sh,size_t argc,char ** argv)460 static int cmd_bap_scan_delegator_set_past_pref(const struct shell *sh,
461 						size_t argc, char **argv)
462 {
463 	bool past_pref;
464 	int err;
465 
466 	err = 0;
467 
468 	past_pref = shell_strtobool(argv[1], 10, &err);
469 	if (err != 0) {
470 		shell_error(sh, "Failed to parse past_pref from %s", argv[1]);
471 		return -ENOEXEC;
472 	}
473 
474 	past_preference = past_pref;
475 
476 	return 0;
477 }
478 
cmd_bap_scan_delegator_sync_pa(const struct shell * sh,size_t argc,char ** argv)479 static int cmd_bap_scan_delegator_sync_pa(const struct shell *sh, size_t argc,
480 					  char **argv)
481 {
482 	struct sync_state *state;
483 	unsigned long src_id;
484 	int err;
485 
486 	err = 0;
487 
488 	src_id = shell_strtoul(argv[1], 16, &err);
489 	if (err != 0) {
490 		shell_error(sh, "Failed to parse src_id from %s", argv[1]);
491 
492 		return -ENOEXEC;
493 	}
494 
495 	if (src_id > UINT8_MAX) {
496 		shell_error(sh, "src_id shall be 0x00-0xff");
497 
498 		return -ENOEXEC;
499 	}
500 
501 	state = sync_state_get_by_src_id((uint8_t)src_id);
502 	if (state == NULL) {
503 		shell_error(ctx_shell, "Could not get state");
504 
505 		return -ENOEXEC;
506 	}
507 
508 	if (0) {
509 #if defined(CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER)
510 	} else if (past_preference &&
511 		   state->past_avail &&
512 		   state->conn != NULL) {
513 		shell_info(sh, "Syncing with PAST");
514 
515 		err = pa_sync_past(state->conn, state, state->pa_interval);
516 		if (err == 0) {
517 			err = bt_bap_scan_delegator_set_pa_state(src_id,
518 								 BT_BAP_PA_STATE_INFO_REQ);
519 			if (err != 0) {
520 				shell_error(sh,
521 					    "Failed to set INFO_REQ state: %d",
522 					    err);
523 			}
524 
525 			return -ENOEXEC;
526 		}
527 #endif /* CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER */
528 	} else {
529 		shell_info(sh, "Syncing without PAST");
530 		err = pa_sync_no_past(state, state->pa_interval);
531 	}
532 
533 	if (err != 0) {
534 		shell_error(sh, "Failed PA sync: %d", err);
535 
536 		return -ENOEXEC;
537 	}
538 
539 	return 0;
540 }
541 
cmd_bap_scan_delegator_term_pa(const struct shell * sh,size_t argc,char ** argv)542 static int cmd_bap_scan_delegator_term_pa(const struct shell *sh, size_t argc,
543 					  char **argv)
544 {
545 	struct sync_state *state;
546 	unsigned long src_id;
547 	int err;
548 
549 	err = 0;
550 
551 	src_id = shell_strtoul(argv[1], 16, &err);
552 	if (err != 0) {
553 		shell_error(sh, "Failed to parse src_id from %s", argv[1]);
554 
555 		return -ENOEXEC;
556 	}
557 
558 	if (src_id > UINT8_MAX) {
559 		shell_error(sh, "src_id shall be 0x00-0xff");
560 
561 		return -ENOEXEC;
562 	}
563 
564 	state = sync_state_get_by_src_id((uint8_t)src_id);
565 	if (state == NULL) {
566 		shell_error(ctx_shell, "Could not get state");
567 
568 		return -ENOEXEC;
569 	}
570 
571 	err = pa_sync_term(state);
572 	if (err != 0) {
573 		shell_error(ctx_shell, "Failed to terminate PA sync: %d", err);
574 
575 		return -ENOEXEC;
576 	}
577 
578 	return 0;
579 }
580 
cmd_bap_scan_delegator_add_src(const struct shell * sh,size_t argc,char ** argv)581 static int cmd_bap_scan_delegator_add_src(const struct shell *sh, size_t argc, char **argv)
582 {
583 	struct bt_bap_scan_delegator_add_src_param param = {0};
584 	struct bt_bap_bass_subgroup *subgroup_param;
585 	unsigned long broadcast_id;
586 	struct sync_state *state;
587 	unsigned long enc_state;
588 	unsigned long adv_sid;
589 	int err;
590 
591 	err = bt_addr_le_from_str(argv[1], argv[2], &param.addr);
592 	if (err != 0) {
593 		shell_error(sh, "Invalid peer address (err %d)", err);
594 
595 		return -ENOEXEC;
596 	}
597 
598 	adv_sid = shell_strtoul(argv[3], 0, &err);
599 	if (err != 0) {
600 		shell_error(sh, "Could not parse adv_sid: %d", err);
601 
602 		return -ENOEXEC;
603 	}
604 
605 	if (adv_sid > BT_GAP_SID_MAX) {
606 		shell_error(sh, "Invalid adv_sid: %lu", adv_sid);
607 
608 		return -ENOEXEC;
609 	}
610 
611 	param.sid = adv_sid;
612 
613 	broadcast_id = shell_strtoul(argv[4], 16, &err);
614 	if (err != 0) {
615 		shell_error(sh, "Failed to parse broadcast_id from %s", argv[1]);
616 
617 		return -EINVAL;
618 	}
619 
620 	if (broadcast_id > BT_AUDIO_BROADCAST_ID_MAX) {
621 		shell_error(sh, "Invalid broadcast_id %lu", broadcast_id);
622 
623 		return -EINVAL;
624 	}
625 
626 	enc_state = shell_strtoul(argv[5], 16, &err);
627 	if (err != 0) {
628 		shell_error(sh, "Failed to parse enc_state from %s", argv[2]);
629 
630 		return -EINVAL;
631 	}
632 
633 	if (enc_state > BT_BAP_BIG_ENC_STATE_BAD_CODE) {
634 		shell_error(sh, "Invalid enc_state %s", bt_bap_big_enc_state_str(enc_state));
635 
636 		return -EINVAL;
637 	}
638 
639 	/* TODO: Support multiple subgroups */
640 	subgroup_param = &param.subgroups[0];
641 	if (argc > 6) {
642 		unsigned long bis_sync;
643 
644 		bis_sync = shell_strtoul(argv[6], 16, &err);
645 		if (err != 0) {
646 			shell_error(sh, "Failed to parse bis_sync from %s", argv[3]);
647 
648 			return -EINVAL;
649 		}
650 
651 		if (bis_sync > BT_BAP_BIS_SYNC_NO_PREF) {
652 			shell_error(sh, "Invalid bis_sync %lu", bis_sync);
653 
654 			return -EINVAL;
655 		}
656 	} else {
657 		subgroup_param->bis_sync = 0U;
658 	}
659 
660 	if (argc > 7) {
661 		subgroup_param->metadata_len =
662 			hex2bin(argv[4], strlen(argv[7]), subgroup_param->metadata,
663 				sizeof(subgroup_param->metadata));
664 
665 		if (subgroup_param->metadata_len == 0U) {
666 			shell_error(sh, "Could not parse metadata");
667 
668 			return -EINVAL;
669 		}
670 	} else {
671 		subgroup_param->metadata_len = 0U;
672 	}
673 
674 	state = sync_state_new();
675 	if (state == NULL) {
676 		shell_error(ctx_shell, "Could not get new state");
677 
678 		return -ENOEXEC;
679 	}
680 
681 	param.encrypt_state = (enum bt_bap_big_enc_state)enc_state;
682 	param.broadcast_id = broadcast_id;
683 	param.num_subgroups = 1U;
684 
685 	err = bt_bap_scan_delegator_add_src(&param);
686 	if (err < 0) {
687 		shell_error(ctx_shell, "Failed to add source: %d", err);
688 
689 		return -ENOEXEC;
690 	}
691 
692 	state->src_id = (uint8_t)err;
693 
694 	return 0;
695 }
696 
cmd_bap_scan_delegator_add_src_by_pa_sync(const struct shell * sh,size_t argc,char ** argv)697 static int cmd_bap_scan_delegator_add_src_by_pa_sync(const struct shell *sh, size_t argc,
698 						     char **argv)
699 {
700 	struct bt_le_per_adv_sync *pa_sync = per_adv_syncs[selected_per_adv_sync];
701 	struct bt_bap_scan_delegator_add_src_param param = {0};
702 	struct bt_bap_bass_subgroup *subgroup_param;
703 	struct bt_le_per_adv_sync_info sync_info;
704 	unsigned long broadcast_id;
705 	struct sync_state *state;
706 	unsigned long enc_state;
707 	int err;
708 
709 	err = bt_le_per_adv_sync_get_info(pa_sync, &sync_info);
710 	if (err != 0) {
711 		shell_error(sh, "Failed to get sync info: %d", err);
712 
713 		return -ENOEXEC;
714 	}
715 	bt_addr_le_copy(&param.addr, &sync_info.addr);
716 	param.sid = sync_info.sid;
717 
718 	broadcast_id = shell_strtoul(argv[1], 16, &err);
719 	if (err != 0) {
720 		shell_error(sh, "Failed to parse broadcast_id from %s", argv[1]);
721 
722 		return -EINVAL;
723 	}
724 
725 	if (broadcast_id > BT_AUDIO_BROADCAST_ID_MAX) {
726 		shell_error(sh, "Invalid broadcast_id %lu", broadcast_id);
727 
728 		return -EINVAL;
729 	}
730 
731 	enc_state = shell_strtoul(argv[2], 16, &err);
732 	if (err != 0) {
733 		shell_error(sh, "Failed to parse enc_state from %s", argv[2]);
734 
735 		return -EINVAL;
736 	}
737 
738 	if (enc_state > BT_BAP_BIG_ENC_STATE_BAD_CODE) {
739 		shell_error(sh, "Invalid enc_state %s", bt_bap_big_enc_state_str(enc_state));
740 
741 		return -EINVAL;
742 	}
743 
744 	/* TODO: Support multiple subgroups */
745 	subgroup_param = &param.subgroups[0];
746 	if (argc > 3) {
747 		unsigned long bis_sync;
748 
749 		bis_sync = shell_strtoul(argv[3], 16, &err);
750 		if (err != 0) {
751 			shell_error(sh, "Failed to parse bis_sync from %s", argv[3]);
752 
753 			return -EINVAL;
754 		}
755 
756 		if (bis_sync > BT_BAP_BIS_SYNC_NO_PREF) {
757 			shell_error(sh, "Invalid bis_sync %lu", bis_sync);
758 
759 			return -EINVAL;
760 		}
761 	} else {
762 		subgroup_param->bis_sync = 0U;
763 	}
764 
765 	if (argc > 4) {
766 		subgroup_param->metadata_len =
767 			hex2bin(argv[4], strlen(argv[4]), subgroup_param->metadata,
768 				sizeof(subgroup_param->metadata));
769 
770 		if (subgroup_param->metadata_len == 0U) {
771 			shell_error(sh, "Could not parse metadata");
772 
773 			return -EINVAL;
774 		}
775 	} else {
776 		subgroup_param->metadata_len = 0U;
777 	}
778 
779 	state = sync_state_new();
780 	if (state == NULL) {
781 		shell_error(ctx_shell, "Could not get new state");
782 
783 		return -ENOEXEC;
784 	}
785 
786 	param.encrypt_state = (enum bt_bap_big_enc_state)enc_state;
787 	param.broadcast_id = broadcast_id;
788 	param.num_subgroups = 1U;
789 
790 	err = bt_bap_scan_delegator_add_src(&param);
791 	if (err < 0) {
792 		shell_error(ctx_shell, "Failed to add source: %d", err);
793 
794 		return -ENOEXEC;
795 	}
796 
797 	state->src_id = (uint8_t)err;
798 
799 	return 0;
800 }
801 
cmd_bap_scan_delegator_mod_src(const struct shell * sh,size_t argc,char ** argv)802 static int cmd_bap_scan_delegator_mod_src(const struct shell *sh, size_t argc,
803 					  char **argv)
804 {
805 	struct bt_bap_bass_subgroup *subgroup_param;
806 	struct bt_bap_scan_delegator_mod_src_param param;
807 	unsigned long broadcast_id;
808 	unsigned long enc_state;
809 	unsigned long src_id;
810 	int err;
811 
812 	err = 0;
813 
814 	src_id = shell_strtoul(argv[1], 16, &err);
815 	if (err != 0) {
816 		shell_error(sh, "Failed to parse src_id from %s", argv[1]);
817 
818 		return -EINVAL;
819 	}
820 
821 	if (src_id > UINT8_MAX) {
822 		shell_error(sh, "Invalid src_id %lu", src_id);
823 
824 		return -EINVAL;
825 	}
826 
827 	broadcast_id = shell_strtoul(argv[2], 16, &err);
828 	if (err != 0) {
829 		shell_error(sh, "Failed to parse broadcast_id from %s", argv[2]);
830 
831 		return -EINVAL;
832 	}
833 
834 	if (broadcast_id > BT_AUDIO_BROADCAST_ID_MAX) {
835 		shell_error(sh, "Invalid broadcast_id %lu", broadcast_id);
836 
837 		return -EINVAL;
838 	}
839 
840 	enc_state = shell_strtoul(argv[3], 16, &err);
841 	if (err != 0) {
842 		shell_error(sh, "Failed to parse enc_state from %s", argv[3]);
843 
844 		return -EINVAL;
845 	}
846 
847 	if (enc_state > BT_BAP_BIG_ENC_STATE_BAD_CODE) {
848 		shell_error(sh, "Invalid enc_state %s", bt_bap_big_enc_state_str(enc_state));
849 
850 		return -EINVAL;
851 	}
852 
853 	/* TODO: Support multiple subgroups */
854 	subgroup_param = &param.subgroups[0];
855 	if (argc > 4) {
856 		unsigned long bis_sync;
857 
858 		bis_sync = shell_strtoul(argv[4], 16, &err);
859 		if (err != 0) {
860 			shell_error(sh, "Failed to parse bis_sync from %s", argv[4]);
861 
862 			return -EINVAL;
863 		}
864 
865 		if (bis_sync > BT_BAP_BIS_SYNC_NO_PREF) {
866 			shell_error(sh, "Invalid bis_sync %lu", bis_sync);
867 
868 			return -EINVAL;
869 		}
870 	} else {
871 		subgroup_param->bis_sync = 0U;
872 	}
873 
874 	if (argc > 5) {
875 		subgroup_param->metadata_len = hex2bin(argv[5], strlen(argv[5]),
876 						       subgroup_param->metadata,
877 						       sizeof(subgroup_param->metadata));
878 
879 		if (subgroup_param->metadata_len == 0U) {
880 			shell_error(sh, "Could not parse metadata");
881 
882 			return -EINVAL;
883 		}
884 	} else {
885 		subgroup_param->metadata_len = 0U;
886 	}
887 
888 
889 	param.src_id = (uint8_t)src_id;
890 	param.encrypt_state = (enum bt_bap_big_enc_state)enc_state;
891 	param.broadcast_id = broadcast_id;
892 	param.num_subgroups = 1U;
893 
894 	err = bt_bap_scan_delegator_mod_src(&param);
895 	if (err < 0) {
896 		shell_error(ctx_shell, "Failed to modify source: %d", err);
897 
898 		return -ENOEXEC;
899 	}
900 
901 	return 0;
902 }
903 
cmd_bap_scan_delegator_rem_src(const struct shell * sh,size_t argc,char ** argv)904 static int cmd_bap_scan_delegator_rem_src(const struct shell *sh, size_t argc,
905 					  char **argv)
906 {
907 	unsigned long src_id;
908 	int err;
909 
910 	err = 0;
911 
912 	src_id = shell_strtoul(argv[1], 16, &err);
913 	if (err != 0) {
914 		shell_error(sh, "Failed to parse src_id from %s", argv[1]);
915 
916 		return -EINVAL;
917 	}
918 
919 	if (src_id > UINT8_MAX) {
920 		shell_error(sh, "Invalid src_id %lu", src_id);
921 
922 		return -EINVAL;
923 	}
924 
925 	err = bt_bap_scan_delegator_rem_src((uint8_t)src_id);
926 	if (err < 0) {
927 		shell_error(ctx_shell, "Failed to remove source source: %d",
928 			    err);
929 
930 		return -ENOEXEC;
931 	}
932 
933 	return 0;
934 }
935 
cmd_bap_scan_delegator_bis_synced(const struct shell * sh,size_t argc,char ** argv)936 static int cmd_bap_scan_delegator_bis_synced(const struct shell *sh, size_t argc,
937 					 char **argv)
938 {
939 	uint32_t bis_syncs[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS];
940 	unsigned long pa_sync_state;
941 	unsigned long bis_synced;
942 	unsigned long src_id;
943 	int result = 0;
944 
945 	src_id = shell_strtoul(argv[1], 0, &result);
946 	if (result != 0) {
947 		shell_error(sh, "Could not parse src_id: %d", result);
948 
949 		return -ENOEXEC;
950 	}
951 
952 	if (src_id > UINT8_MAX) {
953 		shell_error(sh, "Invalid src_id: %lu", src_id);
954 
955 		return -ENOEXEC;
956 	}
957 
958 	pa_sync_state = shell_strtoul(argv[2], 0, &result);
959 	if (result != 0) {
960 		shell_error(sh, "Could not parse pa_sync_state: %d", result);
961 
962 		return -ENOEXEC;
963 	}
964 
965 	if (pa_sync_state > BT_BAP_PA_STATE_NO_PAST) {
966 		shell_error(sh, "Invalid pa_sync_state %s", bt_bap_pa_state_str(pa_sync_state));
967 
968 		return -ENOEXEC;
969 	}
970 
971 	bis_synced = shell_strtoul(argv[3], 0, &result);
972 	if (result != 0) {
973 		shell_error(sh, "Could not parse bis_synced: %d", result);
974 
975 		return -ENOEXEC;
976 	}
977 
978 	if (bis_synced > UINT32_MAX) {
979 		shell_error(sh, "Invalid bis_synced %ld", bis_synced);
980 
981 		return -ENOEXEC;
982 	}
983 
984 	for (size_t i = 0U; i < ARRAY_SIZE(bis_syncs); i++) {
985 		bis_syncs[i] = bis_synced;
986 	}
987 
988 	result = bt_bap_scan_delegator_set_bis_sync_state(src_id, bis_syncs);
989 	if (result != 0) {
990 		shell_print(sh, "Fail: %d", result);
991 	}
992 
993 	return result;
994 }
995 
cmd_bap_scan_delegator(const struct shell * sh,size_t argc,char ** argv)996 static int cmd_bap_scan_delegator(const struct shell *sh, size_t argc,
997 				  char **argv)
998 {
999 	if (argc > 1) {
1000 		shell_error(sh, "%s unknown parameter: %s",
1001 			    argv[0], argv[1]);
1002 	} else {
1003 		shell_error(sh, "%s Missing subcommand", argv[0]);
1004 	}
1005 
1006 	return -ENOEXEC;
1007 }
1008 
1009 SHELL_STATIC_SUBCMD_SET_CREATE(bap_scan_delegator_cmds,
1010 	SHELL_CMD_ARG(init, NULL,
1011 		      "Initialize the service and register callbacks",
1012 		      cmd_bap_scan_delegator_init, 1, 0),
1013 	SHELL_CMD_ARG(set_past_pref, NULL,
1014 		      "Set PAST preference <true || false>",
1015 		      cmd_bap_scan_delegator_set_past_pref, 2, 0),
1016 	SHELL_CMD_ARG(sync_pa, NULL,
1017 		      "Sync to PA <src_id>",
1018 		      cmd_bap_scan_delegator_sync_pa, 2, 0),
1019 	SHELL_CMD_ARG(term_pa, NULL,
1020 		      "Terminate PA sync <src_id>",
1021 		      cmd_bap_scan_delegator_term_pa, 2, 0),
1022 	SHELL_CMD_ARG(add_src, NULL,
1023 		      "Add a PA as source <addr> <sid> <broadcast_id> <enc_state> "
1024 		      "[bis_sync [metadata]]",
1025 		      cmd_bap_scan_delegator_add_src, 5, 2),
1026 	SHELL_CMD_ARG(add_src_by_pa_sync, NULL,
1027 		      "Add a PA as source <broadcast_id> <enc_state> [bis_sync [metadata]]",
1028 		      cmd_bap_scan_delegator_add_src_by_pa_sync, 3, 2),
1029 	SHELL_CMD_ARG(mod_src, NULL,
1030 		      "Modify source <src_id> <broadcast_id> <enc_state> [bis_sync [metadata]]",
1031 		      cmd_bap_scan_delegator_mod_src, 4, 2),
1032 	SHELL_CMD_ARG(rem_src, NULL,
1033 		      "Remove source <src_id>",
1034 		      cmd_bap_scan_delegator_rem_src, 2, 0),
1035 	SHELL_CMD_ARG(synced, NULL,
1036 		      "Set server scan state <src_id> <bis_syncs>",
1037 		      cmd_bap_scan_delegator_bis_synced, 3, 0),
1038 	SHELL_SUBCMD_SET_END,
1039 );
1040 
1041 SHELL_CMD_ARG_REGISTER(bap_scan_delegator, &bap_scan_delegator_cmds,
1042 		       "Bluetooth BAP scan delegator shell commands",
1043 		       cmd_bap_scan_delegator, 1, 1);
1044