1 /* @file
2  * @brief Bluetooth PACS
3  */
4 
5 /*
6  * Copyright (c) 2020 Intel Corporation
7  * Copyright (c) 2022-2023 Nordic Semiconductor ASA
8  *
9  * SPDX-License-Identifier: Apache-2.0
10  */
11 
12 #include <errno.h>
13 #include <stdbool.h>
14 #include <stddef.h>
15 #include <stdint.h>
16 #include <string.h>
17 #include <sys/types.h>
18 
19 #include <zephyr/autoconf.h>
20 #include <zephyr/bluetooth/addr.h>
21 #include <zephyr/bluetooth/att.h>
22 #include <zephyr/bluetooth/audio/audio.h>
23 #include <zephyr/bluetooth/audio/pacs.h>
24 #include <zephyr/bluetooth/bluetooth.h>
25 #include <zephyr/bluetooth/conn.h>
26 #include <zephyr/bluetooth/gatt.h>
27 #include <zephyr/bluetooth/uuid.h>
28 #include <zephyr/init.h>
29 #include <zephyr/kernel.h>
30 #include <zephyr/logging/log.h>
31 #include <zephyr/net_buf.h>
32 #include <zephyr/sys/__assert.h>
33 #include <zephyr/sys/atomic.h>
34 #include <zephyr/sys/byteorder.h>
35 #include <zephyr/sys/check.h>
36 #include <zephyr/sys/slist.h>
37 #include <zephyr/sys/util.h>
38 #include <zephyr/sys/util_macro.h>
39 
40 #include "common/bt_str.h"
41 
42 #include "audio_internal.h"
43 #include "bap_unicast_server.h"
44 #include "pacs_internal.h"
45 
46 LOG_MODULE_REGISTER(bt_pacs, CONFIG_BT_PACS_LOG_LEVEL);
47 
48 #define PAC_NOTIFY_TIMEOUT	K_MSEC(10)
49 #define READ_BUF_SEM_TIMEOUT    K_MSEC(50)
50 
51 #if defined(CONFIG_BT_PAC_SRC)
52 static sys_slist_t src_pac_list = SYS_SLIST_STATIC_INIT(&src_pac_list);
53 static uint16_t src_supported_contexts;
54 #if defined(CONFIG_BT_PAC_SRC_LOC)
55 static uint32_t pacs_src_location;
56 #endif /* CONFIG_BT_PAC_SRC_LOC */
57 #endif /* CONFIG_BT_PAC_SRC */
58 
59 #if defined(CONFIG_BT_PAC_SNK)
60 static sys_slist_t snk_pac_list = SYS_SLIST_STATIC_INIT(&snk_pac_list);
61 static uint16_t snk_supported_contexts;
62 #if defined(CONFIG_BT_PAC_SNK_LOC)
63 static uint32_t pacs_snk_location;
64 #endif /* CONFIG_BT_PAC_SNK_LOC */
65 #endif /* CONFIG_BT_PAC_SNK */
66 
67 static uint16_t src_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
68 static uint16_t snk_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
69 
70 enum {
71 	FLAG_ACTIVE,
72 	FLAG_SINK_PAC_CHANGED,
73 	FLAG_SINK_AUDIO_LOCATIONS_CHANGED,
74 	FLAG_SOURCE_PAC_CHANGED,
75 	FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED,
76 	FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED,
77 	FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED,
78 	FLAG_NUM,
79 };
80 
81 enum {
82 	PACS_FLAG_REGISTERED,
83 	PACS_FLAG_SVC_CHANGING,
84 	PACS_FLAG_NOTIFY_RDY,
85 	PACS_FLAG_SNK_PAC,
86 	PACS_FLAG_SNK_LOC,
87 	PACS_FLAG_SRC_PAC,
88 	PACS_FLAG_SRC_LOC,
89 	PACS_FLAG_NUM,
90 };
91 
92 struct pacs_client {
93 	bt_addr_le_t addr;
94 
95 #if defined(CONFIG_BT_PAC_SNK)
96 	/* Sink Available Contexts override value */
97 	uint16_t *snk_available_contexts;
98 #endif /* CONFIG_BT_PAC_SNK */
99 
100 #if defined(CONFIG_BT_PAC_SRC)
101 	/* Source Available Contexts override value */
102 	uint16_t *src_available_contexts;
103 #endif /* CONFIG_BT_PAC_SRC */
104 
105 	/* Pending notification flags */
106 	ATOMIC_DEFINE(flags, FLAG_NUM);
107 };
108 
109 static struct pacs {
110 	ATOMIC_DEFINE(flags, PACS_FLAG_NUM);
111 
112 	struct pacs_client clients[CONFIG_BT_MAX_PAIRED];
113 } pacs;
114 
115 
116 static K_SEM_DEFINE(read_buf_sem, 1, 1);
117 NET_BUF_SIMPLE_DEFINE_STATIC(read_buf, BT_ATT_MAX_ATTRIBUTE_LEN);
118 
119 static int pacs_gatt_notify(struct bt_conn *conn,
120 			    const struct bt_uuid *uuid,
121 			    const struct bt_gatt_attr *attr,
122 			    const void *data,
123 			    uint16_t len);
124 static void deferred_nfy_work_handler(struct k_work *work);
125 
126 static K_WORK_DEFINE(deferred_nfy_work, deferred_nfy_work_handler);
127 
128 struct pac_records_build_data {
129 	struct bt_pacs_read_rsp *rsp;
130 	struct net_buf_simple *buf;
131 };
132 
client_lookup_conn(const struct bt_conn * conn)133 static struct pacs_client *client_lookup_conn(const struct bt_conn *conn)
134 {
135 	__ASSERT_NO_MSG(conn != NULL);
136 
137 	for (size_t i = 0; i < ARRAY_SIZE(pacs.clients); i++) {
138 		if (atomic_test_bit(pacs.clients[i].flags, FLAG_ACTIVE) &&
139 		    bt_addr_le_eq(&pacs.clients[i].addr, bt_conn_get_dst(conn))) {
140 			return &pacs.clients[i];
141 		}
142 	}
143 
144 	return NULL;
145 }
146 
pacs_set_notify_bit(int bit)147 static void pacs_set_notify_bit(int bit)
148 {
149 	for (size_t i = 0U; i < ARRAY_SIZE(pacs.clients); i++) {
150 		if (atomic_test_bit(pacs.clients[i].flags, FLAG_ACTIVE)) {
151 			atomic_set_bit(pacs.clients[i].flags, bit);
152 		}
153 	}
154 }
155 
build_pac_records(const struct bt_pacs_cap * cap,void * user_data)156 static bool build_pac_records(const struct bt_pacs_cap *cap, void *user_data)
157 {
158 	struct pac_records_build_data *data = user_data;
159 	const struct bt_audio_codec_cap *codec_cap = cap->codec_cap;
160 	struct net_buf_simple *buf = data->buf;
161 	struct net_buf_simple_state state;
162 	struct bt_pac_codec *pac_codec;
163 
164 	net_buf_simple_save(buf, &state);
165 
166 	if (net_buf_simple_tailroom(buf) < sizeof(*pac_codec)) {
167 		goto fail;
168 	}
169 
170 	pac_codec = net_buf_simple_add(buf, sizeof(*pac_codec));
171 	pac_codec->id = codec_cap->id;
172 	pac_codec->cid = sys_cpu_to_le16(codec_cap->cid);
173 	pac_codec->vid = sys_cpu_to_le16(codec_cap->vid);
174 
175 	if (net_buf_simple_tailroom(buf) < (sizeof(struct bt_pac_ltv_data) + codec_cap->data_len)) {
176 		goto fail;
177 	}
178 
179 	net_buf_simple_add_u8(buf, codec_cap->data_len);
180 	net_buf_simple_add_mem(buf, codec_cap->data, codec_cap->data_len);
181 
182 	if (net_buf_simple_tailroom(buf) < (sizeof(struct bt_pac_ltv_data) + codec_cap->meta_len)) {
183 		goto fail;
184 	}
185 
186 	net_buf_simple_add_u8(buf, codec_cap->meta_len);
187 	net_buf_simple_add_mem(buf, codec_cap->meta, codec_cap->meta_len);
188 
189 	data->rsp->num_pac++;
190 
191 	return true;
192 
193 fail:
194 	__ASSERT(false, "No space for %p", cap);
195 
196 	net_buf_simple_restore(buf, &state);
197 
198 	return false;
199 }
200 
foreach_cap(sys_slist_t * list,bt_pacs_cap_foreach_func_t func,void * user_data)201 static void foreach_cap(sys_slist_t *list, bt_pacs_cap_foreach_func_t func,
202 			void *user_data)
203 {
204 	struct bt_pacs_cap *cap;
205 
206 	SYS_SLIST_FOR_EACH_CONTAINER(list, cap, _node) {
207 		if (!func(cap, user_data)) {
208 			break;
209 		}
210 	}
211 }
212 
get_pac_records(sys_slist_t * list,struct net_buf_simple * buf)213 static void get_pac_records(sys_slist_t *list, struct net_buf_simple *buf)
214 {
215 	struct pac_records_build_data data;
216 
217 	/* Reset if buffer before using */
218 	net_buf_simple_reset(buf);
219 
220 	data.rsp = net_buf_simple_add(buf, sizeof(*data.rsp));
221 	data.rsp->num_pac = 0;
222 	data.buf = buf;
223 
224 	foreach_cap(list, build_pac_records, &data);
225 }
226 
available_context_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)227 static void available_context_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
228 {
229 	LOG_DBG("attr %p value 0x%04x", attr, value);
230 }
231 
pacs_get_available_contexts_for_conn(struct bt_conn * conn,enum bt_audio_dir dir)232 static enum bt_audio_context pacs_get_available_contexts_for_conn(struct bt_conn *conn,
233 								  enum bt_audio_dir dir)
234 {
235 	const struct pacs_client *client;
236 
237 	client = client_lookup_conn(conn);
238 	if (client == NULL) {
239 		LOG_DBG("No client context for conn %p", (void *)conn);
240 		return bt_pacs_get_available_contexts(dir);
241 	}
242 
243 	switch (dir) {
244 	case BT_AUDIO_DIR_SINK:
245 #if defined(CONFIG_BT_PAC_SNK)
246 		if (atomic_test_bit(pacs.flags, PACS_FLAG_SNK_PAC) &&
247 		    client->snk_available_contexts != NULL) {
248 			return POINTER_TO_UINT(client->snk_available_contexts);
249 		}
250 #endif /* CONFIG_BT_PAC_SNK */
251 		break;
252 	case BT_AUDIO_DIR_SOURCE:
253 #if defined(CONFIG_BT_PAC_SRC)
254 		if (atomic_test_bit(pacs.flags, PACS_FLAG_SRC_PAC) &&
255 		    client->src_available_contexts != NULL) {
256 			return POINTER_TO_UINT(client->src_available_contexts);
257 		}
258 #endif /* CONFIG_BT_PAC_SRC */
259 		break;
260 	}
261 
262 	return bt_pacs_get_available_contexts(dir);
263 }
264 
available_contexts_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)265 static ssize_t available_contexts_read(struct bt_conn *conn,
266 				       const struct bt_gatt_attr *attr, void *buf,
267 				       uint16_t len, uint16_t offset)
268 {
269 	struct bt_pacs_context context = {
270 		.snk = sys_cpu_to_le16(
271 			pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK)),
272 		.src = sys_cpu_to_le16(
273 			pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE)),
274 	};
275 
276 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", (void *)conn, attr, buf, len, offset);
277 
278 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &context,
279 				 sizeof(context));
280 }
281 
282 #if defined(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE)
supported_context_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)283 static void supported_context_cfg_changed(const struct bt_gatt_attr *attr,
284 					  uint16_t value)
285 {
286 	LOG_DBG("attr %p value 0x%04x", attr, value);
287 }
288 #endif /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */
289 
supported_context_get(enum bt_audio_dir dir)290 static uint16_t supported_context_get(enum bt_audio_dir dir)
291 {
292 	switch (dir) {
293 #if defined(CONFIG_BT_PAC_SNK)
294 	case BT_AUDIO_DIR_SINK:
295 		if (atomic_test_bit(pacs.flags, PACS_FLAG_SNK_PAC)) {
296 			return snk_supported_contexts | BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED;
297 		}
298 		break;
299 #endif /* CONFIG_BT_PAC_SNK */
300 #if defined(CONFIG_BT_PAC_SRC)
301 	case BT_AUDIO_DIR_SOURCE:
302 		if (atomic_test_bit(pacs.flags, PACS_FLAG_SRC_PAC)) {
303 			return src_supported_contexts | BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED;
304 		}
305 		break;
306 #endif /* CONFIG_BT_PAC_SRC */
307 	default:
308 		break;
309 	}
310 
311 	return BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
312 }
313 
supported_context_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)314 static ssize_t supported_context_read(struct bt_conn *conn,
315 				      const struct bt_gatt_attr *attr,
316 				      void *buf, uint16_t len, uint16_t offset)
317 {
318 	struct bt_pacs_context context = {
319 		.snk = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SINK)),
320 		.src = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SOURCE)),
321 	};
322 
323 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", (void *)conn, attr, buf, len, offset);
324 
325 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &context,
326 				 sizeof(context));
327 }
328 
set_available_contexts(uint16_t contexts,uint16_t * available,uint16_t supported)329 static int set_available_contexts(uint16_t contexts, uint16_t *available,
330 				  uint16_t supported)
331 {
332 	if (contexts & ~supported) {
333 		return -ENOTSUP;
334 	}
335 
336 	if (contexts == *available) {
337 		return 0;
338 	}
339 
340 	*available = contexts;
341 
342 	pacs_set_notify_bit(FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED);
343 	k_work_submit(&deferred_nfy_work);
344 
345 	return 0;
346 }
347 
set_supported_contexts(uint16_t contexts,uint16_t * supported,uint16_t * available)348 static int set_supported_contexts(uint16_t contexts, uint16_t *supported,
349 				  uint16_t *available)
350 {
351 	int err;
352 	uint16_t tmp_supported = *supported;
353 	uint16_t tmp_available = *available;
354 
355 	/* Ensure unspecified is always supported */
356 	contexts |= BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED;
357 
358 	if (*supported == contexts) {
359 		return 0;
360 	}
361 
362 	*supported = contexts;
363 
364 	/* Update available contexts if needed*/
365 	if ((contexts & *available) != *available) {
366 		err = set_available_contexts(contexts & *available, available, contexts);
367 		if (err) {
368 			*available = tmp_available;
369 			*supported = tmp_supported;
370 
371 			return err;
372 		}
373 	}
374 
375 	if (IS_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE)) {
376 		pacs_set_notify_bit(FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED);
377 		k_work_submit(&deferred_nfy_work);
378 	}
379 
380 	return 0;
381 }
382 
383 #if defined(CONFIG_BT_PAC_SNK)
snk_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)384 static ssize_t snk_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
385 			void *buf, uint16_t len, uint16_t offset)
386 {
387 	ssize_t ret_val;
388 	int err;
389 
390 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", (void *)conn, attr, buf, len, offset);
391 
392 	err = k_sem_take(&read_buf_sem, READ_BUF_SEM_TIMEOUT);
393 	if (err != 0) {
394 		LOG_DBG("Failed to take read_buf_sem: %d", err);
395 
396 		return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES);
397 	}
398 
399 	get_pac_records(&snk_pac_list, &read_buf);
400 
401 	ret_val = bt_gatt_attr_read(conn, attr, buf, len, offset, read_buf.data,
402 				    read_buf.len);
403 
404 	k_sem_give(&read_buf_sem);
405 
406 	return ret_val;
407 }
408 
409 #if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE)
410 static const struct bt_uuid *pacs_snk_uuid = BT_UUID_PACS_SNK;
411 
snk_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)412 static void snk_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
413 {
414 	LOG_DBG("attr %p value 0x%04x", attr, value);
415 }
416 #endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */
417 #endif /* CONFIG_BT_PAC_SNK */
418 
419 #if defined(CONFIG_BT_PAC_SNK_LOC)
snk_loc_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)420 static ssize_t snk_loc_read(struct bt_conn *conn,
421 			    const struct bt_gatt_attr *attr, void *buf,
422 			    uint16_t len, uint16_t offset)
423 {
424 	uint32_t location = sys_cpu_to_le32(pacs_snk_location);
425 
426 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", (void *)conn, attr, buf, len, offset);
427 
428 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &location,
429 				 sizeof(location));
430 }
431 
432 #if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)
433 static const struct bt_uuid *pacs_snk_loc_uuid = BT_UUID_PACS_SNK_LOC;
434 
snk_loc_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)435 static void snk_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
436 {
437 	LOG_DBG("attr %p value 0x%04x", attr, value);
438 }
439 #endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */
440 
set_snk_location(enum bt_audio_location audio_location)441 static void set_snk_location(enum bt_audio_location audio_location)
442 {
443 	if (atomic_test_bit(pacs.flags, PACS_FLAG_SNK_LOC)) {
444 		if (audio_location == pacs_snk_location) {
445 			return;
446 		}
447 
448 		pacs_snk_location = audio_location;
449 
450 		if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)) {
451 			pacs_set_notify_bit(FLAG_SINK_AUDIO_LOCATIONS_CHANGED);
452 			k_work_submit(&deferred_nfy_work);
453 		}
454 	}
455 }
456 #else
set_snk_location(enum bt_audio_location location)457 static void set_snk_location(enum bt_audio_location location)
458 {
459 	return;
460 }
461 #endif /* CONFIG_BT_PAC_SNK_LOC */
462 
463 #if defined(CONFIG_BT_PAC_SNK_LOC_WRITEABLE)
snk_loc_write(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * data,uint16_t len,uint16_t offset,uint8_t flags)464 static ssize_t snk_loc_write(struct bt_conn *conn,
465 			     const struct bt_gatt_attr *attr, const void *data,
466 			     uint16_t len, uint16_t offset, uint8_t flags)
467 {
468 	enum bt_audio_location location;
469 
470 	if (offset) {
471 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
472 	}
473 
474 	if (len != sizeof(location)) {
475 		return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
476 	}
477 
478 	location = (enum bt_audio_location)sys_get_le32(data);
479 	if (location > BT_AUDIO_LOCATION_MASK) {
480 		LOG_DBG("Invalid location value: 0x%08X", location);
481 		return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
482 	}
483 
484 	set_snk_location(location);
485 
486 	return len;
487 }
488 #endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE */
489 
490 #if defined(CONFIG_BT_PAC_SRC)
src_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)491 static ssize_t src_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
492 			void *buf, uint16_t len, uint16_t offset)
493 {
494 	ssize_t ret_val;
495 	int err;
496 
497 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", (void *)conn, attr, buf, len, offset);
498 
499 	err = k_sem_take(&read_buf_sem, READ_BUF_SEM_TIMEOUT);
500 	if (err != 0) {
501 		LOG_DBG("Failed to take read_buf_sem: %d", err);
502 
503 		return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES);
504 	}
505 
506 	get_pac_records(&src_pac_list, &read_buf);
507 
508 	ret_val = bt_gatt_attr_read(conn, attr, buf, len, offset, read_buf.data,
509 				    read_buf.len);
510 
511 	k_sem_give(&read_buf_sem);
512 
513 	return ret_val;
514 }
515 
516 #if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
517 static const struct bt_uuid *pacs_src_uuid = BT_UUID_PACS_SRC;
518 
src_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)519 static void src_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
520 {
521 	LOG_DBG("attr %p value 0x%04x", attr, value);
522 }
523 #endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
524 #endif /* CONFIG_BT_PAC_SRC */
525 
526 #if defined(CONFIG_BT_PAC_SRC_LOC)
src_loc_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)527 static ssize_t src_loc_read(struct bt_conn *conn,
528 			    const struct bt_gatt_attr *attr, void *buf,
529 			    uint16_t len, uint16_t offset)
530 {
531 	uint32_t location = sys_cpu_to_le32(pacs_src_location);
532 
533 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", (void *)conn, attr, buf, len, offset);
534 
535 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &location,
536 				 sizeof(location));
537 }
538 
539 #if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
540 static const struct bt_uuid *pacs_src_loc_uuid = BT_UUID_PACS_SRC_LOC;
541 
src_loc_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)542 static void src_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
543 {
544 	LOG_DBG("attr %p value 0x%04x", attr, value);
545 }
546 #endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
547 
set_src_location(enum bt_audio_location audio_location)548 static void set_src_location(enum bt_audio_location audio_location)
549 {
550 	if (atomic_test_bit(pacs.flags, PACS_FLAG_SRC_LOC)) {
551 		if (audio_location == pacs_src_location) {
552 			return;
553 		}
554 
555 		pacs_src_location = audio_location;
556 
557 		if (IS_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)) {
558 			pacs_set_notify_bit(FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED);
559 			k_work_submit(&deferred_nfy_work);
560 		}
561 	}
562 }
563 #else
set_src_location(enum bt_audio_location location)564 static void set_src_location(enum bt_audio_location location)
565 {
566 	return;
567 }
568 #endif /* CONFIG_BT_PAC_SRC_LOC */
569 
570 #if defined(CONFIG_BT_PAC_SRC_LOC_WRITEABLE)
src_loc_write(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * data,uint16_t len,uint16_t offset,uint8_t flags)571 static ssize_t src_loc_write(struct bt_conn *conn,
572 			     const struct bt_gatt_attr *attr, const void *data,
573 			     uint16_t len, uint16_t offset, uint8_t flags)
574 {
575 	uint32_t location;
576 
577 	if (offset) {
578 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
579 	}
580 
581 	if (len != sizeof(location)) {
582 		return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
583 	}
584 
585 	location = (enum bt_audio_location)sys_get_le32(data);
586 	if (location > BT_AUDIO_LOCATION_MASK) {
587 		LOG_DBG("Invalid location value: 0x%08X", location);
588 		return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
589 	}
590 
591 	set_src_location(location);
592 
593 	return len;
594 }
595 #endif /* CONFIG_BT_PAC_SRC_LOC_WRITEABLE */
596 
597 
pacs_get_pac(enum bt_audio_dir dir)598 static sys_slist_t *pacs_get_pac(enum bt_audio_dir dir)
599 {
600 	switch (dir) {
601 #if defined(CONFIG_BT_PAC_SNK)
602 	case BT_AUDIO_DIR_SINK:
603 		if (atomic_test_bit(pacs.flags, PACS_FLAG_SNK_PAC)) {
604 			return &snk_pac_list;
605 		}
606 		return NULL;
607 #endif /* CONFIG_BT_PAC_SNK */
608 #if defined(CONFIG_BT_PAC_SRC)
609 	case BT_AUDIO_DIR_SOURCE:
610 		if (atomic_test_bit(pacs.flags, PACS_FLAG_SRC_PAC)) {
611 			return &src_pac_list;
612 		}
613 		return NULL;
614 #endif /* CONFIG_BT_PAC_SRC */
615 	default:
616 		return NULL;
617 	}
618 }
619 
620 #if defined(CONFIG_BT_PAC_SNK)
621 #define BT_PACS_SNK_PROP \
622 	BT_GATT_CHRC_READ \
623 	IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
624 #define BT_PAC_SNK                                                                                 \
625 	BT_AUDIO_CHRC(BT_UUID_PACS_SNK, BT_PACS_SNK_PROP, BT_GATT_PERM_READ_ENCRYPT, snk_read,     \
626 		      NULL, NULL),                                                                 \
627 	IF_ENABLED(CONFIG_BT_PAC_SNK_NOTIFIABLE, (BT_AUDIO_CCC(snk_cfg_changed),))
628 
629 #define BT_PACS_SNK_LOC_PROP \
630 	BT_GATT_CHRC_READ \
631 	IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_WRITEABLE, (|BT_GATT_CHRC_WRITE)) \
632 	IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
633 
634 #define BT_PACS_SNK_LOC_PERM                                                                       \
635 	BT_GATT_PERM_READ_ENCRYPT                                                                  \
636 	IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_WRITEABLE, (|BT_GATT_PERM_WRITE_ENCRYPT))
637 
638 /* declaration + value [+ cccd] */
639 #define PACS_SNK_PAC_CHAR_ATTR_COUNT COND_CODE_1(IS_ENABLED(CONFIG_BT_PAC_SNK_NOTIFIABLE), (3), (2))
640 #else
641 #define BT_PAC_SNK
642 #define PACS_SNK_PAC_CHAR_ATTR_COUNT 0
643 #endif /* CONFIG_BT_PAC_SNK */
644 
645 #if defined(CONFIG_BT_PAC_SNK_LOC)
646 #define BT_PACS_SNK_LOC                                                                            \
647 	BT_AUDIO_CHRC(BT_UUID_PACS_SNK_LOC, BT_PACS_SNK_LOC_PROP, BT_PACS_SNK_LOC_PERM,            \
648 		      snk_loc_read,                                                                \
649 		      COND_CODE_1(CONFIG_BT_PAC_SNK_LOC_WRITEABLE, (snk_loc_write), (NULL)), NULL),\
650 	IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE, (BT_AUDIO_CCC(snk_loc_cfg_changed),))
651 
652 /* declaration + value [+ cccd] */
653 #define PACS_SNK_PAC_LOC_CHAR_ATTR_COUNT                                                           \
654 	COND_CODE_1(IS_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE), (3), (2))
655 #else
656 #define BT_PACS_SNK_LOC
657 #define PACS_SNK_PAC_LOC_CHAR_ATTR_COUNT 0
658 #endif /* CONFIG_BT_PAC_SNK_LOC*/
659 
660 #if defined(CONFIG_BT_PAC_SRC)
661 #define BT_PACS_SRC_PROP \
662 	BT_GATT_CHRC_READ \
663 	IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
664 #define BT_PAC_SRC                                                                                 \
665 	BT_AUDIO_CHRC(BT_UUID_PACS_SRC, BT_PACS_SRC_PROP, BT_GATT_PERM_READ_ENCRYPT, src_read,     \
666 		      NULL, NULL),                                                                 \
667 	IF_ENABLED(CONFIG_BT_PAC_SRC_NOTIFIABLE, (BT_AUDIO_CCC(src_cfg_changed),))
668 
669 #define BT_PACS_SRC_LOC_PROP \
670 	BT_GATT_CHRC_READ \
671 	IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_WRITEABLE, (|BT_GATT_CHRC_WRITE)) \
672 	IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
673 
674 #define BT_PACS_SRC_LOC_PERM                                                                       \
675 	BT_GATT_PERM_READ_ENCRYPT                                                                  \
676 	IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_WRITEABLE, (|BT_GATT_PERM_WRITE_ENCRYPT))
677 
678 /* declaration + value [+ cccd] */
679 #define PACS_SRC_PAC_CHAR_ATTR_COUNT COND_CODE_1(IS_ENABLED(CONFIG_BT_PAC_SRC_NOTIFIABLE), (3), (2))
680 #else
681 #define BT_PAC_SRC
682 #define PACS_SRC_PAC_CHAR_ATTR_COUNT 0
683 #endif
684 
685 #if defined(CONFIG_BT_PAC_SRC_LOC)
686 #define BT_PACS_SRC_LOC                                                                            \
687 	BT_AUDIO_CHRC(BT_UUID_PACS_SRC_LOC, BT_PACS_SRC_LOC_PROP, BT_PACS_SRC_LOC_PERM,            \
688 		      src_loc_read,                                                                \
689 		      COND_CODE_1(CONFIG_BT_PAC_SRC_LOC_WRITEABLE, (src_loc_write), (NULL)), NULL),\
690 	IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE, (BT_AUDIO_CCC(src_loc_cfg_changed),))
691 
692 /* declaration + value [+ cccd] */
693 #define PACS_SRC_PAC_LOC_CHAR_ATTR_COUNT                                                           \
694 	COND_CODE_1(IS_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE), (3), (2))
695 #else
696 #define BT_PACS_SRC_LOC
697 #define PACS_SRC_PAC_LOC_CHAR_ATTR_COUNT 0
698 #endif
699 
700 #define BT_PAC_AVAILABLE_CONTEXT                                                                   \
701 	BT_AUDIO_CHRC(BT_UUID_PACS_AVAILABLE_CONTEXT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,     \
702 		      BT_GATT_PERM_READ_ENCRYPT, available_contexts_read, NULL, NULL),             \
703 	BT_AUDIO_CCC(available_context_cfg_changed),
704 
705 #define BT_PACS_SUPPORTED_CONTEXT_PROP \
706 	BT_GATT_CHRC_READ \
707 	IF_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
708 
709 #define BT_PAC_SUPPORTED_CONTEXT                                                                   \
710 	BT_AUDIO_CHRC(BT_UUID_PACS_SUPPORTED_CONTEXT, BT_PACS_SUPPORTED_CONTEXT_PROP,              \
711 		      BT_GATT_PERM_READ_ENCRYPT, supported_context_read, NULL, NULL),              \
712 	IF_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE,                                    \
713 		   (BT_AUDIO_CCC(supported_context_cfg_changed),))
714 
715 #define BT_PACS_SERVICE_DEFINITION() {                                                             \
716 	BT_GATT_PRIMARY_SERVICE(BT_UUID_PACS),                                                     \
717 	BT_PAC_SNK                                                                                 \
718 	BT_PACS_SNK_LOC                                                                            \
719 	BT_PAC_SRC                                                                                 \
720 	BT_PACS_SRC_LOC                                                                            \
721 	BT_PAC_AVAILABLE_CONTEXT                                                                   \
722 	BT_PAC_SUPPORTED_CONTEXT                                                                   \
723 }
724 
725 static const struct bt_gatt_attr _pacs_attrs[] = BT_PACS_SERVICE_DEFINITION();
726 static struct bt_gatt_attr pacs_attrs[] = BT_PACS_SERVICE_DEFINITION();
727 static struct bt_gatt_service pacs_svc = (struct bt_gatt_service)BT_GATT_SERVICE(pacs_attrs);
728 
configure_pacs_char(const struct bt_pacs_register_param * param)729 static void configure_pacs_char(const struct bt_pacs_register_param *param)
730 {
731 	const uint8_t first_attr_offset = 1U;
732 	struct bt_gatt_attr *svc_attrs =
733 		&pacs_svc.attrs[first_attr_offset]; /* first attribute is the service */
734 	uint8_t attrs_to_rem = 0U;
735 	uint8_t first_to_rem = 0U;
736 
737 	/* Remove the Sink PAC and Location */
738 #if defined(CONFIG_BT_PAC_SNK_LOC)
739 	if (!param->snk_loc) {
740 		first_to_rem = PACS_SNK_PAC_CHAR_ATTR_COUNT;
741 		attrs_to_rem = PACS_SNK_PAC_LOC_CHAR_ATTR_COUNT;
742 	}
743 #endif /* CONFIG_BT_PAC_SNK_LOC */
744 #if defined(CONFIG_BT_PAC_SNK)
745 	if (!param->snk_pac) {
746 		first_to_rem = 0U;
747 		attrs_to_rem = PACS_SNK_PAC_CHAR_ATTR_COUNT + PACS_SNK_PAC_LOC_CHAR_ATTR_COUNT;
748 	}
749 #endif /* CONFIG_BT_PAC_SNK */
750 
751 	if (attrs_to_rem > 0U) {
752 		for (uint8_t i = first_to_rem + attrs_to_rem;
753 		     i < pacs_svc.attr_count - first_attr_offset; i++) {
754 			svc_attrs[i - attrs_to_rem] = svc_attrs[i];
755 		}
756 		pacs_svc.attr_count -= attrs_to_rem;
757 	}
758 
759 #if defined(CONFIG_BT_PAC_SRC)
760 	/* Set first_to_rem to the start of Source PAC Char, for cleaner offset calc */
761 	const uint8_t src_pac_offset =
762 		(PACS_SNK_PAC_CHAR_ATTR_COUNT + PACS_SNK_PAC_LOC_CHAR_ATTR_COUNT) - attrs_to_rem;
763 	attrs_to_rem = 0U;
764 
765 	/* Remove the Source PAC and Location */
766 #if defined(CONFIG_BT_PAC_SRC_LOC)
767 	if (!param->src_loc) {
768 		first_to_rem = src_pac_offset + PACS_SRC_PAC_CHAR_ATTR_COUNT;
769 		attrs_to_rem = PACS_SRC_PAC_LOC_CHAR_ATTR_COUNT;
770 	}
771 #endif /* CONFIG_BT_PAC_SRC_LOC */
772 
773 	if (!param->src_pac) {
774 		first_to_rem = src_pac_offset;
775 		attrs_to_rem = PACS_SRC_PAC_CHAR_ATTR_COUNT + PACS_SRC_PAC_LOC_CHAR_ATTR_COUNT;
776 	}
777 
778 	if (attrs_to_rem > 0U) {
779 		for (uint8_t i = first_to_rem + attrs_to_rem;
780 		     i < pacs_svc.attr_count - first_attr_offset; i++) {
781 			svc_attrs[i - attrs_to_rem] = svc_attrs[i];
782 		}
783 		pacs_svc.attr_count -= attrs_to_rem;
784 	}
785 #endif /* CONFIG_BT_PAC_SRC */
786 }
787 
valid_pacs_register_param(const struct bt_pacs_register_param * param)788 static bool valid_pacs_register_param(const struct bt_pacs_register_param *param)
789 {
790 	bool any_pac_registered = false;
791 
792 	if (param == NULL) {
793 		LOG_DBG("param is NULL");
794 		return false;
795 	}
796 
797 #if defined(CONFIG_BT_PAC_SNK)
798 	any_pac_registered |= param->snk_pac;
799 #endif /* CONFIG_BT_PAC_SNK */
800 #if defined(CONFIG_BT_PAC_SNK_LOC)
801 	if (param->snk_loc && !param->snk_pac) {
802 		LOG_DBG("Cannot register snk_loc without snk_pac");
803 		return false;
804 	}
805 #endif /* CONFIG_BT_PAC_SNK_LOC */
806 #if defined(CONFIG_BT_PAC_SRC)
807 	any_pac_registered |= param->src_pac;
808 #endif /* CONFIG_BT_PAC_SRC */
809 #if defined(CONFIG_BT_PAC_SRC_LOC)
810 	if (param->src_loc && !param->src_pac) {
811 		LOG_DBG("Cannot register src_loc without src_pac");
812 		return false;
813 	}
814 #endif /* CONFIG_BT_PAC_SRC_LOC */
815 
816 	if (!any_pac_registered) {
817 		LOG_DBG("Neither snk_pac or src_pac registered");
818 		return false;
819 	}
820 
821 	return true;
822 }
823 
bt_pacs_register(const struct bt_pacs_register_param * param)824 int bt_pacs_register(const struct bt_pacs_register_param *param)
825 {
826 	int err = 0;
827 
828 	if (!valid_pacs_register_param(param)) {
829 		return -EINVAL;
830 	}
831 
832 	if (atomic_test_and_set_bit(pacs.flags, PACS_FLAG_REGISTERED)) {
833 		LOG_DBG("PACS already registered");
834 
835 		return -EALREADY;
836 	}
837 
838 	/* Save registration param so we can guard functions accordingly */
839 #if defined(CONFIG_BT_PAC_SNK)
840 	atomic_set_bit_to(pacs.flags, PACS_FLAG_SNK_PAC, param->snk_pac);
841 #endif /* CONFIG_BT_PAC_SNK */
842 #if defined(CONFIG_BT_PAC_SNK_LOC)
843 	atomic_set_bit_to(pacs.flags, PACS_FLAG_SNK_LOC, param->snk_loc);
844 #endif /* CONFIG_BT_PAC_SNK_LOC */
845 #if defined(CONFIG_BT_PAC_SRC)
846 	atomic_set_bit_to(pacs.flags, PACS_FLAG_SRC_PAC, param->src_pac);
847 #endif /* CONFIG_BT_PAC_SRC */
848 #if defined(CONFIG_BT_PAC_SRC_LOC)
849 	atomic_set_bit_to(pacs.flags, PACS_FLAG_SRC_LOC, param->src_loc);
850 #endif /* CONFIG_BT_PAC_SRC_LOC */
851 
852 	/* Remove characteristics if necessary */
853 	configure_pacs_char(param);
854 
855 	err = bt_gatt_service_register(&pacs_svc);
856 	if (err != 0) {
857 		LOG_DBG("Failed to register ASCS in gatt DB: %d", err);
858 		atomic_clear_bit(pacs.flags, PACS_FLAG_REGISTERED);
859 
860 		return -ENOEXEC;
861 	}
862 
863 	return 0;
864 }
865 
bt_pacs_unregister(void)866 int bt_pacs_unregister(void)
867 {
868 	int err;
869 
870 	if (!atomic_test_bit(pacs.flags, PACS_FLAG_REGISTERED)) {
871 		LOG_DBG("No pacs instance registered");
872 
873 		return -EALREADY;
874 	}
875 
876 	if (atomic_test_and_set_bit(pacs.flags, PACS_FLAG_SVC_CHANGING)) {
877 		LOG_DBG("Service change already in progress");
878 		atomic_clear_bit(pacs.flags, PACS_FLAG_SVC_CHANGING);
879 
880 		return -EBUSY;
881 	}
882 
883 	err = bt_gatt_service_unregister(&pacs_svc);
884 
885 	/* If unregistration was successful, make sure to reset pacs_attrs so it can be used for
886 	 * new registrations
887 	 */
888 	if (err != 0) {
889 		LOG_DBG("Failed to unregister PACS");
890 		atomic_clear_bit(pacs.flags, PACS_FLAG_SVC_CHANGING);
891 
892 		return err;
893 	}
894 
895 	/* Restore to original definition */
896 	memcpy(pacs_svc.attrs, &_pacs_attrs, sizeof(_pacs_attrs));
897 	pacs_svc.attr_count = ARRAY_SIZE(pacs_attrs);
898 
899 	atomic_clear_bit(pacs.flags, PACS_FLAG_REGISTERED);
900 	atomic_clear_bit(pacs.flags, PACS_FLAG_SVC_CHANGING);
901 
902 	return err;
903 }
904 
905 #if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE) || defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
pac_notify_loc(struct bt_conn * conn,enum bt_audio_dir dir)906 static int pac_notify_loc(struct bt_conn *conn, enum bt_audio_dir dir)
907 {
908 	uint32_t location_le;
909 	int err;
910 	const struct bt_uuid *uuid;
911 
912 	switch (dir) {
913 #if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)
914 	case BT_AUDIO_DIR_SINK:
915 		location_le = sys_cpu_to_le32(pacs_snk_location);
916 		uuid = pacs_snk_loc_uuid;
917 		break;
918 #endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */
919 #if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
920 	case BT_AUDIO_DIR_SOURCE:
921 		location_le = sys_cpu_to_le32(pacs_src_location);
922 		uuid = pacs_src_loc_uuid;
923 		break;
924 #endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
925 	default:
926 		return -EINVAL;
927 	}
928 
929 	err = pacs_gatt_notify(conn, uuid, pacs_svc.attrs, &location_le, sizeof(location_le));
930 	if (err != 0 && err != -ENOTCONN) {
931 		LOG_WRN("PACS notify_loc failed: %d", err);
932 		return err;
933 	}
934 
935 	return 0;
936 }
937 #endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE || CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
938 
939 #if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE) || defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
pac_notify(struct bt_conn * conn,enum bt_audio_dir dir)940 static int pac_notify(struct bt_conn *conn, enum bt_audio_dir dir)
941 {
942 	int err = 0;
943 	sys_slist_t *pac;
944 	const struct bt_uuid *uuid;
945 
946 	switch (dir) {
947 #if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE)
948 	case BT_AUDIO_DIR_SINK:
949 		uuid = pacs_snk_uuid;
950 		break;
951 #endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */
952 #if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
953 	case BT_AUDIO_DIR_SOURCE:
954 		uuid = pacs_src_uuid;
955 		break;
956 #endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
957 	default:
958 		return -EINVAL;
959 	}
960 
961 	err = k_sem_take(&read_buf_sem, K_NO_WAIT);
962 	if (err != 0) {
963 		LOG_DBG("Failed to take read_buf_sem: %d", err);
964 
965 		return err;
966 	}
967 
968 	pac = pacs_get_pac(dir);
969 	__ASSERT(pac, "Failed to get pacs.\n");
970 	get_pac_records(pac, &read_buf);
971 
972 	err = pacs_gatt_notify(conn, uuid, pacs_svc.attrs,
973 			       read_buf.data, read_buf.len);
974 	if (err != 0 && err != -ENOTCONN) {
975 		LOG_WRN("PACS notify failed: %d", err);
976 	}
977 
978 	k_sem_give(&read_buf_sem);
979 
980 	if (err == -ENOTCONN) {
981 		return 0;
982 	} else {
983 		return 0;
984 	}
985 }
986 #endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE || CONFIG_BT_PAC_SRC_NOTIFIABLE */
987 
available_contexts_notify(struct bt_conn * conn)988 static int available_contexts_notify(struct bt_conn *conn)
989 {
990 	struct bt_pacs_context context = {
991 		.snk = sys_cpu_to_le16(
992 			pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK)),
993 		.src = sys_cpu_to_le16(
994 			pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE)),
995 	};
996 	int err;
997 
998 	err = pacs_gatt_notify(conn, BT_UUID_PACS_AVAILABLE_CONTEXT, pacs_svc.attrs,
999 				  &context, sizeof(context));
1000 	if (err != 0 && err != -ENOTCONN) {
1001 		LOG_WRN("Available Audio Contexts notify failed: %d", err);
1002 		return err;
1003 	}
1004 
1005 	return 0;
1006 }
1007 
supported_contexts_notify(struct bt_conn * conn)1008 static int supported_contexts_notify(struct bt_conn *conn)
1009 {
1010 	struct bt_pacs_context context = {
1011 		.snk = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SINK)),
1012 		.src = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SOURCE)),
1013 	};
1014 	int err;
1015 
1016 	err = pacs_gatt_notify(conn, BT_UUID_PACS_SUPPORTED_CONTEXT, pacs_svc.attrs,
1017 				  &context, sizeof(context));
1018 	if (err != 0 && err != -ENOTCONN) {
1019 		LOG_WRN("Supported Audio Contexts notify failed: %d", err);
1020 
1021 		return err;
1022 	}
1023 	return 0;
1024 }
1025 
pacs_gatt_notify_complete_cb(struct bt_conn * conn,void * user_data)1026 void pacs_gatt_notify_complete_cb(struct bt_conn *conn, void *user_data)
1027 {
1028 	/* Notification done, clear bit and reschedule work */
1029 	atomic_clear_bit(pacs.flags, PACS_FLAG_NOTIFY_RDY);
1030 	k_work_submit(&deferred_nfy_work);
1031 }
1032 
pacs_gatt_notify(struct bt_conn * conn,const struct bt_uuid * uuid,const struct bt_gatt_attr * attr,const void * data,uint16_t len)1033 static int pacs_gatt_notify(struct bt_conn *conn,
1034 			    const struct bt_uuid *uuid,
1035 			    const struct bt_gatt_attr *attr,
1036 			    const void *data,
1037 			    uint16_t len)
1038 {
1039 	int err;
1040 	struct bt_gatt_notify_params params;
1041 
1042 	memset(&params, 0, sizeof(params));
1043 	params.uuid = uuid;
1044 	params.attr = attr;
1045 	params.data = data;
1046 	params.len  = len;
1047 	params.func = pacs_gatt_notify_complete_cb;
1048 
1049 	/* Mark notification in progress */
1050 	if (atomic_test_bit(pacs.flags, PACS_FLAG_SVC_CHANGING) ||
1051 	    !atomic_test_bit(pacs.flags, PACS_FLAG_REGISTERED)) {
1052 		return 0;
1053 	}
1054 
1055 	atomic_set_bit(pacs.flags, PACS_FLAG_NOTIFY_RDY);
1056 
1057 	err = bt_gatt_notify_cb(conn, &params);
1058 	if (err != 0) {
1059 		atomic_clear_bit(pacs.flags, PACS_FLAG_NOTIFY_RDY);
1060 	}
1061 
1062 	if (err && err != -ENOTCONN) {
1063 		return err;
1064 	}
1065 
1066 	return 0;
1067 }
1068 
notify_cb(struct bt_conn * conn,void * data)1069 static void notify_cb(struct bt_conn *conn, void *data)
1070 {
1071 	struct pacs_client *client;
1072 	struct bt_conn_info info;
1073 	int err = 0;
1074 
1075 	LOG_DBG("");
1076 
1077 	err = bt_conn_get_info(conn, &info);
1078 	if (err != 0) {
1079 		LOG_ERR("Failed to get conn info: %d", err);
1080 		return;
1081 	}
1082 
1083 	if (info.state != BT_CONN_STATE_CONNECTED) {
1084 		/* Not connected */
1085 		return;
1086 	}
1087 
1088 	client = client_lookup_conn(conn);
1089 	if (client == NULL) {
1090 		return;
1091 	}
1092 
1093 	/* Check if we have unverified notifications in progress */
1094 	if (atomic_test_bit(pacs.flags, PACS_FLAG_NOTIFY_RDY)) {
1095 		return;
1096 	}
1097 
1098 #if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE)
1099 	if (atomic_test_bit(client->flags, FLAG_SINK_PAC_CHANGED)) {
1100 		LOG_DBG("Notifying Sink PAC");
1101 		err = pac_notify(conn, BT_AUDIO_DIR_SINK);
1102 		if (!err) {
1103 			atomic_clear_bit(client->flags, FLAG_SINK_PAC_CHANGED);
1104 		}
1105 	}
1106 #endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */
1107 
1108 #if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)
1109 	if (atomic_test_bit(client->flags, FLAG_SINK_AUDIO_LOCATIONS_CHANGED)) {
1110 		LOG_DBG("Notifying Sink Audio Location");
1111 		err = pac_notify_loc(conn, BT_AUDIO_DIR_SINK);
1112 		if (!err) {
1113 			atomic_clear_bit(client->flags, FLAG_SINK_AUDIO_LOCATIONS_CHANGED);
1114 		}
1115 	}
1116 #endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */
1117 
1118 #if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
1119 	if (atomic_test_bit(client->flags, FLAG_SOURCE_PAC_CHANGED)) {
1120 		LOG_DBG("Notifying Source PAC");
1121 		err = pac_notify(conn, BT_AUDIO_DIR_SOURCE);
1122 		if (!err) {
1123 			atomic_clear_bit(client->flags, FLAG_SOURCE_PAC_CHANGED);
1124 		}
1125 	}
1126 #endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
1127 
1128 #if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
1129 	if (atomic_test_and_clear_bit(client->flags, FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED)) {
1130 		LOG_DBG("Notifying Source Audio Location");
1131 		err = pac_notify_loc(conn, BT_AUDIO_DIR_SOURCE);
1132 		if (!err) {
1133 			atomic_clear_bit(client->flags, FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED);
1134 		}
1135 	}
1136 #endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
1137 
1138 	if (atomic_test_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED)) {
1139 		LOG_DBG("Notifying Available Contexts");
1140 		err = available_contexts_notify(conn);
1141 		if (!err) {
1142 			atomic_clear_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED);
1143 		}
1144 	}
1145 
1146 	if (IS_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE) &&
1147 	    atomic_test_bit(client->flags, FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED)) {
1148 		LOG_DBG("Notifying Supported Contexts");
1149 		err = supported_contexts_notify(conn);
1150 		if (!err) {
1151 			atomic_clear_bit(client->flags, FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED);
1152 		}
1153 	}
1154 }
1155 
deferred_nfy_work_handler(struct k_work * work)1156 static void deferred_nfy_work_handler(struct k_work *work)
1157 {
1158 	bt_conn_foreach(BT_CONN_TYPE_LE, notify_cb, NULL);
1159 }
1160 
pacs_auth_pairing_complete(struct bt_conn * conn,bool bonded)1161 static void pacs_auth_pairing_complete(struct bt_conn *conn, bool bonded)
1162 {
1163 	LOG_DBG("%s paired (%sbonded)", bt_addr_le_str(bt_conn_get_dst(conn)),
1164 		bonded ? "" : "not ");
1165 
1166 	if (!bonded) {
1167 		return;
1168 	}
1169 
1170 	/* Check if already in list, and do nothing if it is */
1171 	for (size_t i = 0U; i < ARRAY_SIZE(pacs.clients); i++) {
1172 		if (atomic_test_bit(pacs.clients[i].flags, FLAG_ACTIVE) &&
1173 		    bt_addr_le_eq(bt_conn_get_dst(conn), &pacs.clients[i].addr)) {
1174 			return;
1175 		}
1176 	}
1177 
1178 	/* Else add the device */
1179 	for (size_t i = 0U; i < ARRAY_SIZE(pacs.clients); i++) {
1180 		if (!atomic_test_bit(pacs.clients[i].flags, FLAG_ACTIVE)) {
1181 			atomic_set_bit(pacs.clients[i].flags, FLAG_ACTIVE);
1182 			memcpy(&pacs.clients[i].addr, bt_conn_get_dst(conn), sizeof(bt_addr_le_t));
1183 
1184 			/* Send out all pending notifications */
1185 			k_work_submit(&deferred_nfy_work);
1186 			return;
1187 		}
1188 	}
1189 }
1190 
pacs_bond_deleted(uint8_t id,const bt_addr_le_t * peer)1191 static void pacs_bond_deleted(uint8_t id, const bt_addr_le_t *peer)
1192 {
1193 	/* Find the device entry to delete */
1194 	for (size_t i = 0U; i < ARRAY_SIZE(pacs.clients); i++) {
1195 		/* Check if match, and if active, if so, reset */
1196 		if (atomic_test_bit(pacs.clients[i].flags, FLAG_ACTIVE) &&
1197 		    bt_addr_le_eq(peer, &pacs.clients[i].addr)) {
1198 			for (size_t j = 0U; j < FLAG_NUM; j++) {
1199 				atomic_clear_bit(pacs.clients[i].flags, j);
1200 			}
1201 			(void)memset(&pacs.clients[i].addr, 0, sizeof(bt_addr_le_t));
1202 			return;
1203 		}
1204 	}
1205 }
1206 
pacs_security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err sec_err)1207 static void pacs_security_changed(struct bt_conn *conn, bt_security_t level,
1208 				  enum bt_security_err sec_err)
1209 {
1210 	struct bt_conn_info info;
1211 	int err;
1212 
1213 	LOG_DBG("%s changed security level to %d", bt_addr_le_str(bt_conn_get_dst(conn)), level);
1214 
1215 	if (sec_err != BT_SECURITY_ERR_SUCCESS || level <= BT_SECURITY_L1) {
1216 		return;
1217 	}
1218 
1219 	err = bt_conn_get_info(conn, &info);
1220 	if (err < 0) {
1221 		__ASSERT_NO_MSG(false);
1222 		return;
1223 	}
1224 
1225 	if (!bt_le_bond_exists(info.id, info.le.dst)) {
1226 		return;
1227 	}
1228 
1229 	for (size_t i = 0U; i < ARRAY_SIZE(pacs.clients); i++) {
1230 		for (size_t j = 0U; j < FLAG_NUM; j++) {
1231 			if (atomic_test_bit(pacs.clients[i].flags, j)) {
1232 
1233 				/**
1234 				 *  It's enough that one flag is set, as the defer work will go
1235 				 * through all notifiable characteristics
1236 				 */
1237 				k_work_submit(&deferred_nfy_work);
1238 				return;
1239 			}
1240 		}
1241 	}
1242 }
1243 
pacs_disconnected(struct bt_conn * conn,uint8_t reason)1244 static void pacs_disconnected(struct bt_conn *conn, uint8_t reason)
1245 {
1246 	struct pacs_client *client;
1247 
1248 	client = client_lookup_conn(conn);
1249 	if (client == NULL) {
1250 		return;
1251 	}
1252 
1253 #if defined(CONFIG_BT_PAC_SNK)
1254 	if (atomic_test_bit(pacs.flags, PACS_FLAG_SNK_PAC) &&
1255 	    client->snk_available_contexts != NULL) {
1256 		uint16_t old = POINTER_TO_UINT(client->snk_available_contexts);
1257 		uint16_t new;
1258 
1259 		client->snk_available_contexts = NULL;
1260 		new = pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK);
1261 
1262 		atomic_set_bit_to(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED, old != new);
1263 	}
1264 #endif /* CONFIG_BT_PAC_SNK */
1265 
1266 #if defined(CONFIG_BT_PAC_SRC)
1267 	if (atomic_test_bit(pacs.flags, PACS_FLAG_SRC_PAC) &&
1268 	    client->src_available_contexts != NULL) {
1269 		uint16_t old = POINTER_TO_UINT(client->src_available_contexts);
1270 		uint16_t new;
1271 
1272 		client->src_available_contexts = NULL;
1273 		new = pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE);
1274 
1275 		atomic_set_bit_to(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED, old != new);
1276 	}
1277 #endif /* CONFIG_BT_PAC_SRC */
1278 }
1279 
1280 BT_CONN_CB_DEFINE(conn_callbacks) = {
1281 	.security_changed = pacs_security_changed,
1282 	.disconnected = pacs_disconnected,
1283 };
1284 
1285 static struct bt_conn_auth_info_cb auth_callbacks = {
1286 	.pairing_complete = pacs_auth_pairing_complete,
1287 	.bond_deleted = pacs_bond_deleted
1288 };
1289 
bt_pacs_cap_foreach(enum bt_audio_dir dir,bt_pacs_cap_foreach_func_t func,void * user_data)1290 void bt_pacs_cap_foreach(enum bt_audio_dir dir, bt_pacs_cap_foreach_func_t func, void *user_data)
1291 {
1292 	sys_slist_t *pac;
1293 
1294 	CHECKIF(func == NULL) {
1295 		LOG_ERR("func is NULL");
1296 		return;
1297 	}
1298 
1299 	pac = pacs_get_pac(dir);
1300 	if (!pac) {
1301 		return;
1302 	}
1303 
1304 	foreach_cap(pac, func, user_data);
1305 }
1306 
add_bonded_addr_to_client_list(const struct bt_bond_info * info,void * data)1307 static void add_bonded_addr_to_client_list(const struct bt_bond_info *info, void *data)
1308 {
1309 	for (uint8_t i = 0; i < ARRAY_SIZE(pacs.clients); i++) {
1310 		/* Check if device is registered, it not, add it */
1311 		if (!atomic_test_bit(pacs.clients[i].flags, FLAG_ACTIVE)) {
1312 			char addr_str[BT_ADDR_LE_STR_LEN];
1313 
1314 			atomic_set_bit(pacs.clients[i].flags, FLAG_ACTIVE);
1315 			memcpy(&pacs.clients[i].addr, &info->addr, sizeof(bt_addr_le_t));
1316 			bt_addr_le_to_str(&pacs.clients[i].addr, addr_str, sizeof(addr_str));
1317 			LOG_DBG("Added %s to bonded list\n", addr_str);
1318 			return;
1319 		}
1320 	}
1321 }
1322 
1323 /* Register Audio Capability */
bt_pacs_cap_register(enum bt_audio_dir dir,struct bt_pacs_cap * cap)1324 int bt_pacs_cap_register(enum bt_audio_dir dir, struct bt_pacs_cap *cap)
1325 {
1326 	const struct bt_audio_codec_cap *codec_cap;
1327 	static bool callbacks_registered;
1328 	sys_slist_t *pac;
1329 
1330 	if (!cap || !cap->codec_cap) {
1331 		return -EINVAL;
1332 	}
1333 
1334 	codec_cap = cap->codec_cap;
1335 
1336 	pac = pacs_get_pac(dir);
1337 	if (!pac) {
1338 		return -EINVAL;
1339 	}
1340 
1341 	/* Restore bonding list */
1342 	bt_foreach_bond(BT_ID_DEFAULT, add_bonded_addr_to_client_list, NULL);
1343 
1344 	LOG_DBG("cap %p dir %s codec_cap id 0x%02x codec_cap cid 0x%04x codec_cap vid 0x%04x", cap,
1345 		bt_audio_dir_str(dir), codec_cap->id, codec_cap->cid, codec_cap->vid);
1346 
1347 	sys_slist_append(pac, &cap->_node);
1348 
1349 	if (!callbacks_registered) {
1350 		bt_conn_auth_info_cb_register(&auth_callbacks);
1351 
1352 		callbacks_registered = true;
1353 	}
1354 
1355 	if (IS_ENABLED(CONFIG_BT_PAC_SNK_NOTIFIABLE) && dir == BT_AUDIO_DIR_SINK) {
1356 		pacs_set_notify_bit(FLAG_SINK_PAC_CHANGED);
1357 		k_work_submit(&deferred_nfy_work);
1358 	}
1359 
1360 	if (IS_ENABLED(CONFIG_BT_PAC_SRC_NOTIFIABLE) && dir == BT_AUDIO_DIR_SOURCE) {
1361 		pacs_set_notify_bit(FLAG_SOURCE_PAC_CHANGED);
1362 		k_work_submit(&deferred_nfy_work);
1363 	}
1364 
1365 	return 0;
1366 }
1367 
1368 /* Unregister Audio Capability */
bt_pacs_cap_unregister(enum bt_audio_dir dir,struct bt_pacs_cap * cap)1369 int bt_pacs_cap_unregister(enum bt_audio_dir dir, struct bt_pacs_cap *cap)
1370 {
1371 	sys_slist_t *pac;
1372 
1373 	if (!cap) {
1374 		return -EINVAL;
1375 	}
1376 
1377 	pac = pacs_get_pac(dir);
1378 	if (!pac) {
1379 		return -EINVAL;
1380 	}
1381 
1382 	LOG_DBG("cap %p dir %s", cap, bt_audio_dir_str(dir));
1383 
1384 	if (!sys_slist_find_and_remove(pac, &cap->_node)) {
1385 		return -ENOENT;
1386 	}
1387 
1388 	switch (dir) {
1389 #if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE)
1390 	case BT_AUDIO_DIR_SINK:
1391 		pacs_set_notify_bit(FLAG_SINK_PAC_CHANGED);
1392 		k_work_submit(&deferred_nfy_work);
1393 		break;
1394 #endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE) */
1395 #if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
1396 	case BT_AUDIO_DIR_SOURCE:
1397 		pacs_set_notify_bit(FLAG_SOURCE_PAC_CHANGED);
1398 		k_work_submit(&deferred_nfy_work);
1399 		break;
1400 #endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
1401 	default:
1402 		return -EINVAL;
1403 	}
1404 
1405 	return 0;
1406 }
1407 
bt_pacs_set_location(enum bt_audio_dir dir,enum bt_audio_location location)1408 int bt_pacs_set_location(enum bt_audio_dir dir, enum bt_audio_location location)
1409 {
1410 	switch (dir) {
1411 	case BT_AUDIO_DIR_SINK:
1412 		set_snk_location(location);
1413 		break;
1414 	case BT_AUDIO_DIR_SOURCE:
1415 		set_src_location(location);
1416 		break;
1417 	default:
1418 		return -EINVAL;
1419 	}
1420 
1421 	return 0;
1422 }
1423 
bt_pacs_set_available_contexts(enum bt_audio_dir dir,enum bt_audio_context contexts)1424 int bt_pacs_set_available_contexts(enum bt_audio_dir dir, enum bt_audio_context contexts)
1425 {
1426 	if (!atomic_test_bit(pacs.flags, PACS_FLAG_REGISTERED)) {
1427 		return -EINVAL;
1428 	}
1429 	switch (dir) {
1430 	case BT_AUDIO_DIR_SINK:
1431 		if (atomic_test_bit(pacs.flags, PACS_FLAG_SNK_PAC)) {
1432 			return set_available_contexts(contexts, &snk_available_contexts,
1433 						      supported_context_get(dir));
1434 		}
1435 		return -EINVAL;
1436 	case BT_AUDIO_DIR_SOURCE:
1437 		if (atomic_test_bit(pacs.flags, PACS_FLAG_SRC_PAC)) {
1438 			return set_available_contexts(contexts, &src_available_contexts,
1439 						      supported_context_get(dir));
1440 		}
1441 		return -EINVAL;
1442 	}
1443 
1444 	return -EINVAL;
1445 }
1446 
bt_pacs_conn_set_available_contexts_for_conn(struct bt_conn * conn,enum bt_audio_dir dir,enum bt_audio_context * contexts)1447 int bt_pacs_conn_set_available_contexts_for_conn(struct bt_conn *conn, enum bt_audio_dir dir,
1448 						 enum bt_audio_context *contexts)
1449 {
1450 	enum bt_audio_context old = pacs_get_available_contexts_for_conn(conn, dir);
1451 	struct bt_conn_info info = { 0 };
1452 	struct pacs_client *client;
1453 	int err;
1454 
1455 	client = client_lookup_conn(conn);
1456 	if (client == NULL) {
1457 		return -ENOENT;
1458 	}
1459 
1460 	err = bt_conn_get_info(conn, &info);
1461 	if (err < 0) {
1462 		LOG_ERR("Could not get conn info: %d", err);
1463 		return err;
1464 	}
1465 
1466 	switch (dir) {
1467 #if defined(CONFIG_BT_PAC_SNK)
1468 	case BT_AUDIO_DIR_SINK:
1469 		if (atomic_test_bit(pacs.flags, PACS_FLAG_SNK_PAC)) {
1470 			if (contexts != NULL) {
1471 				client->snk_available_contexts = UINT_TO_POINTER(*contexts);
1472 			} else {
1473 				client->snk_available_contexts = NULL;
1474 			}
1475 			break;
1476 		}
1477 
1478 		return -EINVAL;
1479 #endif /* CONFIG_BT_PAC_SNK */
1480 #if defined(CONFIG_BT_PAC_SRC)
1481 	case BT_AUDIO_DIR_SOURCE:
1482 		if (atomic_test_bit(pacs.flags, PACS_FLAG_SRC_PAC)) {
1483 			if (contexts != NULL) {
1484 				client->src_available_contexts = UINT_TO_POINTER(*contexts);
1485 			} else {
1486 				client->src_available_contexts = NULL;
1487 			}
1488 			break;
1489 		}
1490 
1491 		return -EINVAL;
1492 #endif /* CONFIG_BT_PAC_SRC */
1493 	default:
1494 		return -EINVAL;
1495 	}
1496 
1497 	if (pacs_get_available_contexts_for_conn(conn, dir) == old) {
1498 		/* No change. Skip notification */
1499 		return 0;
1500 	}
1501 
1502 	atomic_set_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED);
1503 
1504 	/* Send notification on encrypted link only */
1505 	if (info.security.level > BT_SECURITY_L1) {
1506 		k_work_submit(&deferred_nfy_work);
1507 	}
1508 
1509 	return 0;
1510 }
1511 
bt_pacs_set_supported_contexts(enum bt_audio_dir dir,enum bt_audio_context contexts)1512 int bt_pacs_set_supported_contexts(enum bt_audio_dir dir, enum bt_audio_context contexts)
1513 {
1514 	uint16_t *supported_contexts = NULL;
1515 	uint16_t *available_contexts = NULL;
1516 
1517 	switch (dir) {
1518 	case BT_AUDIO_DIR_SINK:
1519 #if defined(CONFIG_BT_PAC_SNK)
1520 		if (atomic_test_bit(pacs.flags, PACS_FLAG_SNK_PAC)) {
1521 			supported_contexts = &snk_supported_contexts;
1522 			available_contexts = &snk_available_contexts;
1523 			break;
1524 		}
1525 		return -EINVAL;
1526 #endif /* CONFIG_BT_PAC_SNK */
1527 		return -ENOTSUP;
1528 	case BT_AUDIO_DIR_SOURCE:
1529 #if defined(CONFIG_BT_PAC_SRC)
1530 		if (atomic_test_bit(pacs.flags, PACS_FLAG_SRC_PAC)) {
1531 			supported_contexts = &src_supported_contexts;
1532 			available_contexts = &src_available_contexts;
1533 			break;
1534 		}
1535 		return -EINVAL;
1536 #endif /* CONFIG_BT_PAC_SRC */
1537 		return -ENOTSUP;
1538 	default:
1539 		return -EINVAL;
1540 	}
1541 
1542 	if (IS_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE) || *supported_contexts == 0) {
1543 		return set_supported_contexts(contexts, supported_contexts, available_contexts);
1544 	}
1545 
1546 	return -EALREADY;
1547 }
1548 
bt_pacs_get_available_contexts(enum bt_audio_dir dir)1549 enum bt_audio_context bt_pacs_get_available_contexts(enum bt_audio_dir dir)
1550 {
1551 	switch (dir) {
1552 	case BT_AUDIO_DIR_SINK:
1553 		if (atomic_test_bit(pacs.flags, PACS_FLAG_SNK_PAC)) {
1554 			return snk_available_contexts;
1555 		}
1556 		return -EINVAL;
1557 	case BT_AUDIO_DIR_SOURCE:
1558 		if (atomic_test_bit(pacs.flags, PACS_FLAG_SRC_PAC)) {
1559 			return src_available_contexts;
1560 		}
1561 		return -EINVAL;
1562 	}
1563 
1564 	return BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
1565 }
1566 
bt_pacs_get_available_contexts_for_conn(struct bt_conn * conn,enum bt_audio_dir dir)1567 enum bt_audio_context bt_pacs_get_available_contexts_for_conn(struct bt_conn *conn,
1568 							      enum bt_audio_dir dir)
1569 {
1570 	CHECKIF(conn == NULL) {
1571 		LOG_ERR("NULL conn");
1572 		return BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
1573 	}
1574 
1575 	return pacs_get_available_contexts_for_conn(conn, dir);
1576 }
1577 
1578 struct codec_cap_lookup_id_data {
1579 	const struct bt_pac_codec *codec_id;
1580 	const struct bt_audio_codec_cap *codec_cap;
1581 };
1582 
codec_lookup_id(const struct bt_pacs_cap * cap,void * user_data)1583 static bool codec_lookup_id(const struct bt_pacs_cap *cap, void *user_data)
1584 {
1585 	struct codec_cap_lookup_id_data *data = user_data;
1586 
1587 	if (cap->codec_cap->id == data->codec_id->id &&
1588 	    cap->codec_cap->cid == data->codec_id->cid &&
1589 	    cap->codec_cap->vid == data->codec_id->vid) {
1590 		data->codec_cap = cap->codec_cap;
1591 
1592 		return false;
1593 	}
1594 
1595 	return true;
1596 }
1597 
bt_pacs_get_codec_cap(enum bt_audio_dir dir,const struct bt_pac_codec * codec_id)1598 const struct bt_audio_codec_cap *bt_pacs_get_codec_cap(enum bt_audio_dir dir,
1599 						       const struct bt_pac_codec *codec_id)
1600 {
1601 	struct codec_cap_lookup_id_data lookup_data = {
1602 		.codec_id = codec_id,
1603 		.codec_cap = NULL,
1604 	};
1605 
1606 	bt_pacs_cap_foreach(dir, codec_lookup_id, &lookup_data);
1607 
1608 	return lookup_data.codec_cap;
1609 }
1610