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/device.h>
29 #include <zephyr/init.h>
30 #include <zephyr/kernel.h>
31 #include <zephyr/logging/log.h>
32 #include <zephyr/net_buf.h>
33 #include <zephyr/sys/__assert.h>
34 #include <zephyr/sys/atomic.h>
35 #include <zephyr/sys/byteorder.h>
36 #include <zephyr/sys/check.h>
37 #include <zephyr/sys/slist.h>
38 #include <zephyr/sys/util.h>
39 #include <zephyr/sys/util_macro.h>
40 
41 #include "../host/conn_internal.h"
42 #include "../host/hci_core.h"
43 #include "common/bt_str.h"
44 
45 #include "audio_internal.h"
46 #include "bap_unicast_server.h"
47 #include "pacs_internal.h"
48 
49 LOG_MODULE_REGISTER(bt_pacs, CONFIG_BT_PACS_LOG_LEVEL);
50 
51 #define PAC_NOTIFY_TIMEOUT	K_MSEC(10)
52 #define READ_BUF_SEM_TIMEOUT    K_MSEC(50)
53 
54 #if defined(CONFIG_BT_PAC_SRC)
55 static uint32_t pacs_src_location;
56 static sys_slist_t src_pacs_list = SYS_SLIST_STATIC_INIT(&src_pacs_list);
57 static uint16_t src_supported_contexts;
58 #endif /* CONFIG_BT_PAC_SRC */
59 
60 #if defined(CONFIG_BT_PAC_SNK)
61 static uint32_t pacs_snk_location;
62 static sys_slist_t snk_pacs_list = SYS_SLIST_STATIC_INIT(&snk_pacs_list);
63 static uint16_t snk_supported_contexts;
64 #endif /* CONFIG_BT_PAC_SNK */
65 
66 static uint16_t src_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
67 static uint16_t snk_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
68 
69 enum {
70 	FLAG_ACTIVE,
71 	FLAG_SINK_PAC_CHANGED,
72 	FLAG_SINK_AUDIO_LOCATIONS_CHANGED,
73 	FLAG_SOURCE_PAC_CHANGED,
74 	FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED,
75 	FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED,
76 	FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED,
77 	FLAG_NUM,
78 };
79 
80 static struct pacs_client {
81 	bt_addr_le_t addr;
82 
83 #if defined(CONFIG_BT_PAC_SNK)
84 	/* Sink Available Contexts override value */
85 	uint16_t *snk_available_contexts;
86 #endif /* CONFIG_BT_PAC_SNK */
87 
88 #if defined(CONFIG_BT_PAC_SRC)
89 	/* Source Available Contexts override value */
90 	uint16_t *src_available_contexts;
91 #endif /* CONFIG_BT_PAC_SRC */
92 
93 	/* Pending notification flags */
94 	ATOMIC_DEFINE(flags, FLAG_NUM);
95 } clients[CONFIG_BT_MAX_PAIRED];
96 
97 static atomic_t notify_rdy;
98 
99 static K_SEM_DEFINE(read_buf_sem, 1, 1);
100 NET_BUF_SIMPLE_DEFINE_STATIC(read_buf, BT_ATT_MAX_ATTRIBUTE_LEN);
101 
102 static int pacs_gatt_notify(struct bt_conn *conn,
103 			    const struct bt_uuid *uuid,
104 			    const struct bt_gatt_attr *attr,
105 			    const void *data,
106 			    uint16_t len);
107 static void deferred_nfy_work_handler(struct k_work *work);
108 
109 static K_WORK_DEFINE(deferred_nfy_work, deferred_nfy_work_handler);
110 
111 struct pac_records_build_data {
112 	struct bt_pacs_read_rsp *rsp;
113 	struct net_buf_simple *buf;
114 };
115 
client_lookup_conn(const struct bt_conn * conn)116 static struct pacs_client *client_lookup_conn(const struct bt_conn *conn)
117 {
118 	__ASSERT_NO_MSG(conn != NULL);
119 
120 	for (size_t i = 0; i < ARRAY_SIZE(clients); i++) {
121 		if (atomic_test_bit(clients[i].flags, FLAG_ACTIVE) &&
122 		    bt_addr_le_eq(&clients[i].addr, bt_conn_get_dst(conn))) {
123 			return &clients[i];
124 		}
125 	}
126 
127 	return NULL;
128 }
129 
pacs_set_notify_bit(int bit)130 static void pacs_set_notify_bit(int bit)
131 {
132 	for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) {
133 		if (atomic_test_bit(clients[i].flags, FLAG_ACTIVE)) {
134 			atomic_set_bit(clients[i].flags, bit);
135 		}
136 	}
137 }
138 
build_pac_records(const struct bt_pacs_cap * cap,void * user_data)139 static bool build_pac_records(const struct bt_pacs_cap *cap, void *user_data)
140 {
141 	struct pac_records_build_data *data = user_data;
142 	const struct bt_audio_codec_cap *codec_cap = cap->codec_cap;
143 	struct net_buf_simple *buf = data->buf;
144 	struct net_buf_simple_state state;
145 	struct bt_pac_codec *pac_codec;
146 
147 	net_buf_simple_save(buf, &state);
148 
149 	if (net_buf_simple_tailroom(buf) < sizeof(*pac_codec)) {
150 		goto fail;
151 	}
152 
153 	pac_codec = net_buf_simple_add(buf, sizeof(*pac_codec));
154 	pac_codec->id = codec_cap->id;
155 	pac_codec->cid = sys_cpu_to_le16(codec_cap->cid);
156 	pac_codec->vid = sys_cpu_to_le16(codec_cap->vid);
157 
158 	if (net_buf_simple_tailroom(buf) < (sizeof(struct bt_pac_ltv_data) + codec_cap->data_len)) {
159 		goto fail;
160 	}
161 
162 	net_buf_simple_add_u8(buf, codec_cap->data_len);
163 	net_buf_simple_add_mem(buf, codec_cap->data, codec_cap->data_len);
164 
165 	if (net_buf_simple_tailroom(buf) < (sizeof(struct bt_pac_ltv_data) + codec_cap->meta_len)) {
166 		goto fail;
167 	}
168 
169 	net_buf_simple_add_u8(buf, codec_cap->meta_len);
170 	net_buf_simple_add_mem(buf, codec_cap->meta, codec_cap->meta_len);
171 
172 	data->rsp->num_pac++;
173 
174 	return true;
175 
176 fail:
177 	__ASSERT(false, "No space for %p", cap);
178 
179 	net_buf_simple_restore(buf, &state);
180 
181 	return false;
182 }
183 
foreach_cap(sys_slist_t * list,bt_pacs_cap_foreach_func_t func,void * user_data)184 static void foreach_cap(sys_slist_t *list, bt_pacs_cap_foreach_func_t func,
185 			void *user_data)
186 {
187 	struct bt_pacs_cap *cap;
188 
189 	SYS_SLIST_FOR_EACH_CONTAINER(list, cap, _node) {
190 		if (!func(cap, user_data)) {
191 			break;
192 		}
193 	}
194 }
195 
get_pac_records(sys_slist_t * list,struct net_buf_simple * buf)196 static void get_pac_records(sys_slist_t *list, struct net_buf_simple *buf)
197 {
198 	struct pac_records_build_data data;
199 
200 	/* Reset if buffer before using */
201 	net_buf_simple_reset(buf);
202 
203 	data.rsp = net_buf_simple_add(buf, sizeof(*data.rsp));
204 	data.rsp->num_pac = 0;
205 	data.buf = buf;
206 
207 	foreach_cap(list, build_pac_records, &data);
208 }
209 
available_context_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)210 static void available_context_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
211 {
212 	LOG_DBG("attr %p value 0x%04x", attr, value);
213 }
214 
pacs_get_available_contexts_for_conn(struct bt_conn * conn,enum bt_audio_dir dir)215 static enum bt_audio_context pacs_get_available_contexts_for_conn(struct bt_conn *conn,
216 								  enum bt_audio_dir dir)
217 {
218 	const struct pacs_client *client;
219 
220 	client = client_lookup_conn(conn);
221 	if (client == NULL) {
222 		LOG_DBG("No client context for conn %p", (void *)conn);
223 		return bt_pacs_get_available_contexts(dir);
224 	}
225 
226 	switch (dir) {
227 	case BT_AUDIO_DIR_SINK:
228 #if defined(CONFIG_BT_PAC_SNK)
229 		if (client->snk_available_contexts != NULL) {
230 			return POINTER_TO_UINT(client->snk_available_contexts);
231 		}
232 #endif /* CONFIG_BT_PAC_SNK */
233 		break;
234 	case BT_AUDIO_DIR_SOURCE:
235 #if defined(CONFIG_BT_PAC_SRC)
236 		if (client->src_available_contexts != NULL) {
237 			return POINTER_TO_UINT(client->src_available_contexts);
238 		}
239 #endif /* CONFIG_BT_PAC_SRC */
240 		break;
241 	}
242 
243 	return bt_pacs_get_available_contexts(dir);
244 }
245 
available_contexts_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)246 static ssize_t available_contexts_read(struct bt_conn *conn,
247 				       const struct bt_gatt_attr *attr, void *buf,
248 				       uint16_t len, uint16_t offset)
249 {
250 	struct bt_pacs_context context = {
251 		.snk = sys_cpu_to_le16(
252 			pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK)),
253 		.src = sys_cpu_to_le16(
254 			pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE)),
255 	};
256 
257 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
258 
259 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &context,
260 				 sizeof(context));
261 }
262 
263 #if defined(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE)
supported_context_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)264 static void supported_context_cfg_changed(const struct bt_gatt_attr *attr,
265 					  uint16_t value)
266 {
267 	LOG_DBG("attr %p value 0x%04x", attr, value);
268 }
269 #endif /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */
270 
supported_context_get(enum bt_audio_dir dir)271 static uint16_t supported_context_get(enum bt_audio_dir dir)
272 {
273 	switch (dir) {
274 #if defined(CONFIG_BT_PAC_SNK)
275 	case BT_AUDIO_DIR_SINK:
276 		return snk_supported_contexts | BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED;
277 #endif /* CONFIG_BT_PAC_SNK */
278 #if defined(CONFIG_BT_PAC_SRC)
279 	case BT_AUDIO_DIR_SOURCE:
280 		return src_supported_contexts | BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED;
281 #endif /* CONFIG_BT_PAC_SRC */
282 	default:
283 		break;
284 	}
285 
286 	return BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
287 }
288 
supported_context_read(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)289 static ssize_t supported_context_read(struct bt_conn *conn,
290 				      const struct bt_gatt_attr *attr,
291 				      void *buf, uint16_t len, uint16_t offset)
292 {
293 	struct bt_pacs_context context = {
294 		.snk = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SINK)),
295 		.src = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SOURCE)),
296 	};
297 
298 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
299 
300 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &context,
301 				 sizeof(context));
302 }
303 
set_available_contexts(uint16_t contexts,uint16_t * available,uint16_t supported)304 static int set_available_contexts(uint16_t contexts, uint16_t *available,
305 				  uint16_t supported)
306 {
307 	if (contexts & ~supported) {
308 		return -ENOTSUP;
309 	}
310 
311 	if (contexts == *available) {
312 		return 0;
313 	}
314 
315 	*available = contexts;
316 
317 	pacs_set_notify_bit(FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED);
318 	k_work_submit(&deferred_nfy_work);
319 
320 	return 0;
321 }
322 
set_supported_contexts(uint16_t contexts,uint16_t * supported,uint16_t * available)323 static int set_supported_contexts(uint16_t contexts, uint16_t *supported,
324 				  uint16_t *available)
325 {
326 	int err;
327 	uint16_t tmp_supported = *supported;
328 	uint16_t tmp_available = *available;
329 
330 	/* Ensure unspecified is always supported */
331 	contexts |= BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED;
332 
333 	if (*supported == contexts) {
334 		return 0;
335 	}
336 
337 	*supported = contexts;
338 
339 	/* Update available contexts if needed*/
340 	if ((contexts & *available) != *available) {
341 		err = set_available_contexts(contexts & *available, available, contexts);
342 		if (err) {
343 			*available = tmp_available;
344 			*supported = tmp_supported;
345 
346 			return err;
347 		}
348 	}
349 
350 	if (IS_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE)) {
351 		pacs_set_notify_bit(FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED);
352 		k_work_submit(&deferred_nfy_work);
353 	}
354 
355 	return 0;
356 }
357 
358 #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)359 static ssize_t snk_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
360 			void *buf, uint16_t len, uint16_t offset)
361 {
362 	ssize_t ret_val;
363 	int err;
364 
365 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
366 
367 	err = k_sem_take(&read_buf_sem, READ_BUF_SEM_TIMEOUT);
368 	if (err != 0) {
369 		LOG_DBG("Failed to take read_buf_sem: %d", err);
370 
371 		return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES);
372 	}
373 
374 	get_pac_records(&snk_pacs_list, &read_buf);
375 
376 	ret_val = bt_gatt_attr_read(conn, attr, buf, len, offset, read_buf.data,
377 				    read_buf.len);
378 
379 	k_sem_give(&read_buf_sem);
380 
381 	return ret_val;
382 }
383 
384 #if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE)
385 static const struct bt_uuid *pacs_snk_uuid = BT_UUID_PACS_SNK;
386 
snk_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)387 static void snk_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
388 {
389 	LOG_DBG("attr %p value 0x%04x", attr, value);
390 }
391 #endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */
392 #endif /* CONFIG_BT_PAC_SNK */
393 
394 #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)395 static ssize_t snk_loc_read(struct bt_conn *conn,
396 			    const struct bt_gatt_attr *attr, void *buf,
397 			    uint16_t len, uint16_t offset)
398 {
399 	uint32_t location = sys_cpu_to_le32(pacs_snk_location);
400 
401 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
402 
403 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &location,
404 				 sizeof(location));
405 }
406 
407 #if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)
408 static const struct bt_uuid *pacs_snk_loc_uuid = BT_UUID_PACS_SNK_LOC;
409 
snk_loc_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)410 static void snk_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
411 {
412 	LOG_DBG("attr %p value 0x%04x", attr, value);
413 }
414 #endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */
415 
set_snk_location(enum bt_audio_location audio_location)416 static void set_snk_location(enum bt_audio_location audio_location)
417 {
418 	if (audio_location == pacs_snk_location) {
419 		return;
420 	}
421 
422 	pacs_snk_location = audio_location;
423 
424 	if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)) {
425 		pacs_set_notify_bit(FLAG_SINK_AUDIO_LOCATIONS_CHANGED);
426 		k_work_submit(&deferred_nfy_work);
427 	}
428 }
429 #else
set_snk_location(enum bt_audio_location location)430 static void set_snk_location(enum bt_audio_location location)
431 {
432 	return;
433 }
434 #endif /* CONFIG_BT_PAC_SNK_LOC */
435 
436 #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)437 static ssize_t snk_loc_write(struct bt_conn *conn,
438 			     const struct bt_gatt_attr *attr, const void *data,
439 			     uint16_t len, uint16_t offset, uint8_t flags)
440 {
441 	enum bt_audio_location location;
442 
443 	if (offset) {
444 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
445 	}
446 
447 	if (len != sizeof(location)) {
448 		return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
449 	}
450 
451 	location = (enum bt_audio_location)sys_get_le32(data);
452 	if (location > BT_AUDIO_LOCATION_MASK) {
453 		LOG_DBG("Invalid location value: 0x%08X", location);
454 		return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
455 	}
456 
457 	set_snk_location(location);
458 
459 	return len;
460 }
461 #endif /* CONFIG_BT_PAC_SNK_LOC_WRITEABLE */
462 
463 #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)464 static ssize_t src_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
465 			void *buf, uint16_t len, uint16_t offset)
466 {
467 	ssize_t ret_val;
468 	int err;
469 
470 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
471 
472 	err = k_sem_take(&read_buf_sem, READ_BUF_SEM_TIMEOUT);
473 	if (err != 0) {
474 		LOG_DBG("Failed to take read_buf_sem: %d", err);
475 
476 		return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES);
477 	}
478 
479 	get_pac_records(&src_pacs_list, &read_buf);
480 
481 	ret_val = bt_gatt_attr_read(conn, attr, buf, len, offset, read_buf.data,
482 				    read_buf.len);
483 
484 	k_sem_give(&read_buf_sem);
485 
486 	return ret_val;
487 }
488 
489 #if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
490 static const struct bt_uuid *pacs_src_uuid = BT_UUID_PACS_SRC;
491 
src_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)492 static void src_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
493 {
494 	LOG_DBG("attr %p value 0x%04x", attr, value);
495 }
496 #endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
497 #endif /* CONFIG_BT_PAC_SRC */
498 
499 #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)500 static ssize_t src_loc_read(struct bt_conn *conn,
501 			    const struct bt_gatt_attr *attr, void *buf,
502 			    uint16_t len, uint16_t offset)
503 {
504 	uint32_t location = sys_cpu_to_le32(pacs_src_location);
505 
506 	LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset);
507 
508 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &location,
509 				 sizeof(location));
510 }
511 
512 #if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
513 static const struct bt_uuid *pacs_src_loc_uuid = BT_UUID_PACS_SRC_LOC;
514 
src_loc_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)515 static void src_loc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
516 {
517 	LOG_DBG("attr %p value 0x%04x", attr, value);
518 }
519 #endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
520 
set_src_location(enum bt_audio_location audio_location)521 static void set_src_location(enum bt_audio_location audio_location)
522 {
523 	if (audio_location == pacs_src_location) {
524 		return;
525 	}
526 
527 	pacs_src_location = audio_location;
528 
529 	if (IS_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)) {
530 		pacs_set_notify_bit(FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED);
531 		k_work_submit(&deferred_nfy_work);
532 	}
533 }
534 #else
set_src_location(enum bt_audio_location location)535 static void set_src_location(enum bt_audio_location location)
536 {
537 	return;
538 }
539 #endif /* CONFIG_BT_PAC_SRC_LOC */
540 
541 #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)542 static ssize_t src_loc_write(struct bt_conn *conn,
543 			     const struct bt_gatt_attr *attr, const void *data,
544 			     uint16_t len, uint16_t offset, uint8_t flags)
545 {
546 	uint32_t location;
547 
548 	if (offset) {
549 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
550 	}
551 
552 	if (len != sizeof(location)) {
553 		return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
554 	}
555 
556 	location = (enum bt_audio_location)sys_get_le32(data);
557 	if (location > BT_AUDIO_LOCATION_MASK) {
558 		LOG_DBG("Invalid location value: 0x%08X", location);
559 		return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
560 	}
561 
562 	set_src_location(location);
563 
564 	return len;
565 }
566 #endif /* CONFIG_BT_PAC_SRC_LOC_WRITEABLE */
567 
568 
pacs_get(enum bt_audio_dir dir)569 static sys_slist_t *pacs_get(enum bt_audio_dir dir)
570 {
571 	switch (dir) {
572 #if defined(CONFIG_BT_PAC_SNK)
573 	case BT_AUDIO_DIR_SINK:
574 		return &snk_pacs_list;
575 #endif /* CONFIG_BT_PAC_SNK */
576 #if defined(CONFIG_BT_PAC_SRC)
577 	case BT_AUDIO_DIR_SOURCE:
578 		return &src_pacs_list;
579 #endif /* CONFIG_BT_PAC_SRC */
580 	default:
581 		return NULL;
582 	}
583 }
584 
585 #define BT_PACS_SNK_PROP \
586 	BT_GATT_CHRC_READ \
587 	IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
588 #define BT_PAC_SNK(_read) \
589 	BT_AUDIO_CHRC(BT_UUID_PACS_SNK, \
590 		      BT_PACS_SNK_PROP, \
591 		      BT_GATT_PERM_READ_ENCRYPT, \
592 		      _read, NULL, NULL), \
593 	IF_ENABLED(CONFIG_BT_PAC_SNK_NOTIFIABLE, (BT_AUDIO_CCC(snk_cfg_changed),))
594 
595 #define BT_PACS_SNK_LOC_PROP \
596 	BT_GATT_CHRC_READ \
597 	IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_WRITEABLE, (|BT_GATT_CHRC_WRITE)) \
598 	IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
599 
600 #define BT_PACS_SNK_LOC_PERM \
601 	BT_GATT_PERM_READ_ENCRYPT \
602 	IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_WRITEABLE, (|BT_GATT_PERM_WRITE_ENCRYPT))
603 
604 #define BT_PACS_SNK_LOC(_read) \
605 	BT_AUDIO_CHRC(BT_UUID_PACS_SNK_LOC, \
606 		      BT_PACS_SNK_LOC_PROP, \
607 		      BT_PACS_SNK_LOC_PERM, \
608 		      _read, \
609 		      COND_CODE_1(CONFIG_BT_PAC_SNK_LOC_WRITEABLE, (snk_loc_write), (NULL)), \
610 		      NULL), \
611 	IF_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE, (BT_AUDIO_CCC(snk_loc_cfg_changed),))
612 
613 #define BT_PACS_SRC_PROP \
614 	BT_GATT_CHRC_READ \
615 	IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
616 #define BT_PAC_SRC(_read) \
617 	BT_AUDIO_CHRC(BT_UUID_PACS_SRC, \
618 		      BT_PACS_SRC_PROP, \
619 		      BT_GATT_PERM_READ_ENCRYPT, \
620 		      _read, NULL, NULL), \
621 	IF_ENABLED(CONFIG_BT_PAC_SRC_NOTIFIABLE, (BT_AUDIO_CCC(src_cfg_changed),))
622 
623 #define BT_PACS_SRC_LOC_PROP \
624 	BT_GATT_CHRC_READ \
625 	IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_WRITEABLE, (|BT_GATT_CHRC_WRITE)) \
626 	IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
627 
628 #define BT_PACS_SRC_LOC_PERM \
629 	BT_GATT_PERM_READ_ENCRYPT \
630 	IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_WRITEABLE, (|BT_GATT_PERM_WRITE_ENCRYPT))
631 
632 #define BT_PACS_SRC_LOC(_read) \
633 	BT_AUDIO_CHRC(BT_UUID_PACS_SRC_LOC, \
634 		      BT_PACS_SRC_LOC_PROP, \
635 		      BT_PACS_SRC_LOC_PERM, \
636 		      _read, \
637 		      COND_CODE_1(CONFIG_BT_PAC_SRC_LOC_WRITEABLE, (src_loc_write), (NULL)), \
638 		      NULL), \
639 	IF_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE, (BT_AUDIO_CCC(src_loc_cfg_changed),))
640 
641 #define BT_PAC_AVAILABLE_CONTEXT(_read) \
642 	BT_AUDIO_CHRC(BT_UUID_PACS_AVAILABLE_CONTEXT, \
643 		      BT_GATT_CHRC_READ|BT_GATT_CHRC_NOTIFY, \
644 		      BT_GATT_PERM_READ_ENCRYPT, \
645 		      _read, NULL, NULL), \
646 	BT_AUDIO_CCC(available_context_cfg_changed),
647 
648 #define BT_PACS_SUPPORTED_CONTEXT_PROP \
649 	BT_GATT_CHRC_READ \
650 	IF_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE, (|BT_GATT_CHRC_NOTIFY))
651 
652 #define BT_PAC_SUPPORTED_CONTEXT(_read) \
653 	BT_AUDIO_CHRC(BT_UUID_PACS_SUPPORTED_CONTEXT, \
654 		      BT_PACS_SUPPORTED_CONTEXT_PROP, \
655 		      BT_GATT_PERM_READ_ENCRYPT, \
656 		      _read, NULL, NULL), \
657 	IF_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE, \
658 		   (BT_AUDIO_CCC(supported_context_cfg_changed),))
659 
660 BT_GATT_SERVICE_DEFINE(pacs_svc,
661 	BT_GATT_PRIMARY_SERVICE(BT_UUID_PACS),
662 #if defined(CONFIG_BT_PAC_SNK)
663 	BT_PAC_SNK(snk_read)
664 #if defined(CONFIG_BT_PAC_SNK_LOC)
665 	BT_PACS_SNK_LOC(snk_loc_read)
666 #endif /* CONFIG_BT_PAC_SNK_LOC */
667 #endif /* CONFIG_BT_PAC_SNK */
668 #if defined(CONFIG_BT_PAC_SRC)
669 	BT_PAC_SRC(src_read)
670 #if defined(CONFIG_BT_PAC_SRC_LOC)
671 	BT_PACS_SRC_LOC(src_loc_read)
672 #endif /* CONFIG_BT_PAC_SRC_LOC */
673 #endif /* CONFIG_BT_PAC_SRC */
674 	BT_PAC_AVAILABLE_CONTEXT(available_contexts_read)
675 	BT_PAC_SUPPORTED_CONTEXT(supported_context_read)
676 );
677 
678 #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)679 static int pac_notify_loc(struct bt_conn *conn, enum bt_audio_dir dir)
680 {
681 	uint32_t location_le;
682 	int err;
683 	const struct bt_uuid *uuid;
684 
685 	switch (dir) {
686 #if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)
687 	case BT_AUDIO_DIR_SINK:
688 		location_le = sys_cpu_to_le32(pacs_snk_location);
689 		uuid = pacs_snk_loc_uuid;
690 		break;
691 #endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */
692 #if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
693 	case BT_AUDIO_DIR_SOURCE:
694 		location_le = sys_cpu_to_le32(pacs_src_location);
695 		uuid = pacs_src_loc_uuid;
696 		break;
697 #endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
698 	default:
699 		return -EINVAL;
700 	}
701 
702 	err = pacs_gatt_notify(conn, uuid, pacs_svc.attrs, &location_le, sizeof(location_le));
703 	if (err != 0 && err != -ENOTCONN) {
704 		LOG_WRN("PACS notify_loc failed: %d", err);
705 		return err;
706 	}
707 
708 	return 0;
709 }
710 #endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE || CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
711 
712 #if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE) || defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
pac_notify(struct bt_conn * conn,enum bt_audio_dir dir)713 static int pac_notify(struct bt_conn *conn, enum bt_audio_dir dir)
714 {
715 	int err = 0;
716 	sys_slist_t *pacs;
717 	const struct bt_uuid *uuid;
718 
719 	switch (dir) {
720 #if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE)
721 	case BT_AUDIO_DIR_SINK:
722 		uuid = pacs_snk_uuid;
723 		break;
724 #endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */
725 #if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
726 	case BT_AUDIO_DIR_SOURCE:
727 		uuid = pacs_src_uuid;
728 		break;
729 #endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
730 	default:
731 		return -EINVAL;
732 	}
733 
734 	err = k_sem_take(&read_buf_sem, K_NO_WAIT);
735 	if (err != 0) {
736 		LOG_DBG("Failed to take read_buf_sem: %d", err);
737 
738 		return err;
739 	}
740 
741 	pacs = pacs_get(dir);
742 	__ASSERT(pacs, "Failed to get pacs.\n");
743 	get_pac_records(pacs, &read_buf);
744 
745 	err = pacs_gatt_notify(conn, uuid, pacs_svc.attrs,
746 			       read_buf.data, read_buf.len);
747 	if (err != 0 && err != -ENOTCONN) {
748 		LOG_WRN("PACS notify failed: %d", err);
749 	}
750 
751 	k_sem_give(&read_buf_sem);
752 
753 	if (err == -ENOTCONN) {
754 		return 0;
755 	} else {
756 		return 0;
757 	}
758 }
759 #endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE || CONFIG_BT_PAC_SRC_NOTIFIABLE */
760 
available_contexts_notify(struct bt_conn * conn)761 static int available_contexts_notify(struct bt_conn *conn)
762 {
763 	struct bt_pacs_context context = {
764 		.snk = sys_cpu_to_le16(
765 			pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK)),
766 		.src = sys_cpu_to_le16(
767 			pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE)),
768 	};
769 	int err;
770 
771 	err = pacs_gatt_notify(conn, BT_UUID_PACS_AVAILABLE_CONTEXT, pacs_svc.attrs,
772 				  &context, sizeof(context));
773 	if (err != 0 && err != -ENOTCONN) {
774 		LOG_WRN("Available Audio Contexts notify failed: %d", err);
775 		return err;
776 	}
777 
778 	return 0;
779 }
780 
supported_contexts_notify(struct bt_conn * conn)781 static int supported_contexts_notify(struct bt_conn *conn)
782 {
783 	struct bt_pacs_context context = {
784 		.snk = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SINK)),
785 		.src = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SOURCE)),
786 	};
787 	int err;
788 
789 	err = pacs_gatt_notify(conn, BT_UUID_PACS_SUPPORTED_CONTEXT, pacs_svc.attrs,
790 				  &context, sizeof(context));
791 	if (err != 0 && err != -ENOTCONN) {
792 		LOG_WRN("Supported Audio Contexts notify failed: %d", err);
793 
794 		return err;
795 	}
796 	return 0;
797 }
798 
pacs_gatt_notify_complete_cb(struct bt_conn * conn,void * user_data)799 void pacs_gatt_notify_complete_cb(struct bt_conn *conn, void *user_data)
800 {
801 	/* Notification done, clear bit and reschedule work */
802 	atomic_clear(&notify_rdy);
803 	k_work_submit(&deferred_nfy_work);
804 }
805 
pacs_gatt_notify(struct bt_conn * conn,const struct bt_uuid * uuid,const struct bt_gatt_attr * attr,const void * data,uint16_t len)806 static int pacs_gatt_notify(struct bt_conn *conn,
807 			    const struct bt_uuid *uuid,
808 			    const struct bt_gatt_attr *attr,
809 			    const void *data,
810 			    uint16_t len)
811 {
812 	int err;
813 	struct bt_gatt_notify_params params;
814 
815 	memset(&params, 0, sizeof(params));
816 	params.uuid = uuid;
817 	params.attr = attr;
818 	params.data = data;
819 	params.len  = len;
820 	params.func = pacs_gatt_notify_complete_cb;
821 
822 	/* Mark notification in progress */
823 	atomic_set(&notify_rdy, 1);
824 
825 	err = bt_gatt_notify_cb(conn, &params);
826 	if (err != 0) {
827 		atomic_clear(&notify_rdy);
828 	}
829 
830 	if (err && err != -ENOTCONN) {
831 		return err;
832 	}
833 
834 	return 0;
835 }
836 
notify_cb(struct bt_conn * conn,void * data)837 static void notify_cb(struct bt_conn *conn, void *data)
838 {
839 	struct pacs_client *client;
840 	struct bt_conn_info info;
841 	int err = 0;
842 
843 	LOG_DBG("");
844 
845 	err = bt_conn_get_info(conn, &info);
846 	if (err != 0) {
847 		LOG_ERR("Failed to get conn info: %d", err);
848 		return;
849 	}
850 
851 	if (info.state != BT_CONN_STATE_CONNECTED) {
852 		/* Not connected */
853 		return;
854 	}
855 
856 	client = client_lookup_conn(conn);
857 	if (client == NULL) {
858 		return;
859 	}
860 
861 	/* Check if we have unverified notifications in progress */
862 	if (atomic_get(&notify_rdy)) {
863 		return;
864 	}
865 
866 #if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE)
867 	if (atomic_test_bit(client->flags, FLAG_SINK_PAC_CHANGED)) {
868 		LOG_DBG("Notifying Sink PAC");
869 		err = pac_notify(conn, BT_AUDIO_DIR_SINK);
870 		if (!err) {
871 			atomic_clear_bit(client->flags, FLAG_SINK_PAC_CHANGED);
872 		}
873 	}
874 #endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */
875 
876 #if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE)
877 	if (atomic_test_bit(client->flags, FLAG_SINK_AUDIO_LOCATIONS_CHANGED)) {
878 		LOG_DBG("Notifying Sink Audio Location");
879 		err = pac_notify_loc(conn, BT_AUDIO_DIR_SINK);
880 		if (!err) {
881 			atomic_clear_bit(client->flags, FLAG_SINK_AUDIO_LOCATIONS_CHANGED);
882 		}
883 	}
884 #endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */
885 
886 #if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
887 	if (atomic_test_bit(client->flags, FLAG_SOURCE_PAC_CHANGED)) {
888 		LOG_DBG("Notifying Source PAC");
889 		err = pac_notify(conn, BT_AUDIO_DIR_SOURCE);
890 		if (!err) {
891 			atomic_clear_bit(client->flags, FLAG_SOURCE_PAC_CHANGED);
892 		}
893 	}
894 #endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
895 
896 #if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE)
897 	if (atomic_test_and_clear_bit(client->flags, FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED)) {
898 		LOG_DBG("Notifying Source Audio Location");
899 		err = pac_notify_loc(conn, BT_AUDIO_DIR_SOURCE);
900 		if (!err) {
901 			atomic_clear_bit(client->flags, FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED);
902 		}
903 	}
904 #endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */
905 
906 	if (atomic_test_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED)) {
907 		LOG_DBG("Notifying Available Contexts");
908 		err = available_contexts_notify(conn);
909 		if (!err) {
910 			atomic_clear_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED);
911 		}
912 	}
913 
914 	if (IS_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE) &&
915 	    atomic_test_bit(client->flags, FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED)) {
916 		LOG_DBG("Notifying Supported Contexts");
917 		err = supported_contexts_notify(conn);
918 		if (!err) {
919 			atomic_clear_bit(client->flags, FLAG_SUPPORTED_AUDIO_CONTEXT_CHANGED);
920 		}
921 	}
922 }
923 
deferred_nfy_work_handler(struct k_work * work)924 static void deferred_nfy_work_handler(struct k_work *work)
925 {
926 	bt_conn_foreach(BT_CONN_TYPE_LE, notify_cb, NULL);
927 }
928 
pacs_auth_pairing_complete(struct bt_conn * conn,bool bonded)929 static void pacs_auth_pairing_complete(struct bt_conn *conn, bool bonded)
930 {
931 	LOG_DBG("%s paired (%sbonded)", bt_addr_le_str(bt_conn_get_dst(conn)),
932 		bonded ? "" : "not ");
933 
934 	if (!bonded) {
935 		return;
936 	}
937 
938 	/* Check if already in list, and do nothing if it is */
939 	for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) {
940 		if (atomic_test_bit(clients[i].flags, FLAG_ACTIVE) &&
941 		    bt_addr_le_eq(bt_conn_get_dst(conn), &clients[i].addr)) {
942 			return;
943 		}
944 	}
945 
946 	/* Else add the device */
947 	for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) {
948 		if (!atomic_test_bit(clients[i].flags, FLAG_ACTIVE)) {
949 			atomic_set_bit(clients[i].flags, FLAG_ACTIVE);
950 			memcpy(&clients[i].addr, bt_conn_get_dst(conn), sizeof(bt_addr_le_t));
951 
952 			/* Send out all pending notifications */
953 			k_work_submit(&deferred_nfy_work);
954 			return;
955 		}
956 	}
957 }
958 
pacs_bond_deleted(uint8_t id,const bt_addr_le_t * peer)959 static void pacs_bond_deleted(uint8_t id, const bt_addr_le_t *peer)
960 {
961 	/* Find the device entry to delete */
962 	for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) {
963 		/* Check if match, and if active, if so, reset */
964 		if (atomic_test_bit(clients[i].flags, FLAG_ACTIVE) &&
965 		    bt_addr_le_eq(peer, &clients[i].addr)) {
966 			for (size_t j = 0U; j < FLAG_NUM; j++) {
967 				atomic_clear_bit(clients[i].flags, j);
968 			}
969 			(void)memset(&clients[i].addr, 0, sizeof(bt_addr_le_t));
970 			return;
971 		}
972 	}
973 }
974 
pacs_security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)975 static void pacs_security_changed(struct bt_conn *conn, bt_security_t level,
976 				  enum bt_security_err err)
977 {
978 	LOG_DBG("%s changed security level to %d", bt_addr_le_str(bt_conn_get_dst(conn)), level);
979 
980 	if (err != 0 || conn->encrypt == 0) {
981 		return;
982 	}
983 
984 	if (!bt_addr_le_is_bonded(conn->id, &conn->le.dst)) {
985 		return;
986 	}
987 
988 	for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) {
989 		for (size_t j = 0U; j < FLAG_NUM; j++) {
990 			if (atomic_test_bit(clients[i].flags, j)) {
991 
992 				/**
993 				 *  It's enough that one flag is set, as the defer work will go
994 				 * through all notifiable characteristics
995 				 */
996 				k_work_submit(&deferred_nfy_work);
997 				return;
998 			}
999 		}
1000 	}
1001 }
1002 
pacs_disconnected(struct bt_conn * conn,uint8_t reason)1003 static void pacs_disconnected(struct bt_conn *conn, uint8_t reason)
1004 {
1005 	struct pacs_client *client;
1006 
1007 	client = client_lookup_conn(conn);
1008 	if (client == NULL) {
1009 		return;
1010 	}
1011 
1012 #if defined(CONFIG_BT_PAC_SNK)
1013 	if (client->snk_available_contexts != NULL) {
1014 		uint16_t old = POINTER_TO_UINT(client->snk_available_contexts);
1015 		uint16_t new;
1016 
1017 		client->snk_available_contexts = NULL;
1018 		new = pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK);
1019 
1020 		atomic_set_bit_to(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED, old != new);
1021 	}
1022 #endif /* CONFIG_BT_PAC_SNK */
1023 
1024 #if defined(CONFIG_BT_PAC_SRC)
1025 	if (client->src_available_contexts != NULL) {
1026 		uint16_t old = POINTER_TO_UINT(client->src_available_contexts);
1027 		uint16_t new;
1028 
1029 		client->src_available_contexts = NULL;
1030 		new = pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE);
1031 
1032 		atomic_set_bit_to(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED, old != new);
1033 	}
1034 #endif /* CONFIG_BT_PAC_SRC */
1035 }
1036 
1037 static struct bt_conn_cb conn_callbacks = {
1038 	.security_changed = pacs_security_changed,
1039 	.disconnected = pacs_disconnected,
1040 };
1041 
1042 static struct bt_conn_auth_info_cb auth_callbacks = {
1043 	.pairing_complete = pacs_auth_pairing_complete,
1044 	.bond_deleted = pacs_bond_deleted
1045 };
1046 
bt_pacs_cap_foreach(enum bt_audio_dir dir,bt_pacs_cap_foreach_func_t func,void * user_data)1047 void bt_pacs_cap_foreach(enum bt_audio_dir dir, bt_pacs_cap_foreach_func_t func, void *user_data)
1048 {
1049 	sys_slist_t *pac;
1050 
1051 	CHECKIF(func == NULL) {
1052 		LOG_ERR("func is NULL");
1053 		return;
1054 	}
1055 
1056 	pac = pacs_get(dir);
1057 	if (!pac) {
1058 		return;
1059 	}
1060 
1061 	foreach_cap(pac, func, user_data);
1062 }
1063 
add_bonded_addr_to_client_list(const struct bt_bond_info * info,void * data)1064 static void add_bonded_addr_to_client_list(const struct bt_bond_info *info, void *data)
1065 {
1066 	for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) {
1067 		/* Check if device is registered, it not, add it */
1068 		if (!atomic_test_bit(clients[i].flags, FLAG_ACTIVE)) {
1069 			char addr_str[BT_ADDR_LE_STR_LEN];
1070 
1071 			atomic_set_bit(clients[i].flags, FLAG_ACTIVE);
1072 			memcpy(&clients[i].addr, &info->addr, sizeof(bt_addr_le_t));
1073 			bt_addr_le_to_str(&clients[i].addr, addr_str, sizeof(addr_str));
1074 			LOG_DBG("Added %s to bonded list\n", addr_str);
1075 			return;
1076 		}
1077 	}
1078 }
1079 
1080 /* Register Audio Capability */
bt_pacs_cap_register(enum bt_audio_dir dir,struct bt_pacs_cap * cap)1081 int bt_pacs_cap_register(enum bt_audio_dir dir, struct bt_pacs_cap *cap)
1082 {
1083 	const struct bt_audio_codec_cap *codec_cap;
1084 	static bool callbacks_registered;
1085 	sys_slist_t *pac;
1086 
1087 	if (!cap || !cap->codec_cap) {
1088 		return -EINVAL;
1089 	}
1090 
1091 	codec_cap = cap->codec_cap;
1092 
1093 	pac = pacs_get(dir);
1094 	if (!pac) {
1095 		return -EINVAL;
1096 	}
1097 
1098 	/* Restore bonding list */
1099 	bt_foreach_bond(BT_ID_DEFAULT, add_bonded_addr_to_client_list, NULL);
1100 
1101 	LOG_DBG("cap %p dir %s codec_cap id 0x%02x codec_cap cid 0x%04x codec_cap vid 0x%04x", cap,
1102 		bt_audio_dir_str(dir), codec_cap->id, codec_cap->cid, codec_cap->vid);
1103 
1104 	sys_slist_append(pac, &cap->_node);
1105 
1106 	if (!callbacks_registered) {
1107 		bt_conn_cb_register(&conn_callbacks);
1108 		bt_conn_auth_info_cb_register(&auth_callbacks);
1109 
1110 		callbacks_registered = true;
1111 	}
1112 
1113 	if (IS_ENABLED(CONFIG_BT_PAC_SNK_NOTIFIABLE) && dir == BT_AUDIO_DIR_SINK) {
1114 		pacs_set_notify_bit(FLAG_SINK_PAC_CHANGED);
1115 		k_work_submit(&deferred_nfy_work);
1116 	}
1117 
1118 	if (IS_ENABLED(CONFIG_BT_PAC_SRC_NOTIFIABLE) && dir == BT_AUDIO_DIR_SOURCE) {
1119 		pacs_set_notify_bit(FLAG_SOURCE_PAC_CHANGED);
1120 		k_work_submit(&deferred_nfy_work);
1121 	}
1122 
1123 	return 0;
1124 }
1125 
1126 /* Unregister Audio Capability */
bt_pacs_cap_unregister(enum bt_audio_dir dir,struct bt_pacs_cap * cap)1127 int bt_pacs_cap_unregister(enum bt_audio_dir dir, struct bt_pacs_cap *cap)
1128 {
1129 	sys_slist_t *pac;
1130 
1131 	if (!cap) {
1132 		return -EINVAL;
1133 	}
1134 
1135 	pac = pacs_get(dir);
1136 	if (!pac) {
1137 		return -EINVAL;
1138 	}
1139 
1140 	LOG_DBG("cap %p dir %s", cap, bt_audio_dir_str(dir));
1141 
1142 	if (!sys_slist_find_and_remove(pac, &cap->_node)) {
1143 		return -ENOENT;
1144 	}
1145 
1146 	switch (dir) {
1147 #if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE)
1148 	case BT_AUDIO_DIR_SINK:
1149 		pacs_set_notify_bit(FLAG_SINK_PAC_CHANGED);
1150 		k_work_submit(&deferred_nfy_work);
1151 		break;
1152 #endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE) */
1153 #if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE)
1154 	case BT_AUDIO_DIR_SOURCE:
1155 		pacs_set_notify_bit(FLAG_SOURCE_PAC_CHANGED);
1156 		k_work_submit(&deferred_nfy_work);
1157 		break;
1158 #endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */
1159 	default:
1160 		return -EINVAL;
1161 	}
1162 
1163 	return 0;
1164 }
1165 
bt_pacs_set_location(enum bt_audio_dir dir,enum bt_audio_location location)1166 int bt_pacs_set_location(enum bt_audio_dir dir, enum bt_audio_location location)
1167 {
1168 	switch (dir) {
1169 	case BT_AUDIO_DIR_SINK:
1170 		set_snk_location(location);
1171 		break;
1172 	case BT_AUDIO_DIR_SOURCE:
1173 		set_src_location(location);
1174 		break;
1175 	default:
1176 		return -EINVAL;
1177 	}
1178 
1179 	return 0;
1180 }
1181 
bt_pacs_set_available_contexts(enum bt_audio_dir dir,enum bt_audio_context contexts)1182 int bt_pacs_set_available_contexts(enum bt_audio_dir dir, enum bt_audio_context contexts)
1183 {
1184 	switch (dir) {
1185 	case BT_AUDIO_DIR_SINK:
1186 		return set_available_contexts(contexts, &snk_available_contexts,
1187 					      supported_context_get(dir));
1188 	case BT_AUDIO_DIR_SOURCE:
1189 		return set_available_contexts(contexts, &src_available_contexts,
1190 					      supported_context_get(dir));
1191 	}
1192 
1193 	return -EINVAL;
1194 }
1195 
bt_pacs_conn_set_available_contexts_for_conn(struct bt_conn * conn,enum bt_audio_dir dir,enum bt_audio_context * contexts)1196 int bt_pacs_conn_set_available_contexts_for_conn(struct bt_conn *conn, enum bt_audio_dir dir,
1197 						 enum bt_audio_context *contexts)
1198 {
1199 	enum bt_audio_context old = pacs_get_available_contexts_for_conn(conn, dir);
1200 	struct bt_conn_info info = { 0 };
1201 	struct pacs_client *client;
1202 	int err;
1203 
1204 	client = client_lookup_conn(conn);
1205 	if (client == NULL) {
1206 		return -ENOENT;
1207 	}
1208 
1209 	err = bt_conn_get_info(conn, &info);
1210 	if (err < 0) {
1211 		LOG_ERR("Could not get conn info: %d", err);
1212 		return err;
1213 	}
1214 
1215 	switch (dir) {
1216 #if defined(CONFIG_BT_PAC_SNK)
1217 	case BT_AUDIO_DIR_SINK:
1218 		if (contexts != NULL) {
1219 			client->snk_available_contexts = UINT_TO_POINTER(*contexts);
1220 		} else {
1221 			client->snk_available_contexts = NULL;
1222 		}
1223 
1224 		break;
1225 #endif /* CONFIG_BT_PAC_SNK */
1226 #if defined(CONFIG_BT_PAC_SRC)
1227 	case BT_AUDIO_DIR_SOURCE:
1228 		if (contexts != NULL) {
1229 			client->src_available_contexts = UINT_TO_POINTER(*contexts);
1230 		} else {
1231 			client->src_available_contexts = NULL;
1232 		}
1233 
1234 		break;
1235 #endif /* CONFIG_BT_PAC_SRC */
1236 	default:
1237 		return -EINVAL;
1238 	}
1239 
1240 	if (pacs_get_available_contexts_for_conn(conn, dir) == old) {
1241 		/* No change. Skip notification */
1242 		return 0;
1243 	}
1244 
1245 	atomic_set_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED);
1246 
1247 	/* Send notification on encrypted link only */
1248 	if (info.security.level > BT_SECURITY_L1) {
1249 		k_work_submit(&deferred_nfy_work);
1250 	}
1251 
1252 	return 0;
1253 }
1254 
bt_pacs_set_supported_contexts(enum bt_audio_dir dir,enum bt_audio_context contexts)1255 int bt_pacs_set_supported_contexts(enum bt_audio_dir dir, enum bt_audio_context contexts)
1256 {
1257 	uint16_t *supported_contexts = NULL;
1258 	uint16_t *available_contexts = NULL;
1259 
1260 	switch (dir) {
1261 	case BT_AUDIO_DIR_SINK:
1262 #if defined(CONFIG_BT_PAC_SNK)
1263 		supported_contexts = &snk_supported_contexts;
1264 		available_contexts = &snk_available_contexts;
1265 		break;
1266 #endif /* CONFIG_BT_PAC_SNK */
1267 		return -ENOTSUP;
1268 	case BT_AUDIO_DIR_SOURCE:
1269 #if defined(CONFIG_BT_PAC_SRC)
1270 		supported_contexts = &src_supported_contexts;
1271 		available_contexts = &src_available_contexts;
1272 		break;
1273 #endif /* CONFIG_BT_PAC_SRC */
1274 		return -ENOTSUP;
1275 	default:
1276 		return -EINVAL;
1277 	}
1278 
1279 	if (IS_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE) || *supported_contexts == 0) {
1280 		return set_supported_contexts(contexts, supported_contexts, available_contexts);
1281 	}
1282 
1283 	return -EALREADY;
1284 }
1285 
bt_pacs_get_available_contexts(enum bt_audio_dir dir)1286 enum bt_audio_context bt_pacs_get_available_contexts(enum bt_audio_dir dir)
1287 {
1288 	switch (dir) {
1289 	case BT_AUDIO_DIR_SINK:
1290 		return snk_available_contexts;
1291 	case BT_AUDIO_DIR_SOURCE:
1292 		return src_available_contexts;
1293 	}
1294 
1295 	return BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
1296 }
1297 
bt_pacs_get_available_contexts_for_conn(struct bt_conn * conn,enum bt_audio_dir dir)1298 enum bt_audio_context bt_pacs_get_available_contexts_for_conn(struct bt_conn *conn,
1299 							      enum bt_audio_dir dir)
1300 {
1301 	CHECKIF(conn == NULL) {
1302 		LOG_ERR("NULL conn");
1303 		return BT_AUDIO_CONTEXT_TYPE_PROHIBITED;
1304 	}
1305 
1306 	return pacs_get_available_contexts_for_conn(conn, dir);
1307 }
1308