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