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