1 /* Bluetooth Coordinated Set Identification Client
2  *
3  * Copyright (c) 2020 Bose Corporation
4  * Copyright (c) 2021-2024 Nordic Semiconductor ASA
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  * csip_set_coordinator should be used in the following way
9  *  1) Find and connect to a set device
10  *  2) Do discovery
11  *  3) read values (always SIRK, size, lock and rank if possible)
12  *  4) Discover other set members if applicable
13  *  5) Connect and bond with each set member
14  *  6) Do discovery of each member
15  *  7) Read rank for each set member
16  *  8) Lock all members based on rank if possible
17  *  9) Do whatever is needed during lock
18  * 10) Unlock all members
19  */
20 
21 #include <errno.h>
22 #include <stdbool.h>
23 #include <stddef.h>
24 #include <stdint.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include <zephyr/autoconf.h>
29 #include <zephyr/bluetooth/att.h>
30 #include <zephyr/bluetooth/audio/csip.h>
31 #include <zephyr/bluetooth/bluetooth.h>
32 #include <zephyr/bluetooth/conn.h>
33 #include <zephyr/bluetooth/gap.h>
34 #include <zephyr/bluetooth/gatt.h>
35 #include <zephyr/bluetooth/buf.h>
36 #include <zephyr/bluetooth/uuid.h>
37 #include <zephyr/device.h>
38 #include <zephyr/init.h>
39 #include <zephyr/kernel.h>
40 #include <zephyr/logging/log.h>
41 #include <zephyr/sys/__assert.h>
42 #include <zephyr/sys/atomic.h>
43 #include <zephyr/sys/slist.h>
44 #include <zephyr/sys/util.h>
45 #include <zephyr/sys/util_macro.h>
46 #include <zephyr/types.h>
47 #include <zephyr/sys/check.h>
48 #include <zephyr/sys/byteorder.h>
49 
50 #include "csip_crypto.h"
51 #include "csip_internal.h"
52 #include "common/bt_str.h"
53 #include "host/conn_internal.h"
54 #include "host/keys.h"
55 
56 LOG_MODULE_REGISTER(bt_csip_set_coordinator, CONFIG_BT_CSIP_SET_COORDINATOR_LOG_LEVEL);
57 
58 static struct active_members {
59 	struct bt_csip_set_coordinator_set_member *members[CONFIG_BT_MAX_CONN];
60 	struct bt_csip_set_coordinator_set_info info;
61 	uint8_t members_count;
62 	uint8_t members_handled;
63 	uint8_t members_restored;
64 	bool in_progress;
65 
66 	bt_csip_set_coordinator_ordered_access_t oap_cb;
67 } active;
68 
69 enum set_coordinator_flag {
70 	SET_COORDINATOR_FLAG_BUSY,
71 
72 	SET_COORDINATOR_FLAG_NUM_FLAGS, /* keep as last */
73 };
74 
75 struct bt_csip_set_coordinator_inst {
76 	uint8_t inst_count;
77 	uint8_t gatt_write_buf[1];
78 
79 	struct bt_csip_set_coordinator_svc_inst
80 		svc_insts[CONFIG_BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES];
81 	struct bt_csip_set_coordinator_set_member set_member;
82 	struct bt_conn *conn;
83 	struct bt_csip_set_coordinator_svc_inst *cur_inst;
84 	struct bt_gatt_discover_params discover_params;
85 	struct bt_gatt_read_params read_params;
86 	struct bt_gatt_write_params write_params;
87 
88 	ATOMIC_DEFINE(flags, SET_COORDINATOR_FLAG_NUM_FLAGS);
89 };
90 
91 static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0);
92 
93 static sys_slist_t csip_set_coordinator_cbs = SYS_SLIST_STATIC_INIT(&csip_set_coordinator_cbs);
94 static struct bt_csip_set_coordinator_inst client_insts[CONFIG_BT_MAX_CONN];
95 
96 static int read_sirk(struct bt_csip_set_coordinator_svc_inst *svc_inst);
97 static int csip_set_coordinator_read_set_size(struct bt_conn *conn,
98 					      uint8_t inst_idx,
99 					      bt_gatt_read_func_t cb);
100 static int csip_set_coordinator_read_set_lock(struct bt_csip_set_coordinator_svc_inst *svc_inst);
101 
102 static uint8_t csip_set_coordinator_discover_insts_read_sirk_cb(struct bt_conn *conn, uint8_t err,
103 								struct bt_gatt_read_params *params,
104 								const void *data, uint16_t length);
105 static void discover_insts_resume(struct bt_conn *conn, uint16_t sirk_handle,
106 				 uint16_t size_handle, uint16_t rank_handle);
107 
active_members_reset(void)108 static void active_members_reset(void)
109 {
110 	for (size_t i = 0U; i < active.members_count; i++) {
111 		const struct bt_csip_set_coordinator_set_member *member = active.members[i];
112 		struct bt_csip_set_coordinator_inst *client =
113 			CONTAINER_OF(member, struct bt_csip_set_coordinator_inst, set_member);
114 
115 		atomic_clear_bit(client->flags, SET_COORDINATOR_FLAG_BUSY);
116 	}
117 
118 	(void)memset(&active, 0, sizeof(active));
119 }
120 
lookup_instance_by_handle(struct bt_conn * conn,uint16_t handle)121 static struct bt_csip_set_coordinator_svc_inst *lookup_instance_by_handle(struct bt_conn *conn,
122 						 uint16_t handle)
123 {
124 	uint8_t conn_index;
125 	struct bt_csip_set_coordinator_inst *client;
126 
127 	__ASSERT(conn, "NULL conn");
128 	__ASSERT(handle > 0, "Handle cannot be 0");
129 
130 	conn_index = bt_conn_index(conn);
131 	client = &client_insts[conn_index];
132 
133 	for (int i = 0; i < ARRAY_SIZE(client->svc_insts); i++) {
134 		if (client->svc_insts[i].start_handle <= handle &&
135 		    client->svc_insts[i].end_handle >= handle) {
136 			return &client->svc_insts[i];
137 		}
138 	}
139 
140 	return NULL;
141 }
142 
bt_csip_set_coordinator_lookup_instance_by_index(const struct bt_conn * conn,uint8_t idx)143 struct bt_csip_set_coordinator_svc_inst *bt_csip_set_coordinator_lookup_instance_by_index
144 	(const struct bt_conn *conn, uint8_t idx)
145 {
146 	uint8_t conn_index;
147 	struct bt_csip_set_coordinator_inst *client;
148 
149 	__ASSERT(conn, "NULL conn");
150 	__ASSERT(idx < CONFIG_BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES,
151 		 "Index shall be less than maximum number of instances %u (was %u)",
152 		 CONFIG_BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES, idx);
153 
154 	conn_index = bt_conn_index(conn);
155 	client = &client_insts[conn_index];
156 	return &client->svc_insts[idx];
157 }
158 
lookup_instance_by_set_info(const struct bt_csip_set_coordinator_set_member * member,const struct bt_csip_set_coordinator_set_info * set_info)159 static struct bt_csip_set_coordinator_svc_inst *lookup_instance_by_set_info(
160 	const struct bt_csip_set_coordinator_set_member *member,
161 	const struct bt_csip_set_coordinator_set_info *set_info)
162 {
163 	struct bt_csip_set_coordinator_inst *inst =
164 		CONTAINER_OF(member, struct bt_csip_set_coordinator_inst, set_member);
165 
166 	for (int i = 0; i < ARRAY_SIZE(member->insts); i++) {
167 		const struct bt_csip_set_coordinator_set_info *member_set_info;
168 
169 		member_set_info = &member->insts[i].info;
170 		if (member_set_info->set_size == set_info->set_size &&
171 		    memcmp(member_set_info->sirk, set_info->sirk, sizeof(set_info->sirk)) == 0) {
172 			return bt_csip_set_coordinator_lookup_instance_by_index(inst->conn, i);
173 		}
174 	}
175 
176 	return NULL;
177 }
178 
get_next_active_instance(void)179 static struct bt_csip_set_coordinator_svc_inst *get_next_active_instance(void)
180 {
181 	struct bt_csip_set_coordinator_set_member *member;
182 	struct bt_csip_set_coordinator_svc_inst *svc_inst;
183 
184 	member = active.members[active.members_handled];
185 
186 	svc_inst = lookup_instance_by_set_info(member, &active.info);
187 	if (svc_inst == NULL) {
188 		LOG_DBG("Failed to lookup instance by set_info");
189 	}
190 
191 	return svc_inst;
192 }
193 
member_rank_compare_asc(const void * m1,const void * m2)194 static int member_rank_compare_asc(const void *m1, const void *m2)
195 {
196 	const struct bt_csip_set_coordinator_set_member *member_1 =
197 		*(const struct bt_csip_set_coordinator_set_member **)m1;
198 	const struct bt_csip_set_coordinator_set_member *member_2 =
199 		*(const struct bt_csip_set_coordinator_set_member **)m2;
200 	struct bt_csip_set_coordinator_svc_inst *svc_inst_1;
201 	struct bt_csip_set_coordinator_svc_inst *svc_inst_2;
202 
203 	svc_inst_1 = lookup_instance_by_set_info(member_1, &active.info);
204 	svc_inst_2 = lookup_instance_by_set_info(member_2, &active.info);
205 
206 	if (svc_inst_1 == NULL) {
207 		LOG_ERR("svc_inst_1 was NULL for member %p", member_1);
208 		return 0;
209 	}
210 
211 	if (svc_inst_2 == NULL) {
212 		LOG_ERR("svc_inst_2 was NULL for member %p", member_2);
213 		return 0;
214 	}
215 
216 	return svc_inst_1->set_info->rank - svc_inst_2->set_info->rank;
217 }
218 
member_rank_compare_desc(const void * m1,const void * m2)219 static int member_rank_compare_desc(const void *m1, const void *m2)
220 {
221 	/* If we call the "compare ascending" function with the members
222 	 * reversed, it will work as a descending comparison
223 	 */
224 	return member_rank_compare_asc(m2, m1);
225 }
226 
active_members_store_ordered(const struct bt_csip_set_coordinator_set_member * members[],size_t count,const struct bt_csip_set_coordinator_set_info * info,bool ascending)227 static void active_members_store_ordered(const struct bt_csip_set_coordinator_set_member *members[],
228 					 size_t count,
229 					 const struct bt_csip_set_coordinator_set_info *info,
230 					 bool ascending)
231 {
232 	(void)memcpy(active.members, members, count * sizeof(members[0U]));
233 	active.members_count = count;
234 	memcpy(&active.info, info, sizeof(active.info));
235 
236 	if (count > 1U && CONFIG_BT_MAX_CONN > 1) {
237 		qsort(active.members, count, sizeof(members[0U]),
238 		ascending ? member_rank_compare_asc : member_rank_compare_desc);
239 
240 #if defined(CONFIG_ASSERT)
241 		for (size_t i = 1U; i < count; i++) {
242 			const struct bt_csip_set_coordinator_svc_inst *svc_inst_1 =
243 				lookup_instance_by_set_info(active.members[i - 1U], info);
244 			const struct bt_csip_set_coordinator_svc_inst *svc_inst_2 =
245 				lookup_instance_by_set_info(active.members[i], info);
246 			const uint8_t rank_1 = svc_inst_1->set_info->rank;
247 			const uint8_t rank_2 = svc_inst_2->set_info->rank;
248 
249 			if (ascending) {
250 				__ASSERT(rank_1 <= rank_2,
251 					 "Members not sorted by ascending rank %u - %u", rank_1,
252 					 rank_2);
253 			} else {
254 				__ASSERT(rank_1 >= rank_2,
255 					 "Members not sorted by descending rank %u - %u", rank_1,
256 					 rank_2);
257 			}
258 		}
259 #endif /* CONFIG_ASSERT */
260 	}
261 }
262 
sirk_decrypt(struct bt_conn * conn,const uint8_t * enc_sirk,uint8_t * out_sirk)263 static int sirk_decrypt(struct bt_conn *conn,
264 			const uint8_t *enc_sirk,
265 			uint8_t *out_sirk)
266 {
267 	int err;
268 	const uint8_t *k;
269 
270 	if (IS_ENABLED(CONFIG_BT_CSIP_SET_COORDINATOR_TEST_SAMPLE_DATA)) {
271 		/* test_k is from the sample data from A.2 in the CSIS spec */
272 		static const uint8_t test_k[] = {
273 			/* Sample data is in big-endian, we need it in little-endian. */
274 			REVERSE_ARGS(0x67, 0x6e, 0x1b, 0x9b,
275 				     0xd4, 0x48, 0x69, 0x6f,
276 				     0x06, 0x1e, 0xc6, 0x22,
277 				     0x3c, 0xe5, 0xce, 0xd9) };
278 
279 		LOG_DBG("Decrypting with sample data K");
280 
281 		k = test_k;
282 	} else {
283 		k = conn->le.keys->ltk.val;
284 	}
285 
286 	err = bt_csip_sdf(k, enc_sirk, out_sirk);
287 
288 	return err;
289 }
290 
lock_changed(struct bt_csip_set_coordinator_csis_inst * inst,bool locked)291 static void lock_changed(struct bt_csip_set_coordinator_csis_inst *inst, bool locked)
292 {
293 	struct bt_csip_set_coordinator_cb *listener;
294 
295 	active_members_reset();
296 
297 	SYS_SLIST_FOR_EACH_CONTAINER(&csip_set_coordinator_cbs, listener, _node) {
298 		if (listener->lock_changed) {
299 			listener->lock_changed(inst, locked);
300 		}
301 	}
302 }
303 
sirk_changed(struct bt_csip_set_coordinator_csis_inst * inst)304 static void sirk_changed(struct bt_csip_set_coordinator_csis_inst *inst)
305 {
306 	struct bt_csip_set_coordinator_cb *listener;
307 
308 	SYS_SLIST_FOR_EACH_CONTAINER(&csip_set_coordinator_cbs, listener, _node) {
309 		if (listener->sirk_changed) {
310 			listener->sirk_changed(inst);
311 		}
312 	}
313 }
314 
release_set_complete(int err)315 static void release_set_complete(int err)
316 {
317 	struct bt_csip_set_coordinator_cb *listener;
318 
319 	active_members_reset();
320 
321 	SYS_SLIST_FOR_EACH_CONTAINER(&csip_set_coordinator_cbs, listener, _node) {
322 		if (listener->release_set) {
323 			listener->release_set(err);
324 		}
325 	}
326 }
327 
lock_set_complete(int err)328 static void lock_set_complete(int err)
329 {
330 	struct bt_csip_set_coordinator_cb *listener;
331 
332 	active_members_reset();
333 
334 	SYS_SLIST_FOR_EACH_CONTAINER(&csip_set_coordinator_cbs, listener, _node) {
335 		if (listener->lock_set) {
336 			listener->lock_set(err);
337 		}
338 	}
339 }
340 
ordered_access_complete(const struct bt_csip_set_coordinator_set_info * set_info,int err,bool locked,struct bt_csip_set_coordinator_set_member * member)341 static void ordered_access_complete(const struct bt_csip_set_coordinator_set_info *set_info,
342 				    int err, bool locked,
343 				    struct bt_csip_set_coordinator_set_member *member)
344 {
345 
346 	struct bt_csip_set_coordinator_cb *listener;
347 
348 	active_members_reset();
349 
350 	SYS_SLIST_FOR_EACH_CONTAINER(&csip_set_coordinator_cbs, listener, _node) {
351 		if (listener->ordered_access) {
352 			listener->ordered_access(set_info, err, locked, member);
353 		}
354 	}
355 }
356 
discover_complete(struct bt_csip_set_coordinator_inst * client,int err)357 static void discover_complete(struct bt_csip_set_coordinator_inst *client,
358 			      int err)
359 {
360 	struct bt_csip_set_coordinator_cb *listener;
361 
362 	client->cur_inst = NULL;
363 	atomic_clear_bit(client->flags, SET_COORDINATOR_FLAG_BUSY);
364 
365 	SYS_SLIST_FOR_EACH_CONTAINER(&csip_set_coordinator_cbs, listener, _node) {
366 		if (listener->discover) {
367 			if (err == 0) {
368 				listener->discover(client->conn,
369 						   &client->set_member,
370 						   err, client->inst_count);
371 			} else {
372 				listener->discover(client->conn, NULL, err, 0U);
373 			}
374 		}
375 	}
376 }
377 
sirk_notify_func(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)378 static uint8_t sirk_notify_func(struct bt_conn *conn,
379 				struct bt_gatt_subscribe_params *params,
380 				const void *data, uint16_t length)
381 {
382 	uint16_t handle = params->value_handle;
383 	struct bt_csip_set_coordinator_svc_inst *svc_inst;
384 
385 	if (data == NULL) {
386 		LOG_DBG("[UNSUBSCRIBED] %u", params->value_handle);
387 		params->value_handle = 0U;
388 
389 		return BT_GATT_ITER_STOP;
390 	}
391 
392 	if (conn == NULL) {
393 		return BT_GATT_ITER_CONTINUE;
394 	}
395 
396 	svc_inst = lookup_instance_by_handle(conn, handle);
397 
398 	if (svc_inst != NULL) {
399 		LOG_DBG("Instance %u", svc_inst->idx);
400 		if (length == sizeof(struct bt_csip_sirk)) {
401 			struct bt_csip_sirk *sirk = (struct bt_csip_sirk *)data;
402 			struct bt_csip_set_coordinator_inst *client;
403 			struct bt_csip_set_coordinator_csis_inst *inst;
404 			uint8_t *dst_sirk;
405 
406 			client = &client_insts[bt_conn_index(conn)];
407 			inst = &client->set_member.insts[svc_inst->idx];
408 			dst_sirk = inst->info.sirk;
409 
410 			LOG_DBG("SIRK %sencrypted",
411 				sirk->type == BT_CSIP_SIRK_TYPE_PLAIN ? "not " : "");
412 
413 			/* Assuming not connected to other set devices */
414 			if (sirk->type == BT_CSIP_SIRK_TYPE_ENCRYPTED) {
415 				if (IS_ENABLED(CONFIG_BT_CSIP_SET_COORDINATOR_ENC_SIRK_SUPPORT)) {
416 					int err;
417 
418 					LOG_HEXDUMP_DBG(sirk->value, sizeof(*sirk),
419 							"Encrypted SIRK");
420 					err = sirk_decrypt(conn, sirk->value,
421 							   dst_sirk);
422 					if (err != 0) {
423 						LOG_ERR("Could not decrypt "
424 							"SIRK %d",
425 							err);
426 					}
427 				} else {
428 					LOG_DBG("Encrypted SIRK not supported");
429 					return BT_GATT_ITER_CONTINUE;
430 				}
431 			} else {
432 				(void)memcpy(dst_sirk, sirk->value, sizeof(sirk->value));
433 			}
434 
435 			LOG_HEXDUMP_DBG(dst_sirk, BT_CSIP_SIRK_SIZE, "SIRK");
436 
437 			sirk_changed(inst);
438 		} else {
439 			LOG_DBG("Invalid length %u", length);
440 		}
441 	} else {
442 		LOG_DBG("Notification/Indication on unknown service inst");
443 	}
444 
445 	return BT_GATT_ITER_CONTINUE;
446 }
447 
size_notify_func(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)448 static uint8_t size_notify_func(struct bt_conn *conn,
449 				struct bt_gatt_subscribe_params *params,
450 				const void *data, uint16_t length)
451 {
452 	uint8_t set_size;
453 	uint16_t handle = params->value_handle;
454 	struct bt_csip_set_coordinator_svc_inst *svc_inst;
455 
456 	if (data == NULL) {
457 		LOG_DBG("[UNSUBSCRIBED] %u", params->value_handle);
458 		params->value_handle = 0U;
459 
460 		return BT_GATT_ITER_STOP;
461 	}
462 
463 	if (conn == NULL) {
464 		return BT_GATT_ITER_CONTINUE;
465 	}
466 
467 	svc_inst = lookup_instance_by_handle(conn, handle);
468 
469 	if (svc_inst != NULL) {
470 		if (length == sizeof(set_size)) {
471 			struct bt_csip_set_coordinator_inst *client;
472 			struct bt_csip_set_coordinator_set_info *set_info;
473 
474 			client = &client_insts[bt_conn_index(conn)];
475 			set_info = &client->set_member.insts[svc_inst->idx].info;
476 
477 			(void)memcpy(&set_size, data, length);
478 			LOG_DBG("Set size updated from %u to %u", set_info->set_size, set_size);
479 
480 			set_info->set_size = set_size;
481 			/* TODO: Notify app */
482 		} else {
483 			LOG_DBG("Invalid length %u", length);
484 		}
485 
486 	} else {
487 		LOG_DBG("Notification/Indication on unknown service inst");
488 	}
489 	LOG_HEXDUMP_DBG(data, length, "Value");
490 
491 	return BT_GATT_ITER_CONTINUE;
492 }
493 
lock_notify_func(struct bt_conn * conn,struct bt_gatt_subscribe_params * params,const void * data,uint16_t length)494 static uint8_t lock_notify_func(struct bt_conn *conn,
495 				struct bt_gatt_subscribe_params *params,
496 				const void *data, uint16_t length)
497 {
498 	uint8_t value;
499 	uint16_t handle = params->value_handle;
500 	struct bt_csip_set_coordinator_svc_inst *svc_inst;
501 
502 	if (data == NULL) {
503 		LOG_DBG("[UNSUBSCRIBED] %u", params->value_handle);
504 		params->value_handle = 0U;
505 
506 		return BT_GATT_ITER_STOP;
507 	}
508 
509 	if (conn == NULL) {
510 		return BT_GATT_ITER_CONTINUE;
511 	}
512 
513 	svc_inst = lookup_instance_by_handle(conn, handle);
514 
515 	if (svc_inst != NULL) {
516 		if (length == sizeof(svc_inst->set_lock)) {
517 			struct bt_csip_set_coordinator_inst *client;
518 			struct bt_csip_set_coordinator_csis_inst *inst;
519 			bool locked;
520 
521 			(void)memcpy(&value, data, length);
522 			if (value != BT_CSIP_RELEASE_VALUE &&
523 			    value != BT_CSIP_LOCK_VALUE) {
524 				LOG_DBG("Invalid value %u", value);
525 				return BT_GATT_ITER_STOP;
526 			}
527 
528 			(void)memcpy(&svc_inst->set_lock, data, length);
529 
530 			locked = svc_inst->set_lock == BT_CSIP_LOCK_VALUE;
531 			LOG_DBG("Instance %u lock was %s", svc_inst->idx,
532 				locked ? "locked" : "released");
533 
534 			client = &client_insts[bt_conn_index(conn)];
535 			inst = &client->set_member.insts[svc_inst->idx];
536 
537 			lock_changed(inst, locked);
538 		} else {
539 			LOG_DBG("Invalid length %u", length);
540 		}
541 	} else {
542 		LOG_DBG("Notification/Indication on unknown service inst");
543 	}
544 	LOG_HEXDUMP_DBG(data, length, "Value");
545 
546 	return BT_GATT_ITER_CONTINUE;
547 }
548 
csip_set_coordinator_write_set_lock(struct bt_csip_set_coordinator_svc_inst * inst,bool lock,bt_gatt_write_func_t cb)549 static int csip_set_coordinator_write_set_lock(struct bt_csip_set_coordinator_svc_inst *inst,
550 					       bool lock,
551 					       bt_gatt_write_func_t cb)
552 {
553 	struct bt_csip_set_coordinator_inst *client = &client_insts[bt_conn_index(inst->conn)];
554 
555 	if (inst->set_lock_handle == 0) {
556 		LOG_DBG("Handle not set");
557 		client->cur_inst = NULL;
558 		return -EINVAL;
559 	}
560 
561 	/* Write to call control point */
562 	client->gatt_write_buf[0] = lock ? BT_CSIP_LOCK_VALUE : BT_CSIP_RELEASE_VALUE;
563 	client->write_params.data = client->gatt_write_buf;
564 	client->write_params.length = sizeof(lock);
565 	client->write_params.func = cb;
566 	client->write_params.handle = inst->set_lock_handle;
567 
568 	return bt_gatt_write(inst->conn, &client->write_params);
569 }
570 
read_sirk(struct bt_csip_set_coordinator_svc_inst * svc_inst)571 static int read_sirk(struct bt_csip_set_coordinator_svc_inst *svc_inst)
572 {
573 	struct bt_csip_set_coordinator_inst *client = &client_insts[bt_conn_index(svc_inst->conn)];
574 
575 	if (client->cur_inst != NULL) {
576 		if (client->cur_inst != svc_inst) {
577 			return -EBUSY;
578 		}
579 	} else {
580 		client->cur_inst = svc_inst;
581 	}
582 
583 	if (svc_inst->sirk_handle == 0) {
584 		LOG_DBG("Handle not set");
585 		return -EINVAL;
586 	}
587 
588 	client->read_params.func = csip_set_coordinator_discover_insts_read_sirk_cb;
589 	client->read_params.handle_count = 1;
590 	client->read_params.single.handle = svc_inst->sirk_handle;
591 	client->read_params.single.offset = 0U;
592 
593 	return bt_gatt_read(svc_inst->conn, &client->read_params);
594 }
595 
csip_set_coordinator_read_set_size(struct bt_conn * conn,uint8_t inst_idx,bt_gatt_read_func_t cb)596 static int csip_set_coordinator_read_set_size(struct bt_conn *conn,
597 					      uint8_t inst_idx,
598 					      bt_gatt_read_func_t cb)
599 {
600 	struct bt_csip_set_coordinator_inst *client = &client_insts[bt_conn_index(conn)];
601 
602 	if (inst_idx >= CONFIG_BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES) {
603 		return -EINVAL;
604 	} else if (client->cur_inst != NULL) {
605 		if (client->cur_inst !=
606 		    bt_csip_set_coordinator_lookup_instance_by_index(conn, inst_idx)) {
607 			return -EBUSY;
608 		}
609 	} else {
610 		client->cur_inst = bt_csip_set_coordinator_lookup_instance_by_index(conn, inst_idx);
611 		if (client->cur_inst == NULL) {
612 			LOG_DBG("Inst not found");
613 			return -EINVAL;
614 		}
615 	}
616 
617 	if (client->cur_inst->set_size_handle == 0) {
618 		LOG_DBG("Handle not set");
619 		client->cur_inst = NULL;
620 		return -EINVAL;
621 	}
622 
623 	client->read_params.func = cb;
624 	client->read_params.handle_count = 1;
625 	client->read_params.single.handle = client->cur_inst->set_size_handle;
626 	client->read_params.single.offset = 0U;
627 
628 	return bt_gatt_read(conn, &client->read_params);
629 }
630 
csip_set_coordinator_read_rank(struct bt_conn * conn,uint8_t inst_idx,bt_gatt_read_func_t cb)631 static int csip_set_coordinator_read_rank(struct bt_conn *conn,
632 					  uint8_t inst_idx,
633 					  bt_gatt_read_func_t cb)
634 {
635 	struct bt_csip_set_coordinator_inst *client = &client_insts[bt_conn_index(conn)];
636 
637 	if (inst_idx >= CONFIG_BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES) {
638 		return -EINVAL;
639 	} else if (client->cur_inst != NULL) {
640 		if (client->cur_inst !=
641 		    bt_csip_set_coordinator_lookup_instance_by_index(conn, inst_idx)) {
642 			return -EBUSY;
643 		}
644 	} else {
645 		client->cur_inst = bt_csip_set_coordinator_lookup_instance_by_index(conn, inst_idx);
646 		if (client->cur_inst == NULL) {
647 			LOG_DBG("Inst not found");
648 			return -EINVAL;
649 		}
650 	}
651 
652 	if (client->cur_inst->rank_handle == 0) {
653 		LOG_DBG("Handle not set");
654 		client->cur_inst = NULL;
655 		return -EINVAL;
656 	}
657 
658 	client->read_params.func = cb;
659 	client->read_params.handle_count = 1;
660 	client->read_params.single.handle = client->cur_inst->rank_handle;
661 	client->read_params.single.offset = 0U;
662 
663 	return bt_gatt_read(conn, &client->read_params);
664 }
665 
csip_set_coordinator_discover_sets(struct bt_csip_set_coordinator_inst * client)666 static int csip_set_coordinator_discover_sets(struct bt_csip_set_coordinator_inst *client)
667 {
668 	struct bt_csip_set_coordinator_set_member *member = &client->set_member;
669 
670 	/* Start reading values and call CB when done */
671 	return read_sirk((struct bt_csip_set_coordinator_svc_inst *)member->insts[0].svc_inst);
672 }
673 
discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)674 static uint8_t discover_func(struct bt_conn *conn,
675 			     const struct bt_gatt_attr *attr,
676 			     struct bt_gatt_discover_params *params)
677 {
678 	struct bt_gatt_chrc *chrc;
679 	struct bt_csip_set_coordinator_inst *client = &client_insts[bt_conn_index(conn)];
680 	struct bt_gatt_subscribe_params *sub_params = NULL;
681 	void *notify_handler = NULL;
682 
683 	if (attr == NULL) {
684 		LOG_DBG("Setup complete for %u / %u", client->cur_inst->idx + 1,
685 			client->inst_count);
686 		(void)memset(params, 0, sizeof(*params));
687 
688 		if (CONFIG_BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES > 1 &&
689 		    (client->cur_inst->idx + 1) < client->inst_count) {
690 			int err;
691 
692 			client->cur_inst = &client->svc_insts[client->cur_inst->idx + 1];
693 			client->discover_params.uuid = NULL;
694 			client->discover_params.start_handle = client->cur_inst->start_handle;
695 			client->discover_params.end_handle = client->cur_inst->end_handle;
696 			client->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
697 			client->discover_params.func = discover_func;
698 
699 			err = bt_gatt_discover(conn, &client->discover_params);
700 			if (err != 0) {
701 				LOG_DBG("Discover failed (err %d)", err);
702 				discover_complete(client, err);
703 			}
704 
705 		} else {
706 			int err;
707 
708 			client->cur_inst = NULL;
709 			err = csip_set_coordinator_discover_sets(client);
710 			if (err != 0) {
711 				LOG_DBG("Discover sets failed (err %d)", err);
712 				discover_complete(client, err);
713 			}
714 		}
715 		return BT_GATT_ITER_STOP;
716 	}
717 
718 	LOG_DBG("[ATTRIBUTE] handle 0x%04X", attr->handle);
719 
720 	if (params->type == BT_GATT_DISCOVER_CHARACTERISTIC &&
721 	    client->inst_count != 0) {
722 		chrc = (struct bt_gatt_chrc *)attr->user_data;
723 		if (bt_uuid_cmp(chrc->uuid, BT_UUID_CSIS_SIRK) == 0) {
724 			LOG_DBG("SIRK");
725 			client->cur_inst->sirk_handle = chrc->value_handle;
726 			sub_params = &client->cur_inst->sirk_sub_params;
727 			sub_params->disc_params = &client->cur_inst->sirk_sub_disc_params;
728 			notify_handler = sirk_notify_func;
729 		} else if (bt_uuid_cmp(chrc->uuid, BT_UUID_CSIS_SET_SIZE) == 0) {
730 			LOG_DBG("Set size");
731 			client->cur_inst->set_size_handle = chrc->value_handle;
732 			sub_params = &client->cur_inst->size_sub_params;
733 			sub_params->disc_params = &client->cur_inst->size_sub_disc_params;
734 			notify_handler = size_notify_func;
735 		} else if (bt_uuid_cmp(chrc->uuid, BT_UUID_CSIS_SET_LOCK) == 0) {
736 			struct bt_csip_set_coordinator_set_info *set_info;
737 
738 			LOG_DBG("Set lock");
739 			client->cur_inst->set_lock_handle = chrc->value_handle;
740 			sub_params = &client->cur_inst->lock_sub_params;
741 			sub_params->disc_params = &client->cur_inst->lock_sub_disc_params;
742 			notify_handler = lock_notify_func;
743 
744 			set_info = &client->set_member.insts[client->cur_inst->idx].info;
745 			set_info->lockable = true;
746 		} else if (bt_uuid_cmp(chrc->uuid, BT_UUID_CSIS_RANK) == 0) {
747 			LOG_DBG("Set rank");
748 			client->cur_inst->rank_handle = chrc->value_handle;
749 		}
750 
751 		if (sub_params != NULL && notify_handler != NULL) {
752 			sub_params->value = 0;
753 			if ((chrc->properties & BT_GATT_CHRC_NOTIFY) != 0) {
754 				sub_params->value = BT_GATT_CCC_NOTIFY;
755 			} else if ((chrc->properties & BT_GATT_CHRC_INDICATE) != 0) {
756 				sub_params->value = BT_GATT_CCC_INDICATE;
757 			}
758 
759 			if (sub_params->value != 0) {
760 				int err;
761 
762 				sub_params->ccc_handle = BT_GATT_AUTO_DISCOVER_CCC_HANDLE;
763 				sub_params->end_handle = client->cur_inst->end_handle;
764 				sub_params->value_handle = chrc->value_handle;
765 				sub_params->notify = notify_handler;
766 				atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE);
767 
768 				err = bt_gatt_subscribe(conn, sub_params);
769 				if (err != 0 && err != -EALREADY) {
770 					LOG_DBG("Failed to subscribe (err %d)", err);
771 					discover_complete(client, err);
772 
773 					return BT_GATT_ITER_STOP;
774 				}
775 			}
776 		}
777 	}
778 
779 	return BT_GATT_ITER_CONTINUE;
780 }
781 
primary_discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)782 static uint8_t primary_discover_func(struct bt_conn *conn,
783 				     const struct bt_gatt_attr *attr,
784 				     struct bt_gatt_discover_params *params)
785 {
786 	struct bt_gatt_service_val *prim_service;
787 	struct bt_csip_set_coordinator_inst *client = &client_insts[bt_conn_index(conn)];
788 
789 	if (attr == NULL ||
790 	    client->inst_count == CONFIG_BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES) {
791 		LOG_DBG("Discover complete, found %u instances", client->inst_count);
792 		(void)memset(params, 0, sizeof(*params));
793 
794 		if (client->inst_count != 0) {
795 			int err;
796 
797 			client->cur_inst = &client->svc_insts[0];
798 			client->discover_params.uuid = NULL;
799 			client->discover_params.start_handle = client->cur_inst->start_handle;
800 			client->discover_params.end_handle = client->cur_inst->end_handle;
801 			client->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
802 			client->discover_params.func = discover_func;
803 
804 			err = bt_gatt_discover(conn, &client->discover_params);
805 			if (err != 0) {
806 				LOG_DBG("Discover failed (err %d)", err);
807 				discover_complete(client, err);
808 			}
809 		} else {
810 			discover_complete(client, 0);
811 		}
812 
813 		return BT_GATT_ITER_STOP;
814 	}
815 
816 	LOG_DBG("[ATTRIBUTE] handle 0x%04X", attr->handle);
817 
818 	if (params->type == BT_GATT_DISCOVER_PRIMARY) {
819 		prim_service = (struct bt_gatt_service_val *)attr->user_data;
820 		client->discover_params.start_handle = attr->handle + 1;
821 
822 		client->cur_inst = &client->svc_insts[client->inst_count];
823 		client->cur_inst->idx = client->inst_count;
824 		client->cur_inst->start_handle = attr->handle;
825 		client->cur_inst->end_handle = prim_service->end_handle;
826 		client->cur_inst->conn = bt_conn_ref(conn);
827 		client->cur_inst->set_info = &client->set_member.insts[client->cur_inst->idx].info;
828 		client->inst_count++;
829 	}
830 
831 	return BT_GATT_ITER_CONTINUE;
832 }
833 
bt_csip_set_coordinator_is_set_member(const uint8_t sirk[BT_CSIP_SIRK_SIZE],struct bt_data * data)834 bool bt_csip_set_coordinator_is_set_member(const uint8_t sirk[BT_CSIP_SIRK_SIZE],
835 					   struct bt_data *data)
836 {
837 	if (data->type == BT_DATA_CSIS_RSI &&
838 	    data->data_len == BT_CSIP_RSI_SIZE) {
839 		uint8_t err;
840 		uint8_t hash[BT_CSIP_CRYPTO_HASH_SIZE];
841 		uint8_t prand[BT_CSIP_CRYPTO_PRAND_SIZE];
842 		uint8_t calculated_hash[BT_CSIP_CRYPTO_HASH_SIZE];
843 
844 		memcpy(hash, data->data, BT_CSIP_CRYPTO_HASH_SIZE);
845 		memcpy(prand, data->data + BT_CSIP_CRYPTO_HASH_SIZE, BT_CSIP_CRYPTO_PRAND_SIZE);
846 
847 		LOG_DBG("hash: %s", bt_hex(hash, BT_CSIP_CRYPTO_HASH_SIZE));
848 		LOG_DBG("prand %s", bt_hex(prand, BT_CSIP_CRYPTO_PRAND_SIZE));
849 		err = bt_csip_sih(sirk, prand, calculated_hash);
850 		if (err != 0) {
851 			return false;
852 		}
853 
854 		LOG_DBG("calculated_hash: %s", bt_hex(calculated_hash, BT_CSIP_CRYPTO_HASH_SIZE));
855 		LOG_DBG("hash: %s", bt_hex(hash, BT_CSIP_CRYPTO_HASH_SIZE));
856 
857 		return memcmp(calculated_hash, hash, BT_CSIP_CRYPTO_HASH_SIZE) == 0;
858 	}
859 
860 	return false;
861 }
862 
csip_set_coordinator_discover_insts_read_rank_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)863 static uint8_t csip_set_coordinator_discover_insts_read_rank_cb(struct bt_conn *conn,
864 								uint8_t err,
865 								struct bt_gatt_read_params *params,
866 								const void *data,
867 								uint16_t length)
868 {
869 	struct bt_csip_set_coordinator_inst *client = &client_insts[bt_conn_index(conn)];
870 
871 	__ASSERT(client->cur_inst != NULL, "client->cur_inst must not be NULL");
872 
873 	if (err != 0) {
874 		LOG_DBG("err: 0x%02X", err);
875 
876 		discover_complete(client, err);
877 	} else if (data != NULL) {
878 		struct bt_csip_set_coordinator_set_info *set_info;
879 
880 		LOG_HEXDUMP_DBG(data, length, "Data read");
881 
882 		set_info = &client->set_member.insts[client->cur_inst->idx].info;
883 
884 		if (length == sizeof(set_info->rank)) {
885 			(void)memcpy(&set_info->rank, data, length);
886 			LOG_DBG("%u", set_info->rank);
887 		} else {
888 			LOG_DBG("Invalid length, continuing to next member");
889 		}
890 
891 		discover_insts_resume(conn, 0, 0, 0);
892 	}
893 
894 	return BT_GATT_ITER_STOP;
895 }
896 
csip_set_coordinator_discover_insts_read_set_size_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)897 static uint8_t csip_set_coordinator_discover_insts_read_set_size_cb(
898 	struct bt_conn *conn, uint8_t err, struct bt_gatt_read_params *params,
899 	const void *data, uint16_t length)
900 {
901 	struct bt_csip_set_coordinator_inst *client = &client_insts[bt_conn_index(conn)];
902 
903 	__ASSERT(client->cur_inst != NULL, "client->cur_inst must not be NULL");
904 
905 	if (err != 0) {
906 		LOG_DBG("err: 0x%02X", err);
907 
908 		discover_complete(client, err);
909 	} else if (data != NULL) {
910 		struct bt_csip_set_coordinator_set_info *set_info;
911 
912 		LOG_HEXDUMP_DBG(data, length, "Data read");
913 
914 		set_info = &client->set_member.insts[client->cur_inst->idx].info;
915 
916 		if (length == sizeof(set_info->set_size)) {
917 			(void)memcpy(&set_info->set_size, data, length);
918 			LOG_DBG("%u", set_info->set_size);
919 		} else {
920 			LOG_DBG("Invalid length");
921 		}
922 
923 		discover_insts_resume(conn, 0, 0, client->cur_inst->rank_handle);
924 	}
925 
926 	return BT_GATT_ITER_STOP;
927 }
928 
parse_sirk(struct bt_csip_set_coordinator_inst * client,const void * data,uint16_t length)929 static int parse_sirk(struct bt_csip_set_coordinator_inst *client,
930 		      const void *data, uint16_t length)
931 {
932 	uint8_t *sirk;
933 
934 	sirk = client->set_member.insts[client->cur_inst->idx].info.sirk;
935 
936 	if (length == sizeof(struct bt_csip_sirk)) {
937 		struct bt_csip_sirk *recvd_sirk = (struct bt_csip_sirk *)data;
938 
939 		LOG_DBG("SIRK %sencrypted",
940 			recvd_sirk->type == BT_CSIP_SIRK_TYPE_PLAIN ? "not " : "");
941 		/* Assuming not connected to other set devices */
942 		if (recvd_sirk->type == BT_CSIP_SIRK_TYPE_ENCRYPTED) {
943 			if (IS_ENABLED(CONFIG_BT_CSIP_SET_COORDINATOR_ENC_SIRK_SUPPORT)) {
944 				int err;
945 
946 				LOG_HEXDUMP_DBG(recvd_sirk->value, sizeof(recvd_sirk->value),
947 						"Encrypted SIRK");
948 				err = sirk_decrypt(client->conn, recvd_sirk->value, sirk);
949 				if (err != 0) {
950 					LOG_ERR("Could not decrypt "
951 						"SIRK %d",
952 						err);
953 					return err;
954 				}
955 			} else {
956 				LOG_WRN("Encrypted SIRK not supported");
957 				sirk = NULL;
958 				return BT_ATT_ERR_INSUFFICIENT_ENCRYPTION;
959 			}
960 		} else {
961 			(void)memcpy(sirk, recvd_sirk->value, sizeof(recvd_sirk->value));
962 		}
963 
964 		if (sirk != NULL) {
965 			LOG_HEXDUMP_DBG(sirk, BT_CSIP_SIRK_SIZE, "SIRK");
966 		}
967 	} else {
968 		LOG_DBG("Invalid length");
969 		return BT_ATT_ERR_INVALID_ATTRIBUTE_LEN;
970 	}
971 
972 	return 0;
973 }
974 
csip_set_coordinator_discover_insts_read_sirk_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)975 static uint8_t csip_set_coordinator_discover_insts_read_sirk_cb(struct bt_conn *conn, uint8_t err,
976 								struct bt_gatt_read_params *params,
977 								const void *data, uint16_t length)
978 {
979 	struct bt_csip_set_coordinator_inst *client = &client_insts[bt_conn_index(conn)];
980 	int cb_err = err;
981 	__ASSERT(client->cur_inst != NULL, "client->cur_inst must not be NULL");
982 
983 	if (err != 0) {
984 		LOG_DBG("err: 0x%02X", err);
985 
986 		discover_complete(client, err);
987 	} else if (data != NULL) {
988 		LOG_HEXDUMP_DBG(data, length, "Data read");
989 
990 		cb_err = parse_sirk(client, data, length);
991 
992 		if (cb_err != 0) {
993 			LOG_DBG("Could not parse SIRK: %d", cb_err);
994 		} else {
995 			discover_insts_resume(conn, 0, client->cur_inst->set_size_handle,
996 					      client->cur_inst->rank_handle);
997 		}
998 	}
999 
1000 	return BT_GATT_ITER_STOP;
1001 }
1002 
1003 /**
1004  * @brief Reads the (next) characteristics for the set discovery procedure
1005  *
1006  * It skips all handles that are 0.
1007  *
1008  * @param conn        Connection to a CSIP set member device.
1009  * @param sirk_handle 0, or the handle for the SIRK characteristic.
1010  * @param size_handle 0, or the handle for the size characteristic.
1011  * @param rank_handle 0, or the handle for the rank characteristic.
1012  */
discover_insts_resume(struct bt_conn * conn,uint16_t sirk_handle,uint16_t size_handle,uint16_t rank_handle)1013 static void discover_insts_resume(struct bt_conn *conn, uint16_t sirk_handle,
1014 				 uint16_t size_handle, uint16_t rank_handle)
1015 {
1016 	int cb_err = 0;
1017 	struct bt_csip_set_coordinator_inst *client = &client_insts[bt_conn_index(conn)];
1018 
1019 	if (size_handle != 0) {
1020 		cb_err = csip_set_coordinator_read_set_size(
1021 			conn, client->cur_inst->idx,
1022 			csip_set_coordinator_discover_insts_read_set_size_cb);
1023 		if (cb_err != 0) {
1024 			LOG_DBG("Could not read set size: %d", cb_err);
1025 		}
1026 	} else if (rank_handle != 0) {
1027 		cb_err = csip_set_coordinator_read_rank(
1028 			conn, client->cur_inst->idx,
1029 			csip_set_coordinator_discover_insts_read_rank_cb);
1030 		if (cb_err != 0) {
1031 			LOG_DBG("Could not read set rank: %d", cb_err);
1032 		}
1033 	} else {
1034 		uint8_t next_idx = client->cur_inst->idx + 1;
1035 
1036 		client->cur_inst = NULL;
1037 		if (next_idx < client->inst_count) {
1038 			client->cur_inst =
1039 				bt_csip_set_coordinator_lookup_instance_by_index(conn, next_idx);
1040 
1041 			/* Read next */
1042 			cb_err = read_sirk(client->cur_inst);
1043 		} else {
1044 			discover_complete(client, 0);
1045 
1046 			return;
1047 		}
1048 	}
1049 
1050 	if (cb_err != 0) {
1051 		discover_complete(client, cb_err);
1052 	}
1053 }
1054 
csip_set_coordinator_write_restore_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)1055 static void csip_set_coordinator_write_restore_cb(struct bt_conn *conn,
1056 						  uint8_t err,
1057 						  struct bt_gatt_write_params *params)
1058 {
1059 	struct bt_csip_set_coordinator_inst *client = &client_insts[bt_conn_index(conn)];
1060 
1061 	if (err != 0) {
1062 		LOG_WRN("Could not restore (%d)", err);
1063 		release_set_complete(err);
1064 
1065 		return;
1066 	}
1067 
1068 	active.members_restored++;
1069 	LOG_DBG("Restored %u/%u members", active.members_restored, active.members_handled);
1070 
1071 	if (active.members_restored < active.members_handled &&
1072 	    CONFIG_BT_MAX_CONN > 1) {
1073 		struct bt_csip_set_coordinator_set_member *member;
1074 		int csip_err;
1075 
1076 		member = active.members[active.members_handled - active.members_restored - 1];
1077 		client->cur_inst = lookup_instance_by_set_info(member, &active.info);
1078 		if (client->cur_inst == NULL) {
1079 			release_set_complete(-ENOENT);
1080 
1081 			return;
1082 		}
1083 
1084 		csip_err = csip_set_coordinator_write_set_lock(
1085 			client->cur_inst, false, csip_set_coordinator_write_restore_cb);
1086 		if (csip_err != 0) {
1087 			LOG_DBG("Failed to release next member[%u]: %d", active.members_handled,
1088 				csip_err);
1089 
1090 			release_set_complete(csip_err);
1091 		}
1092 	} else {
1093 		release_set_complete(0);
1094 	}
1095 }
1096 
csip_set_coordinator_write_lock_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)1097 static void csip_set_coordinator_write_lock_cb(struct bt_conn *conn,
1098 					       uint8_t err,
1099 					       struct bt_gatt_write_params *params)
1100 {
1101 	struct bt_csip_set_coordinator_inst *client = &client_insts[bt_conn_index(conn)];
1102 
1103 	if (err != 0) {
1104 		LOG_DBG("Could not lock (0x%X)", err);
1105 		if (active.members_handled > 0 && CONFIG_BT_MAX_CONN > 1) {
1106 			struct bt_csip_set_coordinator_set_member *member;
1107 			int csip_err;
1108 
1109 			active.members_restored = 0;
1110 
1111 			member = active.members[active.members_handled - 1];
1112 			client->cur_inst = lookup_instance_by_set_info(member, &active.info);
1113 			if (client->cur_inst == NULL) {
1114 				LOG_DBG("Failed to lookup instance by set_info");
1115 
1116 				lock_set_complete(-ENOENT);
1117 				return;
1118 			}
1119 
1120 			csip_err = csip_set_coordinator_write_set_lock(
1121 				client->cur_inst, false, csip_set_coordinator_write_restore_cb);
1122 			if (csip_err != 0) {
1123 				LOG_WRN("Could not release lock of previous locked member: %d",
1124 					csip_err);
1125 				active_members_reset();
1126 				return;
1127 			}
1128 		} else {
1129 			lock_set_complete(err);
1130 		}
1131 
1132 		return;
1133 	}
1134 
1135 	active.members_handled++;
1136 	LOG_DBG("Locked %u/%u members", active.members_handled, active.members_count);
1137 
1138 	if (active.members_handled < active.members_count) {
1139 		struct bt_csip_set_coordinator_svc_inst *prev_inst = client->cur_inst;
1140 		int csip_err;
1141 
1142 		client->cur_inst = get_next_active_instance();
1143 		if (client->cur_inst == NULL) {
1144 			lock_set_complete(-ENOENT);
1145 
1146 			return;
1147 		}
1148 
1149 		csip_err = csip_set_coordinator_write_set_lock(client->cur_inst, true,
1150 							       csip_set_coordinator_write_lock_cb);
1151 		if (csip_err != 0) {
1152 			LOG_DBG("Failed to lock next member[%u]: %d", active.members_handled,
1153 				csip_err);
1154 
1155 			active.members_restored = 0;
1156 
1157 			csip_err = csip_set_coordinator_write_set_lock(
1158 					prev_inst, false,
1159 					csip_set_coordinator_write_restore_cb);
1160 			if (csip_err != 0) {
1161 				LOG_WRN("Could not release lock of previous locked member: %d",
1162 					csip_err);
1163 				active_members_reset();
1164 				return;
1165 			}
1166 		}
1167 	} else {
1168 		lock_set_complete(0);
1169 	}
1170 }
1171 
csip_set_coordinator_write_release_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)1172 static void csip_set_coordinator_write_release_cb(struct bt_conn *conn, uint8_t err,
1173 						  struct bt_gatt_write_params *params)
1174 {
1175 	struct bt_csip_set_coordinator_inst *client = &client_insts[bt_conn_index(conn)];
1176 
1177 	if (err != 0) {
1178 		LOG_DBG("Could not release lock (%d)", err);
1179 		release_set_complete(err);
1180 
1181 		return;
1182 	}
1183 
1184 	active.members_handled++;
1185 	LOG_DBG("Released %u/%u members", active.members_handled, active.members_count);
1186 
1187 	if (active.members_handled < active.members_count) {
1188 		int csip_err;
1189 
1190 		client->cur_inst = get_next_active_instance();
1191 		if (client->cur_inst == NULL) {
1192 			release_set_complete(-ENOENT);
1193 
1194 			return;
1195 		}
1196 
1197 		csip_err = csip_set_coordinator_write_set_lock(
1198 			client->cur_inst, false, csip_set_coordinator_write_release_cb);
1199 		if (csip_err != 0) {
1200 			LOG_DBG("Failed to release next member[%u]: %d", active.members_handled,
1201 				csip_err);
1202 
1203 			release_set_complete(csip_err);
1204 		}
1205 	} else {
1206 		release_set_complete(0);
1207 	}
1208 }
1209 
csip_set_coordinator_lock_state_read_cb(int err,bool locked)1210 static void csip_set_coordinator_lock_state_read_cb(int err, bool locked)
1211 {
1212 	const struct bt_csip_set_coordinator_set_info *info = &active.info;
1213 	struct bt_csip_set_coordinator_set_member *cur_member = NULL;
1214 
1215 	if (err || locked) {
1216 		cur_member = active.members[active.members_handled];
1217 	} else if (active.oap_cb == NULL || !active.oap_cb(info, active.members,
1218 		   active.members_count)) {
1219 		err = -ECANCELED;
1220 	}
1221 
1222 	ordered_access_complete(info, err, locked, cur_member);
1223 }
1224 
csip_set_coordinator_read_lock_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)1225 static uint8_t csip_set_coordinator_read_lock_cb(struct bt_conn *conn,
1226 						 uint8_t err,
1227 						 struct bt_gatt_read_params *params,
1228 						 const void *data,
1229 						 uint16_t length)
1230 {
1231 	struct bt_csip_set_coordinator_inst *client = &client_insts[bt_conn_index(conn)];
1232 	uint8_t value = 0;
1233 
1234 	if (err != 0) {
1235 		LOG_DBG("Could not read lock value (0x%X)", err);
1236 
1237 		csip_set_coordinator_lock_state_read_cb(err, false);
1238 
1239 		return BT_GATT_ITER_STOP;
1240 	}
1241 
1242 	active.members_handled++;
1243 	LOG_DBG("Read lock state on %u/%u members", active.members_handled, active.members_count);
1244 
1245 	if (data == NULL || length != sizeof(client->cur_inst->set_lock)) {
1246 		LOG_DBG("Invalid data %p or length %u", data, length);
1247 
1248 		csip_set_coordinator_lock_state_read_cb(err, false);
1249 
1250 		return BT_GATT_ITER_STOP;
1251 	}
1252 
1253 	value = ((uint8_t *)data)[0];
1254 	if (value != BT_CSIP_RELEASE_VALUE && value != BT_CSIP_LOCK_VALUE) {
1255 		LOG_DBG("Invalid value %u read", value);
1256 		err = BT_ATT_ERR_UNLIKELY;
1257 
1258 		csip_set_coordinator_lock_state_read_cb(err, false);
1259 
1260 		return BT_GATT_ITER_STOP;
1261 	}
1262 
1263 	client->cur_inst->set_lock = value;
1264 
1265 	if (value != BT_CSIP_RELEASE_VALUE) {
1266 		LOG_DBG("Set member not unlocked");
1267 
1268 		csip_set_coordinator_lock_state_read_cb(0, true);
1269 
1270 		return BT_GATT_ITER_STOP;
1271 	}
1272 
1273 	if (active.members_handled < active.members_count) {
1274 		int csip_err;
1275 
1276 		client->cur_inst = get_next_active_instance();
1277 		if (client->cur_inst == NULL) {
1278 			csip_set_coordinator_lock_state_read_cb(-ENOENT, false);
1279 
1280 			return BT_GATT_ITER_STOP;
1281 		}
1282 
1283 		csip_err = csip_set_coordinator_read_set_lock(client->cur_inst);
1284 		if (csip_err != 0) {
1285 			LOG_DBG("Failed to read next member[%u]: %d", active.members_handled,
1286 				csip_err);
1287 
1288 			csip_set_coordinator_lock_state_read_cb(err, false);
1289 		}
1290 	} else {
1291 		csip_set_coordinator_lock_state_read_cb(0, false);
1292 	}
1293 
1294 	return BT_GATT_ITER_STOP;
1295 }
1296 
csip_set_coordinator_read_set_lock(struct bt_csip_set_coordinator_svc_inst * inst)1297 static int csip_set_coordinator_read_set_lock(struct bt_csip_set_coordinator_svc_inst *inst)
1298 {
1299 	struct bt_csip_set_coordinator_inst *client = &client_insts[bt_conn_index(inst->conn)];
1300 	int err;
1301 
1302 	if (inst->set_lock_handle == 0) {
1303 		LOG_DBG("Handle not set");
1304 		client->cur_inst = NULL;
1305 		return -EINVAL;
1306 	}
1307 
1308 	client->read_params.func = csip_set_coordinator_read_lock_cb;
1309 	client->read_params.handle_count = 1;
1310 	client->read_params.single.handle = inst->set_lock_handle;
1311 	client->read_params.single.offset = 0;
1312 
1313 	client->cur_inst = inst;
1314 
1315 	err = bt_gatt_read(inst->conn, &client->read_params);
1316 	if (err != 0) {
1317 		client->cur_inst = NULL;
1318 	}
1319 
1320 	return err;
1321 }
1322 
csip_set_coordinator_reset(struct bt_csip_set_coordinator_inst * inst)1323 static void csip_set_coordinator_reset(struct bt_csip_set_coordinator_inst *inst)
1324 {
1325 	inst->inst_count = 0U;
1326 	memset(&inst->set_member, 0, sizeof(inst->set_member));
1327 
1328 	for (size_t i = 0; i < ARRAY_SIZE(inst->svc_insts); i++) {
1329 		struct bt_csip_set_coordinator_svc_inst *svc_inst = &inst->svc_insts[i];
1330 
1331 		svc_inst->idx = 0;
1332 		svc_inst->set_lock = 0;
1333 		svc_inst->start_handle = 0;
1334 		svc_inst->end_handle = 0;
1335 		svc_inst->sirk_handle = 0;
1336 		svc_inst->set_size_handle = 0;
1337 		svc_inst->set_lock_handle = 0;
1338 		svc_inst->rank_handle = 0;
1339 
1340 		if (svc_inst->conn != NULL) {
1341 			struct bt_conn *conn = svc_inst->conn;
1342 
1343 			bt_conn_unref(conn);
1344 			svc_inst->conn = NULL;
1345 		}
1346 
1347 		if (svc_inst->set_info != NULL) {
1348 			memset(svc_inst->set_info, 0, sizeof(*svc_inst->set_info));
1349 			svc_inst->set_info = NULL;
1350 		}
1351 	}
1352 
1353 	if (inst->conn) {
1354 		bt_conn_unref(inst->conn);
1355 		inst->conn = NULL;
1356 	}
1357 }
1358 
disconnected(struct bt_conn * conn,uint8_t reason)1359 static void disconnected(struct bt_conn *conn, uint8_t reason)
1360 {
1361 	struct bt_csip_set_coordinator_inst *inst = &client_insts[bt_conn_index(conn)];
1362 
1363 	if (inst->conn == conn) {
1364 		csip_set_coordinator_reset(inst);
1365 	}
1366 }
1367 
1368 BT_CONN_CB_DEFINE(conn_callbacks) = {
1369 	.disconnected = disconnected,
1370 };
1371 
bt_csip_set_coordinator_csis_inst_by_handle(struct bt_conn * conn,uint16_t start_handle)1372 struct bt_csip_set_coordinator_csis_inst *bt_csip_set_coordinator_csis_inst_by_handle(
1373 	struct bt_conn *conn, uint16_t start_handle)
1374 {
1375 	const struct bt_csip_set_coordinator_svc_inst *svc_inst;
1376 
1377 	CHECKIF(conn == NULL) {
1378 		LOG_DBG("conn is NULL");
1379 
1380 		return NULL;
1381 	}
1382 
1383 	CHECKIF(start_handle == 0) {
1384 		LOG_DBG("start_handle is 0");
1385 
1386 		return NULL;
1387 	}
1388 
1389 	svc_inst = lookup_instance_by_handle(conn, start_handle);
1390 
1391 	if (svc_inst != NULL) {
1392 		struct bt_csip_set_coordinator_inst *client;
1393 
1394 		client = &client_insts[bt_conn_index(conn)];
1395 
1396 		return &client->set_member.insts[svc_inst->idx];
1397 	}
1398 
1399 	return NULL;
1400 }
1401 
1402 struct bt_csip_set_coordinator_set_member *
bt_csip_set_coordinator_set_member_by_conn(const struct bt_conn * conn)1403 bt_csip_set_coordinator_set_member_by_conn(const struct bt_conn *conn)
1404 {
1405 	struct bt_csip_set_coordinator_inst *client;
1406 
1407 	CHECKIF(conn == NULL) {
1408 		LOG_DBG("conn is NULL");
1409 
1410 		return NULL;
1411 	}
1412 
1413 	client = &client_insts[bt_conn_index(conn)];
1414 	if (client->conn == conn) {
1415 		return &client->set_member;
1416 	}
1417 
1418 	return NULL;
1419 }
1420 
1421 /*************************** PUBLIC FUNCTIONS ***************************/
bt_csip_set_coordinator_register_cb(struct bt_csip_set_coordinator_cb * cb)1422 int bt_csip_set_coordinator_register_cb(struct bt_csip_set_coordinator_cb *cb)
1423 {
1424 	CHECKIF(cb == NULL) {
1425 		LOG_DBG("cb is NULL");
1426 
1427 		return -EINVAL;
1428 	}
1429 
1430 	sys_slist_append(&csip_set_coordinator_cbs, &cb->_node);
1431 
1432 	return 0;
1433 }
1434 
bt_csip_set_coordinator_discover(struct bt_conn * conn)1435 int bt_csip_set_coordinator_discover(struct bt_conn *conn)
1436 {
1437 	int err;
1438 	struct bt_csip_set_coordinator_inst *client;
1439 
1440 	CHECKIF(conn == NULL) {
1441 		LOG_DBG("NULL conn");
1442 		return -EINVAL;
1443 	}
1444 
1445 	client = &client_insts[bt_conn_index(conn)];
1446 	if (atomic_test_and_set_bit(client->flags, SET_COORDINATOR_FLAG_BUSY)) {
1447 		return -EBUSY;
1448 	}
1449 
1450 	csip_set_coordinator_reset(client);
1451 
1452 	/* Discover CSIS on peer, setup handles and notify */
1453 	(void)memset(&client->discover_params, 0, sizeof(client->discover_params));
1454 	(void)memcpy(&uuid, BT_UUID_CSIS, sizeof(uuid));
1455 	client->discover_params.func = primary_discover_func;
1456 	client->discover_params.uuid = &uuid.uuid;
1457 	client->discover_params.type = BT_GATT_DISCOVER_PRIMARY;
1458 	client->discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
1459 	client->discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
1460 
1461 	err = bt_gatt_discover(conn, &client->discover_params);
1462 	if (err == 0) {
1463 		for (size_t i = 0; i < ARRAY_SIZE(client->set_member.insts); i++) {
1464 			client->set_member.insts[i].svc_inst = (void *)&client->svc_insts[i];
1465 		}
1466 		client->conn = bt_conn_ref(conn);
1467 	} else {
1468 		atomic_clear_bit(client->flags, SET_COORDINATOR_FLAG_BUSY);
1469 	}
1470 
1471 	return err;
1472 }
1473 
verify_members(const struct bt_csip_set_coordinator_set_member ** members,uint8_t count,const struct bt_csip_set_coordinator_set_info * set_info)1474 static int verify_members(const struct bt_csip_set_coordinator_set_member **members,
1475 			  uint8_t count,
1476 			  const struct bt_csip_set_coordinator_set_info *set_info)
1477 {
1478 	bool zero_rank;
1479 	uint8_t ranks[CONFIG_BT_MAX_CONN];
1480 
1481 	if (count > CONFIG_BT_MAX_CONN) {
1482 		LOG_DBG("count (%u) larger than maximum support servers (%d)", count,
1483 			CONFIG_BT_MAX_CONN);
1484 		return -EINVAL;
1485 	}
1486 
1487 	zero_rank = false;
1488 	for (int i = 0; i < count; i++) {
1489 		const struct bt_csip_set_coordinator_set_member *member = members[i];
1490 		struct bt_csip_set_coordinator_inst *client_inst =
1491 			CONTAINER_OF(member, struct bt_csip_set_coordinator_inst, set_member);
1492 		struct bt_csip_set_coordinator_svc_inst *svc_inst;
1493 		struct bt_conn *conn;
1494 
1495 		CHECKIF(member == NULL) {
1496 			LOG_DBG("Invalid member[%d] was NULL", i);
1497 			return -EINVAL;
1498 		}
1499 
1500 		conn = client_inst->conn;
1501 
1502 		CHECKIF(conn == NULL) {
1503 			LOG_DBG("Member[%d] conn was NULL", i);
1504 			return -EINVAL;
1505 		}
1506 
1507 		if (conn->state != BT_CONN_CONNECTED) {
1508 			LOG_DBG("Member[%d] was not connected", i);
1509 			return -ENOTCONN;
1510 		}
1511 
1512 		svc_inst = lookup_instance_by_set_info(member, set_info);
1513 		if (svc_inst == NULL) {
1514 			LOG_DBG("Member[%d] could not find matching instance for the set_info", i);
1515 			return -EINVAL;
1516 		}
1517 
1518 		ranks[i] = svc_inst->set_info->rank;
1519 		if (ranks[i] == 0U && !zero_rank) {
1520 			zero_rank = true;
1521 		} else if (ranks[i] != 0 && zero_rank) {
1522 			/* all members in a set shall either use rank, or not use rank */
1523 			LOG_DBG("Found mix of 0 and non-0 ranks");
1524 			return -EINVAL;
1525 		}
1526 	}
1527 
1528 	if (CONFIG_BT_MAX_CONN > 1 && !zero_rank && count > 1U) {
1529 		/* Search for duplicate ranks */
1530 		for (uint8_t i = 0U; i < count - 1; i++) {
1531 			for (uint8_t j = i + 1; j < count; j++) {
1532 				if (ranks[j] == ranks[i]) {
1533 					/* duplicate rank */
1534 					LOG_DBG("Duplicate rank (%u) for members[%zu] "
1535 						"and members[%zu]",
1536 						ranks[i], i, j);
1537 					return -EINVAL;
1538 				}
1539 			}
1540 		}
1541 	}
1542 
1543 	return 0;
1544 }
1545 
check_and_set_members_busy(const struct bt_csip_set_coordinator_set_member * members[],size_t count)1546 static bool check_and_set_members_busy(const struct bt_csip_set_coordinator_set_member *members[],
1547 				       size_t count)
1548 {
1549 	size_t num_free;
1550 
1551 	for (num_free = 0U; num_free < count; num_free++) {
1552 		const struct bt_csip_set_coordinator_set_member *member = members[num_free];
1553 		struct bt_csip_set_coordinator_inst *client =
1554 			CONTAINER_OF(member, struct bt_csip_set_coordinator_inst, set_member);
1555 
1556 		if (atomic_test_and_set_bit(client->flags, SET_COORDINATOR_FLAG_BUSY)) {
1557 			LOG_DBG("Member[%zu] (%p) is busy", num_free, member);
1558 			break;
1559 		}
1560 	}
1561 
1562 	/* If any is busy, revert any busy states we've set */
1563 	if (num_free != count) {
1564 		for (size_t i = 0U; i < num_free; i++) {
1565 			const struct bt_csip_set_coordinator_set_member *member = members[i];
1566 			struct bt_csip_set_coordinator_inst *client = CONTAINER_OF(
1567 				member, struct bt_csip_set_coordinator_inst, set_member);
1568 
1569 			atomic_clear_bit(client->flags, SET_COORDINATOR_FLAG_BUSY);
1570 		}
1571 	}
1572 
1573 	return num_free == count;
1574 }
1575 
1576 static int
csip_set_coordinator_get_lock_state(const struct bt_csip_set_coordinator_set_member ** members,uint8_t count,const struct bt_csip_set_coordinator_set_info * set_info)1577 csip_set_coordinator_get_lock_state(const struct bt_csip_set_coordinator_set_member **members,
1578 				    uint8_t count,
1579 				    const struct bt_csip_set_coordinator_set_info *set_info)
1580 {
1581 	int err;
1582 
1583 	if (active.in_progress) {
1584 		LOG_DBG("Procedure in progress");
1585 		return -EBUSY;
1586 	}
1587 
1588 	err = verify_members(members, count, set_info);
1589 	if (err != 0) {
1590 		LOG_DBG("Could not verify members: %d", err);
1591 		return err;
1592 	}
1593 
1594 	if (!check_and_set_members_busy(members, count)) {
1595 		LOG_DBG("One or more members are busy");
1596 		return -EBUSY;
1597 	}
1598 
1599 	active_members_store_ordered(members, count, set_info, true);
1600 
1601 	for (uint8_t i = 0U; i < count; i++) {
1602 		struct bt_csip_set_coordinator_svc_inst *svc_inst;
1603 
1604 		svc_inst = lookup_instance_by_set_info(active.members[i], &active.info);
1605 		if (svc_inst == NULL) {
1606 			LOG_DBG("Failed to lookup instance by set_info");
1607 
1608 			active_members_reset();
1609 			return -ENOENT;
1610 		}
1611 
1612 		if (svc_inst->set_info->lockable) {
1613 			err = csip_set_coordinator_read_set_lock(svc_inst);
1614 			if (err == 0) {
1615 				active.in_progress = true;
1616 			}
1617 
1618 			break;
1619 		}
1620 
1621 		active.members_handled++;
1622 	}
1623 
1624 	if (!active.in_progress && err == 0) {
1625 		/* We are not reading any lock states (because they are not on the remote devices),
1626 		 * so we can just initiate the ordered access procedure (oap) callback directly
1627 		 * here.
1628 		 */
1629 		if (active.oap_cb == NULL ||
1630 		    !active.oap_cb(&active.info, active.members, active.members_count)) {
1631 			err = -ECANCELED;
1632 		}
1633 
1634 		ordered_access_complete(&active.info, err, false, NULL);
1635 	}
1636 
1637 	return err;
1638 }
1639 
bt_csip_set_coordinator_ordered_access(const struct bt_csip_set_coordinator_set_member * members[],uint8_t count,const struct bt_csip_set_coordinator_set_info * set_info,bt_csip_set_coordinator_ordered_access_t cb)1640 int bt_csip_set_coordinator_ordered_access(
1641 	const struct bt_csip_set_coordinator_set_member *members[],
1642 	uint8_t count,
1643 	const struct bt_csip_set_coordinator_set_info *set_info,
1644 	bt_csip_set_coordinator_ordered_access_t cb)
1645 {
1646 	int err;
1647 
1648 	/* wait for the get_lock_state to finish and then call the callback */
1649 	active.oap_cb = cb;
1650 
1651 	err = csip_set_coordinator_get_lock_state(members, count, set_info);
1652 	if (err != 0) {
1653 		active.oap_cb = NULL;
1654 
1655 		return err;
1656 	}
1657 
1658 	return 0;
1659 }
1660 
1661 /* As per CSIP, locking and releasing sets can only be done by bonded devices, so it does not makes
1662  * sense to have these functions available if we do not support bonding
1663  */
1664 #if defined(CONFIG_BT_BONDABLE)
all_members_bonded(const struct bt_csip_set_coordinator_set_member * members[],size_t count)1665 static bool all_members_bonded(const struct bt_csip_set_coordinator_set_member *members[],
1666 			       size_t count)
1667 {
1668 	for (size_t i = 0U; i < count; i++) {
1669 		const struct bt_csip_set_coordinator_set_member *member = members[i];
1670 		const struct bt_csip_set_coordinator_inst *client =
1671 			CONTAINER_OF(member, struct bt_csip_set_coordinator_inst, set_member);
1672 		struct bt_conn_info info;
1673 		int err;
1674 
1675 		err = bt_conn_get_info(client->conn, &info);
1676 		if (err != 0 || !bt_le_bond_exists(info.id, info.le.dst)) {
1677 			LOG_DBG("Member[%zu] is not bonded", i);
1678 
1679 			return false;
1680 		}
1681 	}
1682 
1683 	return true;
1684 }
1685 
bt_csip_set_coordinator_lock(const struct bt_csip_set_coordinator_set_member ** members,uint8_t count,const struct bt_csip_set_coordinator_set_info * set_info)1686 int bt_csip_set_coordinator_lock(
1687 	const struct bt_csip_set_coordinator_set_member **members,
1688 	uint8_t count,
1689 	const struct bt_csip_set_coordinator_set_info *set_info)
1690 {
1691 	struct bt_csip_set_coordinator_svc_inst *svc_inst;
1692 	int err;
1693 
1694 	CHECKIF(active.in_progress) {
1695 		LOG_DBG("Procedure in progress");
1696 		return -EBUSY;
1697 	}
1698 
1699 	err = verify_members(members, count, set_info);
1700 	if (err != 0) {
1701 		LOG_DBG("Could not verify members: %d", err);
1702 		return err;
1703 	}
1704 
1705 	if (!all_members_bonded(members, count)) {
1706 		return -EINVAL;
1707 	}
1708 
1709 	if (!check_and_set_members_busy(members, count)) {
1710 		LOG_DBG("One or more members are busy");
1711 		return -EBUSY;
1712 	}
1713 
1714 	active_members_store_ordered(members, count, set_info, true);
1715 
1716 	svc_inst = lookup_instance_by_set_info(active.members[0], &active.info);
1717 	if (svc_inst == NULL) {
1718 		LOG_DBG("Failed to lookup instance by set_info");
1719 
1720 		active_members_reset();
1721 		return -ENOENT;
1722 	}
1723 
1724 	err = csip_set_coordinator_write_set_lock(svc_inst, true,
1725 						  csip_set_coordinator_write_lock_cb);
1726 	if (err == 0) {
1727 		active.in_progress = true;
1728 	}
1729 
1730 	return err;
1731 }
1732 
bt_csip_set_coordinator_release(const struct bt_csip_set_coordinator_set_member ** members,uint8_t count,const struct bt_csip_set_coordinator_set_info * set_info)1733 int bt_csip_set_coordinator_release(const struct bt_csip_set_coordinator_set_member **members,
1734 				    uint8_t count,
1735 				    const struct bt_csip_set_coordinator_set_info *set_info)
1736 {
1737 	struct bt_csip_set_coordinator_svc_inst *svc_inst;
1738 	int err;
1739 
1740 	CHECKIF(active.in_progress) {
1741 		LOG_DBG("Procedure in progress");
1742 		return -EBUSY;
1743 	}
1744 
1745 	err = verify_members(members, count, set_info);
1746 	if (err != 0) {
1747 		LOG_DBG("Could not verify members: %d", err);
1748 		return err;
1749 	}
1750 
1751 	if (!all_members_bonded(members, count)) {
1752 		return -EINVAL;
1753 	}
1754 
1755 	if (!check_and_set_members_busy(members, count)) {
1756 		LOG_DBG("One or more members are busy");
1757 		return -EBUSY;
1758 	}
1759 
1760 	active_members_store_ordered(members, count, set_info, false);
1761 
1762 	svc_inst = lookup_instance_by_set_info(active.members[0], &active.info);
1763 	if (svc_inst == NULL) {
1764 		LOG_DBG("Failed to lookup instance by set_info");
1765 
1766 		active_members_reset();
1767 		return -ENOENT;
1768 	}
1769 
1770 	err = csip_set_coordinator_write_set_lock(svc_inst, false,
1771 						  csip_set_coordinator_write_release_cb);
1772 	if (err == 0) {
1773 		active.in_progress = true;
1774 	}
1775 
1776 	return err;
1777 }
1778 #endif /* CONFIG_BT_BONDABLE */
1779