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