1 /* bap_base.c - BAP BASE handling */
2 
3 /*
4  * Copyright (c) 2023 Nordic Semiconductor ASA
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <errno.h>
10 #include <stdbool.h>
11 #include <stddef.h>
12 #include <stdint.h>
13 #include <string.h>
14 
15 #include <zephyr/autoconf.h>
16 #include <zephyr/bluetooth/audio/audio.h>
17 #include <zephyr/bluetooth/audio/bap.h>
18 #include <zephyr/bluetooth/bluetooth.h>
19 #include <zephyr/bluetooth/gap.h>
20 #include <zephyr/bluetooth/iso.h>
21 #include <zephyr/bluetooth/uuid.h>
22 #include <zephyr/logging/log.h>
23 #include <zephyr/net_buf.h>
24 #include <zephyr/sys/check.h>
25 #include <zephyr/sys/util.h>
26 #include <zephyr/sys/util_macro.h>
27 
28 LOG_MODULE_REGISTER(bt_bap_base, CONFIG_BT_BAP_BASE_LOG_LEVEL);
29 
30 /* The BASE and the following defines are defined by BAP v1.0.1, section 3.7.2.2 Basic Audio
31  * Announcements
32  */
33 #define BASE_MAX_SIZE            (UINT8_MAX - 1 /* type */ - BT_UUID_SIZE_16)
34 #define BASE_CODEC_ID_SIZE       (1 /* id */ + 2 /* cid */ + 2 /* vid */)
35 #define BASE_PD_SIZE             3
36 #define BASE_SUBGROUP_COUNT_SIZE 1
37 #define BASE_NUM_BIS_SIZE        1
38 #define BASE_CC_LEN_SIZE         1
39 #define BASE_META_LEN_SIZE       1
40 #define BASE_BIS_INDEX_SIZE      1
41 #define BASE_BIS_CC_LEN_SIZE     1
42 #define BASE_SUBGROUP_MAX_SIZE   (BASE_MAX_SIZE - BASE_PD_SIZE - BASE_SUBGROUP_COUNT_SIZE)
43 #define BASE_SUBGROUP_MIN_SIZE                                                                     \
44 	(BASE_NUM_BIS_SIZE + BASE_CODEC_ID_SIZE + BASE_CC_LEN_SIZE + BASE_META_LEN_SIZE +          \
45 	 BASE_BIS_INDEX_SIZE + BASE_BIS_CC_LEN_SIZE)
46 #define BASE_MIN_SIZE                                                                              \
47 	(BT_UUID_SIZE_16 + BASE_PD_SIZE + BASE_SUBGROUP_COUNT_SIZE + BASE_SUBGROUP_MIN_SIZE)
48 #define BASE_SUBGROUP_MAX_COUNT                                                                    \
49 	((BASE_MAX_SIZE - BASE_PD_SIZE - BASE_SUBGROUP_COUNT_SIZE) / BASE_SUBGROUP_MIN_SIZE)
50 
base_pull_pd(struct net_buf_simple * net_buf)51 static uint32_t base_pull_pd(struct net_buf_simple *net_buf)
52 {
53 	return net_buf_simple_pull_le24(net_buf);
54 }
55 
base_pull_bis_count(struct net_buf_simple * net_buf)56 static uint8_t base_pull_bis_count(struct net_buf_simple *net_buf)
57 {
58 	return net_buf_simple_pull_u8(net_buf);
59 }
60 
base_pull_codec_id(struct net_buf_simple * net_buf,struct bt_bap_base_codec_id * codec_id)61 static void base_pull_codec_id(struct net_buf_simple *net_buf,
62 			       struct bt_bap_base_codec_id *codec_id)
63 {
64 	struct bt_bap_base_codec_id codec;
65 
66 	codec.id = net_buf_simple_pull_u8(net_buf);    /* coding format */
67 	codec.cid = net_buf_simple_pull_le16(net_buf); /* company id */
68 	codec.vid = net_buf_simple_pull_le16(net_buf); /* VS codec id */
69 
70 	if (codec_id != NULL) {
71 		*codec_id = codec;
72 	}
73 }
74 
base_pull_ltv(struct net_buf_simple * net_buf,uint8_t ** data)75 static uint8_t base_pull_ltv(struct net_buf_simple *net_buf, uint8_t **data)
76 {
77 	const uint8_t len = net_buf_simple_pull_u8(net_buf);
78 
79 	if (data == NULL) {
80 		net_buf_simple_pull_mem(net_buf, len);
81 	} else {
82 		*data = net_buf_simple_pull_mem(net_buf, len);
83 	}
84 
85 	return len;
86 }
87 
check_pull_ltv(struct net_buf_simple * net_buf)88 static bool check_pull_ltv(struct net_buf_simple *net_buf)
89 {
90 	uint8_t ltv_len;
91 
92 	if (net_buf->len < sizeof(ltv_len)) {
93 		return false;
94 	}
95 
96 	ltv_len = net_buf_simple_pull_u8(net_buf);
97 	if (net_buf->len < ltv_len) {
98 		return false;
99 	}
100 	net_buf_simple_pull_mem(net_buf, ltv_len);
101 
102 	return true;
103 }
104 
bt_bap_base_get_base_from_ad(const struct bt_data * ad)105 const struct bt_bap_base *bt_bap_base_get_base_from_ad(const struct bt_data *ad)
106 {
107 	struct bt_uuid_16 broadcast_uuid;
108 	const struct bt_bap_base *base;
109 	struct net_buf_simple net_buf;
110 	uint8_t subgroup_count;
111 	void *uuid;
112 
113 	CHECKIF(ad == NULL) {
114 		LOG_DBG("data is NULL");
115 
116 		return NULL;
117 	}
118 
119 	if (ad->type != BT_DATA_SVC_DATA16) {
120 		LOG_DBG("Invalid type: %u", ad->type);
121 
122 		return NULL;
123 	}
124 
125 	if (ad->data_len < BASE_MIN_SIZE) {
126 		LOG_DBG("Invalid len: %u", ad->data_len);
127 
128 		return NULL;
129 	}
130 
131 	net_buf_simple_init_with_data(&net_buf, (void *)ad->data, ad->data_len);
132 
133 	uuid = net_buf_simple_pull_mem(&net_buf, BT_UUID_SIZE_16);
134 	if (!bt_uuid_create(&broadcast_uuid.uuid, uuid, BT_UUID_SIZE_16)) {
135 		LOG_ERR("bt_uuid_create failed");
136 
137 		return NULL;
138 	}
139 
140 	if (bt_uuid_cmp(&broadcast_uuid.uuid, BT_UUID_BASIC_AUDIO) != 0) {
141 		LOG_DBG("Invalid UUID");
142 
143 		return NULL;
144 	}
145 
146 	/* Store the start of the BASE */
147 	base = (const struct bt_bap_base *)net_buf.data;
148 
149 	/* Pull all data to verify that the result BASE is valid */
150 	base_pull_pd(&net_buf);
151 	subgroup_count = net_buf_simple_pull_u8(&net_buf);
152 	if (subgroup_count == 0 || subgroup_count > BASE_SUBGROUP_MAX_COUNT) {
153 		LOG_DBG("Invalid subgroup count: %u", subgroup_count);
154 
155 		return NULL;
156 	}
157 
158 	for (uint8_t i = 0U; i < subgroup_count; i++) {
159 		uint8_t bis_count;
160 
161 		if (net_buf.len < sizeof(bis_count)) {
162 			LOG_DBG("Invalid BASE length: %u", ad->data_len);
163 
164 			return NULL;
165 		}
166 
167 		bis_count = base_pull_bis_count(&net_buf);
168 		if (bis_count == 0 || bis_count > BT_ISO_MAX_GROUP_ISO_COUNT) {
169 			LOG_DBG("Subgroup[%u]: Invalid BIS count: %u", i, bis_count);
170 
171 			return NULL;
172 		}
173 
174 		if (net_buf.len < BASE_CODEC_ID_SIZE) {
175 			LOG_DBG("Invalid BASE length: %u", ad->data_len);
176 
177 			return NULL;
178 		}
179 
180 		base_pull_codec_id(&net_buf, NULL);
181 
182 		/* Pull CC */
183 		if (!check_pull_ltv(&net_buf)) {
184 			LOG_DBG("Invalid BASE length: %u", ad->data_len);
185 
186 			return NULL;
187 		}
188 
189 		/* Pull meta */
190 		if (!check_pull_ltv(&net_buf)) {
191 			LOG_DBG("Invalid BASE length: %u", ad->data_len);
192 
193 			return NULL;
194 		}
195 
196 		for (uint8_t j = 0U; j < bis_count; j++) {
197 			uint8_t bis_index;
198 
199 			if (net_buf.len < sizeof(bis_index)) {
200 				LOG_DBG("Invalid BASE length: %u", ad->data_len);
201 
202 				return NULL;
203 			}
204 
205 			bis_index = net_buf_simple_pull_u8(&net_buf);
206 			if (bis_index == 0 || bis_index > BT_ISO_BIS_INDEX_MAX) {
207 				LOG_DBG("Subgroup[%u]: Invalid BIS index: %u", i, bis_index);
208 
209 				return NULL;
210 			}
211 
212 			/* Pull BIS CC data */
213 			if (!check_pull_ltv(&net_buf)) {
214 				LOG_DBG("Invalid BASE length: %u", ad->data_len);
215 
216 				return NULL;
217 			}
218 		}
219 	}
220 
221 	return base;
222 }
223 
bt_bap_base_get_size(const struct bt_bap_base * base)224 int bt_bap_base_get_size(const struct bt_bap_base *base)
225 {
226 	struct net_buf_simple net_buf;
227 	uint8_t subgroup_count;
228 	size_t size = 0;
229 
230 	CHECKIF(base == NULL) {
231 		LOG_DBG("base is NULL");
232 
233 		return -EINVAL;
234 	}
235 
236 	net_buf_simple_init_with_data(&net_buf, (void *)base, BASE_MAX_SIZE);
237 	base_pull_pd(&net_buf);
238 	size += BASE_PD_SIZE;
239 	subgroup_count = net_buf_simple_pull_u8(&net_buf);
240 	size += BASE_SUBGROUP_COUNT_SIZE;
241 
242 	/* Parse subgroup data */
243 	for (uint8_t i = 0U; i < subgroup_count; i++) {
244 		uint8_t bis_count;
245 		uint8_t len;
246 
247 		bis_count = base_pull_bis_count(&net_buf);
248 		size += BASE_NUM_BIS_SIZE;
249 
250 		base_pull_codec_id(&net_buf, NULL);
251 		size += BASE_CODEC_ID_SIZE;
252 
253 		/* Codec config */
254 		len = base_pull_ltv(&net_buf, NULL);
255 		size += len + BASE_CC_LEN_SIZE;
256 
257 		/* meta */
258 		len = base_pull_ltv(&net_buf, NULL);
259 		size += len + BASE_META_LEN_SIZE;
260 
261 		/* Parse BIS data */
262 		for (uint8_t j = 0U; j < bis_count; j++) {
263 			/* BIS index */
264 			net_buf_simple_pull_u8(&net_buf);
265 			size += BASE_BIS_INDEX_SIZE;
266 
267 			/* Codec config */
268 			len = base_pull_ltv(&net_buf, NULL);
269 			size += len + BASE_BIS_CC_LEN_SIZE;
270 		}
271 	}
272 
273 	return (int)size;
274 }
275 
bt_bap_base_get_pres_delay(const struct bt_bap_base * base)276 int bt_bap_base_get_pres_delay(const struct bt_bap_base *base)
277 {
278 	struct net_buf_simple net_buf;
279 	uint32_t pd;
280 
281 	CHECKIF(base == NULL) {
282 		LOG_DBG("base is NULL");
283 
284 		return -EINVAL;
285 	}
286 
287 	net_buf_simple_init_with_data(&net_buf, (void *)base, sizeof(pd));
288 	pd = base_pull_pd(&net_buf);
289 
290 	return (int)pd; /* PD is 24-bit so it fits in an int */
291 }
292 
bt_bap_base_get_subgroup_count(const struct bt_bap_base * base)293 int bt_bap_base_get_subgroup_count(const struct bt_bap_base *base)
294 {
295 	struct net_buf_simple net_buf;
296 	uint8_t subgroup_count;
297 
298 	CHECKIF(base == NULL) {
299 		LOG_DBG("base is NULL");
300 
301 		return -EINVAL;
302 	}
303 
304 	net_buf_simple_init_with_data(&net_buf, (void *)base, BASE_MAX_SIZE);
305 	base_pull_pd(&net_buf);
306 	subgroup_count = net_buf_simple_pull_u8(&net_buf);
307 
308 	return (int)subgroup_count; /* subgroup_count is 8-bit so it fits in an int */
309 }
310 
bt_bap_base_foreach_subgroup(const struct bt_bap_base * base,bool (* func)(const struct bt_bap_base_subgroup * data,void * user_data),void * user_data)311 int bt_bap_base_foreach_subgroup(const struct bt_bap_base *base,
312 				 bool (*func)(const struct bt_bap_base_subgroup *data,
313 					      void *user_data),
314 				 void *user_data)
315 {
316 	struct bt_bap_base_subgroup *subgroup;
317 	struct net_buf_simple net_buf;
318 	uint8_t subgroup_count;
319 
320 	CHECKIF(base == NULL) {
321 		LOG_DBG("base is NULL");
322 
323 		return -EINVAL;
324 	}
325 
326 	CHECKIF(func == NULL) {
327 		LOG_DBG("func is NULL");
328 
329 		return -EINVAL;
330 	}
331 
332 	net_buf_simple_init_with_data(&net_buf, (void *)base, BASE_MAX_SIZE);
333 	base_pull_pd(&net_buf);
334 	subgroup_count = net_buf_simple_pull_u8(&net_buf);
335 
336 	for (uint8_t i = 0U; i < subgroup_count; i++) {
337 		subgroup = (struct bt_bap_base_subgroup *)net_buf.data;
338 		if (!func(subgroup, user_data)) {
339 			LOG_DBG("user stopped parsing");
340 
341 			return -ECANCELED;
342 		}
343 
344 		/* Parse subgroup data to get next subgroup pointer */
345 		if (subgroup_count > 1) { /* Only parse data if it isn't the last one */
346 			uint8_t bis_count;
347 
348 			bis_count = base_pull_bis_count(&net_buf);
349 			base_pull_codec_id(&net_buf, NULL);
350 
351 			/* Codec config */
352 			base_pull_ltv(&net_buf, NULL);
353 
354 			/* meta */
355 			base_pull_ltv(&net_buf, NULL);
356 
357 			for (uint8_t j = 0U; j < bis_count; j++) {
358 				net_buf_simple_pull_u8(&net_buf); /* index */
359 
360 				/* Codec config */
361 				base_pull_ltv(&net_buf, NULL);
362 			}
363 		}
364 	}
365 
366 	return 0;
367 }
368 
bt_bap_base_get_subgroup_codec_id(const struct bt_bap_base_subgroup * subgroup,struct bt_bap_base_codec_id * codec_id)369 int bt_bap_base_get_subgroup_codec_id(const struct bt_bap_base_subgroup *subgroup,
370 				      struct bt_bap_base_codec_id *codec_id)
371 {
372 	struct net_buf_simple net_buf;
373 
374 	CHECKIF(subgroup == NULL) {
375 		LOG_DBG("subgroup is NULL");
376 
377 		return -EINVAL;
378 	}
379 
380 	CHECKIF(codec_id == NULL) {
381 		LOG_DBG("codec_id is NULL");
382 
383 		return -EINVAL;
384 	}
385 
386 	net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE);
387 	base_pull_bis_count(&net_buf);
388 	base_pull_codec_id(&net_buf, codec_id);
389 
390 	return 0;
391 }
392 
bt_bap_base_get_subgroup_codec_data(const struct bt_bap_base_subgroup * subgroup,uint8_t ** data)393 int bt_bap_base_get_subgroup_codec_data(const struct bt_bap_base_subgroup *subgroup, uint8_t **data)
394 {
395 	struct net_buf_simple net_buf;
396 
397 	CHECKIF(subgroup == NULL) {
398 		LOG_DBG("subgroup is NULL");
399 
400 		return -EINVAL;
401 	}
402 
403 	CHECKIF(data == NULL) {
404 		LOG_DBG("data is NULL");
405 
406 		return -EINVAL;
407 	}
408 
409 	net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE);
410 	base_pull_bis_count(&net_buf);
411 	base_pull_codec_id(&net_buf, NULL);
412 
413 	/* Codec config */
414 	return base_pull_ltv(&net_buf, data);
415 }
416 
bt_bap_base_get_subgroup_codec_meta(const struct bt_bap_base_subgroup * subgroup,uint8_t ** meta)417 int bt_bap_base_get_subgroup_codec_meta(const struct bt_bap_base_subgroup *subgroup, uint8_t **meta)
418 {
419 	struct net_buf_simple net_buf;
420 
421 	CHECKIF(subgroup == NULL) {
422 		LOG_DBG("subgroup is NULL");
423 
424 		return -EINVAL;
425 	}
426 
427 	CHECKIF(meta == NULL) {
428 		LOG_DBG("meta is NULL");
429 
430 		return -EINVAL;
431 	}
432 
433 	net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE);
434 	base_pull_bis_count(&net_buf);
435 	base_pull_codec_id(&net_buf, NULL);
436 
437 	/* Codec config */
438 	base_pull_ltv(&net_buf, NULL);
439 
440 	/* meta */
441 	return base_pull_ltv(&net_buf, meta);
442 }
443 
bt_bap_base_subgroup_codec_to_codec_cfg(const struct bt_bap_base_subgroup * subgroup,struct bt_audio_codec_cfg * codec_cfg)444 int bt_bap_base_subgroup_codec_to_codec_cfg(const struct bt_bap_base_subgroup *subgroup,
445 					    struct bt_audio_codec_cfg *codec_cfg)
446 {
447 	struct bt_bap_base_codec_id codec_id;
448 	struct net_buf_simple net_buf;
449 	uint8_t *ltv_data;
450 	uint8_t ltv_len;
451 
452 	CHECKIF(subgroup == NULL) {
453 		LOG_DBG("subgroup is NULL");
454 
455 		return -EINVAL;
456 	}
457 
458 	CHECKIF(codec_cfg == NULL) {
459 		LOG_DBG("codec_cfg is NULL");
460 
461 		return -EINVAL;
462 	}
463 
464 	net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE);
465 	base_pull_bis_count(&net_buf);
466 	base_pull_codec_id(&net_buf, &codec_id);
467 
468 	codec_cfg->id = codec_id.id;
469 	codec_cfg->cid = codec_id.cid;
470 	codec_cfg->vid = codec_id.vid;
471 
472 	/* Codec config */
473 	ltv_len = base_pull_ltv(&net_buf, &ltv_data);
474 
475 	if (ltv_len > ARRAY_SIZE(codec_cfg->data)) {
476 		LOG_DBG("Cannot fit %u octets of codec data (max %zu)", ltv_len,
477 			ARRAY_SIZE(codec_cfg->data));
478 
479 		return -ENOMEM;
480 	}
481 
482 	codec_cfg->data_len = ltv_len;
483 	memcpy(codec_cfg->data, ltv_data, ltv_len);
484 
485 	/* Meta */
486 	ltv_len = base_pull_ltv(&net_buf, &ltv_data);
487 
488 	if (ltv_len > ARRAY_SIZE(codec_cfg->meta)) {
489 		LOG_DBG("Cannot fit %u octets of codec meta (max %zu)", ltv_len,
490 			ARRAY_SIZE(codec_cfg->meta));
491 
492 		return -ENOMEM;
493 	}
494 
495 	codec_cfg->meta_len = ltv_len;
496 	memcpy(codec_cfg->meta, ltv_data, ltv_len);
497 
498 	return 0;
499 }
bt_bap_base_get_subgroup_bis_count(const struct bt_bap_base_subgroup * subgroup)500 int bt_bap_base_get_subgroup_bis_count(const struct bt_bap_base_subgroup *subgroup)
501 {
502 	struct net_buf_simple net_buf;
503 
504 	CHECKIF(subgroup == NULL) {
505 		LOG_DBG("subgroup is NULL");
506 
507 		return -EINVAL;
508 	}
509 
510 	net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE);
511 
512 	return base_pull_bis_count(&net_buf);
513 }
514 
bt_bap_base_subgroup_foreach_bis(const struct bt_bap_base_subgroup * subgroup,bool (* func)(const struct bt_bap_base_subgroup_bis * subgroup,void * user_data),void * user_data)515 int bt_bap_base_subgroup_foreach_bis(const struct bt_bap_base_subgroup *subgroup,
516 				     bool (*func)(const struct bt_bap_base_subgroup_bis *subgroup,
517 						  void *user_data),
518 				     void *user_data)
519 {
520 	struct net_buf_simple net_buf;
521 	uint8_t bis_count;
522 
523 	CHECKIF(subgroup == NULL) {
524 		LOG_DBG("subgroup is NULL");
525 
526 		return -EINVAL;
527 	}
528 
529 	CHECKIF(func == NULL) {
530 		LOG_DBG("func is NULL");
531 
532 		return -EINVAL;
533 	}
534 
535 	net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE);
536 
537 	bis_count = base_pull_bis_count(&net_buf);
538 	base_pull_codec_id(&net_buf, NULL);
539 
540 	/* Codec config */
541 	base_pull_ltv(&net_buf, NULL);
542 
543 	/* meta */
544 	base_pull_ltv(&net_buf, NULL);
545 
546 	for (uint8_t i = 0U; i < bis_count; i++) {
547 		struct bt_bap_base_subgroup_bis bis;
548 
549 		bis.index = net_buf_simple_pull_u8(&net_buf); /* index */
550 
551 		/* Codec config */
552 		bis.data_len = base_pull_ltv(&net_buf, &bis.data);
553 
554 		if (!func(&bis, user_data)) {
555 			LOG_DBG("user stopped parsing");
556 
557 			return -ECANCELED;
558 		}
559 	}
560 
561 	return 0;
562 }
563 
bt_bap_base_subgroup_bis_codec_to_codec_cfg(const struct bt_bap_base_subgroup_bis * bis,struct bt_audio_codec_cfg * codec_cfg)564 int bt_bap_base_subgroup_bis_codec_to_codec_cfg(const struct bt_bap_base_subgroup_bis *bis,
565 						struct bt_audio_codec_cfg *codec_cfg)
566 {
567 	CHECKIF(bis == NULL) {
568 		LOG_DBG("bis is NULL");
569 
570 		return -EINVAL;
571 	}
572 
573 	CHECKIF(codec_cfg == NULL) {
574 		LOG_DBG("codec_cfg is NULL");
575 
576 		return -EINVAL;
577 	}
578 
579 	if (bis->data_len > ARRAY_SIZE(codec_cfg->data)) {
580 		LOG_DBG("Cannot fit %u octets of codec data (max %zu)", bis->data_len,
581 			ARRAY_SIZE(codec_cfg->data));
582 
583 		return -ENOMEM;
584 	}
585 
586 	codec_cfg->data_len = bis->data_len;
587 	memcpy(codec_cfg->data, bis->data, bis->data_len);
588 
589 	return 0;
590 }
591 
base_subgroup_bis_cb(const struct bt_bap_base_subgroup_bis * bis,void * user_data)592 static bool base_subgroup_bis_cb(const struct bt_bap_base_subgroup_bis *bis, void *user_data)
593 {
594 	uint32_t *base_bis_index_bitfield = user_data;
595 
596 	*base_bis_index_bitfield |= BT_ISO_BIS_INDEX_BIT(bis->index);
597 
598 	return true;
599 }
600 
base_subgroup_cb(const struct bt_bap_base_subgroup * subgroup,void * user_data)601 static bool base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data)
602 {
603 	const int err = bt_bap_base_subgroup_foreach_bis(subgroup, base_subgroup_bis_cb, user_data);
604 
605 	if (err != 0) {
606 		LOG_DBG("Failed to parse all BIS: %d", err);
607 		return false;
608 	}
609 
610 	return true;
611 }
612 
bt_bap_base_subgroup_get_bis_indexes(const struct bt_bap_base_subgroup * subgroup,uint32_t * bis_indexes)613 int bt_bap_base_subgroup_get_bis_indexes(const struct bt_bap_base_subgroup *subgroup,
614 					 uint32_t *bis_indexes)
615 {
616 	CHECKIF(subgroup == NULL) {
617 		LOG_DBG("subgroup is NULL");
618 
619 		return -EINVAL;
620 	}
621 
622 	CHECKIF(bis_indexes == NULL) {
623 		LOG_DBG("bis_indexes is NULL");
624 
625 		return -EINVAL;
626 	}
627 
628 	*bis_indexes = 0U;
629 
630 	return bt_bap_base_subgroup_foreach_bis(subgroup, base_subgroup_bis_cb, bis_indexes);
631 }
632 
bt_bap_base_get_bis_indexes(const struct bt_bap_base * base,uint32_t * bis_indexes)633 int bt_bap_base_get_bis_indexes(const struct bt_bap_base *base, uint32_t *bis_indexes)
634 {
635 	CHECKIF(base == NULL) {
636 		LOG_DBG("base is NULL");
637 
638 		return -EINVAL;
639 	}
640 
641 	CHECKIF(bis_indexes == NULL) {
642 		LOG_DBG("bis_indexes is NULL");
643 
644 		return -EINVAL;
645 	}
646 
647 	*bis_indexes = 0U;
648 
649 	return bt_bap_base_foreach_subgroup(base, base_subgroup_cb, bis_indexes);
650 }
651