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