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