Line data Source code
1 1 : /**
2 : * @file
3 : * @brief Bluetooth Coordinated Set Identification Profile (CSIP) APIs.
4 : */
5 :
6 : /*
7 : * Copyright (c) 2021-2024 Nordic Semiconductor ASA
8 : *
9 : * SPDX-License-Identifier: Apache-2.0
10 : */
11 :
12 : #ifndef ZEPHYR_SUBSYS_BLUETOOTH_AUDIO_CSIP_H_
13 : #define ZEPHYR_SUBSYS_BLUETOOTH_AUDIO_CSIP_H_
14 :
15 : /**
16 : * @brief Coordinated Set Identification Profile (CSIP)
17 : *
18 : * @defgroup bt_csip Coordinated Set Identification Profile (CSIP)
19 : *
20 : * @since 3.0
21 : * @version 0.8.0
22 : *
23 : * @ingroup bluetooth
24 : * @{
25 : *
26 : * The Coordinated Set Identification Profile (CSIP) provides procedures to discover and coordinate
27 : * sets of devices.
28 : */
29 :
30 : #include <stdbool.h>
31 : #include <stddef.h>
32 : #include <stdint.h>
33 :
34 : #include <zephyr/autoconf.h>
35 : #include <zephyr/bluetooth/bluetooth.h>
36 : #include <zephyr/bluetooth/conn.h>
37 : #include <zephyr/bluetooth/gap.h>
38 : #include <zephyr/kernel.h>
39 : #include <zephyr/sys/slist.h>
40 :
41 : #ifdef __cplusplus
42 : extern "C" {
43 : #endif
44 :
45 : /** Recommended timer for member discovery */
46 1 : #define BT_CSIP_SET_COORDINATOR_DISCOVER_TIMER_VALUE K_SECONDS(10)
47 :
48 : /**
49 : * Defines the maximum number of Coordinated Set Identification service instances for the
50 : * Coordinated Set Identification Set Coordinator
51 : */
52 : #if defined(CONFIG_BT_CSIP_SET_COORDINATOR)
53 : #define BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES CONFIG_BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES
54 : #else
55 1 : #define BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES 0
56 : #endif /* CONFIG_BT_CSIP_SET_COORDINATOR */
57 :
58 : /** Accept the request to read the SIRK as plaintext */
59 1 : #define BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT 0x00
60 : /** Accept the request to read the SIRK, but return encrypted SIRK */
61 1 : #define BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT_ENC 0x01
62 : /** Reject the request to read the SIRK */
63 1 : #define BT_CSIP_READ_SIRK_REQ_RSP_REJECT 0x02
64 : /** SIRK is available only via an OOB procedure */
65 1 : #define BT_CSIP_READ_SIRK_REQ_RSP_OOB_ONLY 0x03
66 :
67 : /** Size of the Set Identification Resolving Key (SIRK) */
68 1 : #define BT_CSIP_SIRK_SIZE 16
69 :
70 : /** Size of the Resolvable Set Identifier (RSI) */
71 1 : #define BT_CSIP_RSI_SIZE 6
72 :
73 : /* Coordinate Set Identification Service Error codes */
74 : /** Service is already locked */
75 1 : #define BT_CSIP_ERROR_LOCK_DENIED 0x80
76 : /** Service is not locked */
77 1 : #define BT_CSIP_ERROR_LOCK_RELEASE_DENIED 0x81
78 : /** Invalid lock value */
79 1 : #define BT_CSIP_ERROR_LOCK_INVAL_VALUE 0x82
80 : /** SIRK only available out-of-band */
81 1 : #define BT_CSIP_ERROR_SIRK_OOB_ONLY 0x83
82 : /** Client is already owner of the lock */
83 1 : #define BT_CSIP_ERROR_LOCK_ALREADY_GRANTED 0x84
84 :
85 : /**
86 : * @brief Helper to declare bt_data array including RSI
87 : *
88 : * This macro is mainly for creating an array of struct bt_data
89 : * elements which is then passed to e.g. @ref bt_le_ext_adv_start().
90 : *
91 : * @param _rsi Pointer to the RSI value
92 : */
93 1 : #define BT_CSIP_DATA_RSI(_rsi) BT_DATA(BT_DATA_CSIS_RSI, _rsi, BT_CSIP_RSI_SIZE)
94 :
95 : /** @brief Opaque Coordinated Set Identification Service instance. */
96 : struct bt_csip_set_member_svc_inst;
97 :
98 : /** Callback structure for the Coordinated Set Identification Service */
99 1 : struct bt_csip_set_member_cb {
100 : /**
101 : * @brief Callback whenever the lock changes on the server.
102 : *
103 : * @param conn The connection to the client that changed the lock.
104 : * NULL if server changed it, either by calling
105 : * bt_csip_set_member_lock() or by timeout.
106 : * @param svc_inst Pointer to the Coordinated Set Identification
107 : * Service.
108 : * @param locked Whether the lock was locked or released.
109 : *
110 : */
111 1 : void (*lock_changed)(struct bt_conn *conn,
112 : struct bt_csip_set_member_svc_inst *svc_inst,
113 : bool locked);
114 :
115 : /**
116 : * @brief Request from a peer device to read the sirk.
117 : *
118 : * If this callback is not set, all clients will be allowed to read
119 : * the SIRK unencrypted.
120 : *
121 : * @param conn The connection to the client that requested to read
122 : * the SIRK.
123 : * @param svc_inst Pointer to the Coordinated Set Identification
124 : * Service.
125 : *
126 : * @return A BT_CSIP_READ_SIRK_REQ_RSP_* response code.
127 : */
128 1 : uint8_t (*sirk_read_req)(struct bt_conn *conn,
129 : struct bt_csip_set_member_svc_inst *svc_inst);
130 : };
131 :
132 : /** Register structure for Coordinated Set Identification Service */
133 1 : struct bt_csip_set_member_register_param {
134 : /**
135 : * @brief Size of the set.
136 : *
137 : * If set to 0, the set size characteristic won't be initialized.
138 : */
139 1 : uint8_t set_size;
140 :
141 : /**
142 : * @brief The unique Set Identity Resolving Key (SIRK)
143 : *
144 : * This shall be unique between different sets, and shall be the same
145 : * for each set member for each set.
146 : */
147 1 : uint8_t sirk[BT_CSIP_SIRK_SIZE];
148 :
149 : /**
150 : * @brief Boolean to set whether the set is lockable by clients
151 : *
152 : * Setting this to false will disable the lock characteristic.
153 : */
154 1 : bool lockable;
155 :
156 : /**
157 : * @brief Rank of this device in this set.
158 : *
159 : * If the lockable parameter is set to true, this shall be > 0 and
160 : * <= to the set_size. If the lockable parameter is set to false, this
161 : * may be set to 0 to disable the rank characteristic.
162 : */
163 1 : uint8_t rank;
164 :
165 : /** Pointer to the callback structure. */
166 1 : struct bt_csip_set_member_cb *cb;
167 :
168 : #if CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT > 1 || defined(__DOXYGEN__)
169 : /**
170 : * @brief Parent service pointer
171 : *
172 : * Mandatory parent service pointer if this CSIS instance is included
173 : * by another service. All CSIS instances when
174 : * @kconfig{CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT} is above 1
175 : * shall be included by another service, as per the
176 : * Coordinated Set Identification Profile (CSIP).
177 : */
178 1 : const struct bt_gatt_service *parent;
179 : #endif /* CONFIG_BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT > 1 */
180 : };
181 :
182 : /**
183 : * @brief Get the service declaration attribute.
184 : *
185 : * The first service attribute can be included in any other GATT service.
186 : *
187 : * @param svc_inst Pointer to the Coordinated Set Identification Service.
188 : *
189 : * @return The first CSIS attribute instance.
190 : */
191 1 : void *bt_csip_set_member_svc_decl_get(const struct bt_csip_set_member_svc_inst *svc_inst);
192 :
193 : /**
194 : * @brief Register a Coordinated Set Identification Service instance.
195 : *
196 : * This will register and enable the service and make it discoverable by
197 : * clients.
198 : *
199 : * This shall only be done as a server.
200 : *
201 : * @param param Coordinated Set Identification Service register
202 : * parameters.
203 : * @param[out] svc_inst Pointer to the registered Coordinated Set
204 : * Identification Service.
205 : *
206 : * @return 0 if success, errno on failure.
207 : */
208 1 : int bt_csip_set_member_register(const struct bt_csip_set_member_register_param *param,
209 : struct bt_csip_set_member_svc_inst **svc_inst);
210 :
211 : /**
212 : * @brief Unregister a Coordinated Set Identification Service instance.
213 : *
214 : * This will unregister and disable the service instance.
215 : *
216 : * @param svc_inst Pointer to the registered Coordinated Set Identification Service.
217 : *
218 : * @return 0 if success, errno on failure.
219 : */
220 1 : int bt_csip_set_member_unregister(struct bt_csip_set_member_svc_inst *svc_inst);
221 :
222 : /**
223 : * @brief Set the SIRK of a service instance
224 : *
225 : * @param svc_inst Pointer to the registered Coordinated Set Identification Service.
226 : * @param sirk The new SIRK.
227 : */
228 1 : int bt_csip_set_member_sirk(struct bt_csip_set_member_svc_inst *svc_inst,
229 : const uint8_t sirk[BT_CSIP_SIRK_SIZE]);
230 :
231 : /**
232 : * @brief Get the SIRK of a service instance
233 : *
234 : * @param[in] svc_inst Pointer to the registered Coordinated Set Identification Service.
235 : * @param[out] sirk Array to store the SIRK in.
236 : */
237 1 : int bt_csip_set_member_get_sirk(struct bt_csip_set_member_svc_inst *svc_inst,
238 : uint8_t sirk[BT_CSIP_SIRK_SIZE]);
239 :
240 : /**
241 : * @brief Generate the Resolvable Set Identifier (RSI) value.
242 : *
243 : * This will generate RSI for given @p svc_inst instance.
244 : *
245 : * @param svc_inst Pointer to the Coordinated Set Identification Service.
246 : * @param rsi Pointer to the 6-octet newly generated RSI data in little-endian.
247 : *
248 : * @return int 0 if on success, errno on error.
249 : */
250 1 : int bt_csip_set_member_generate_rsi(const struct bt_csip_set_member_svc_inst *svc_inst,
251 : uint8_t rsi[BT_CSIP_RSI_SIZE]);
252 :
253 : /**
254 : * @brief Locks a specific Coordinated Set Identification Service instance on the server.
255 : *
256 : * @param svc_inst Pointer to the Coordinated Set Identification Service.
257 : * @param lock If true lock the set, if false release the set.
258 : * @param force This argument only have meaning when @p lock is false
259 : * (release) and will force release the lock, regardless of who
260 : * took the lock.
261 : *
262 : * @return 0 on success, GATT error on error.
263 : */
264 1 : int bt_csip_set_member_lock(struct bt_csip_set_member_svc_inst *svc_inst,
265 : bool lock, bool force);
266 :
267 : /** Information about a specific set */
268 1 : struct bt_csip_set_coordinator_set_info {
269 : /**
270 : * @brief The 16 octet set Set Identity Resolving Key (SIRK)
271 : *
272 : * The SIRK may not be exposed by the server over Bluetooth, and
273 : * may require an out-of-band solution.
274 : */
275 1 : uint8_t sirk[BT_CSIP_SIRK_SIZE];
276 :
277 : /**
278 : * @brief The size of the set
279 : *
280 : * Will be 0 if not exposed by the server.
281 : */
282 1 : uint8_t set_size;
283 :
284 : /**
285 : * @brief The rank of the set on the remote device
286 : *
287 : * Will be 0 if not exposed by the server.
288 : */
289 1 : uint8_t rank;
290 :
291 : /** Whether or not the set can be locked on this device */
292 1 : bool lockable;
293 : };
294 :
295 : /**
296 : * @brief Struct representing a coordinated set instance on a remote device
297 : *
298 : * The values in this struct will be populated during discovery of sets
299 : * (bt_csip_set_coordinator_discover()).
300 : */
301 1 : struct bt_csip_set_coordinator_csis_inst {
302 : /** Information about the coordinated set */
303 1 : struct bt_csip_set_coordinator_set_info info;
304 :
305 : /** Internally used pointer value */
306 1 : void *svc_inst;
307 : };
308 :
309 : /** Struct representing a remote device as a set member */
310 1 : struct bt_csip_set_coordinator_set_member {
311 : /** Array of Coordinated Set Identification Service instances for the remote device */
312 1 : struct bt_csip_set_coordinator_csis_inst insts[BT_CSIP_SET_COORDINATOR_MAX_CSIS_INSTANCES];
313 : };
314 :
315 : /**
316 : * @typedef bt_csip_set_coordinator_discover_cb
317 : * @brief Callback for discovering Coordinated Set Identification Services.
318 : *
319 : * @param conn Pointer to the remote device.
320 : * @param member Pointer to the set member.
321 : * @param err 0 on success, or an errno value on error.
322 : * @param set_count Number of sets on the member.
323 : */
324 1 : typedef void (*bt_csip_set_coordinator_discover_cb)(
325 : struct bt_conn *conn,
326 : const struct bt_csip_set_coordinator_set_member *member,
327 : int err, size_t set_count);
328 :
329 : /**
330 : * @brief Initialise the csip_set_coordinator instance for a connection. This will do a
331 : * discovery on the device and prepare the instance for following commands.
332 : *
333 : * @param conn Pointer to remote device to perform discovery on.
334 : *
335 : * @return int Return 0 on success, or an errno value on error.
336 : */
337 1 : int bt_csip_set_coordinator_discover(struct bt_conn *conn);
338 :
339 : /**
340 : * @brief Get the set member from a connection pointer
341 : *
342 : * Get the Coordinated Set Identification Profile Set Coordinator pointer from a connection pointer.
343 : * Only Set Coordinators that have been initiated via bt_csip_set_coordinator_discover() can be
344 : * retrieved.
345 : *
346 : * @param conn Connection pointer.
347 : *
348 : * @retval Pointer to a Coordinated Set Identification Profile Set Coordinator instance
349 : * @retval NULL if @p conn is NULL or if the connection has not done discovery yet
350 : */
351 : struct bt_csip_set_coordinator_set_member *
352 1 : bt_csip_set_coordinator_set_member_by_conn(const struct bt_conn *conn);
353 :
354 : /**
355 : * @typedef bt_csip_set_coordinator_lock_set_cb
356 : * @brief Callback for locking a set across one or more devices
357 : *
358 : * @param err 0 on success, or an errno value on error.
359 : */
360 1 : typedef void (*bt_csip_set_coordinator_lock_set_cb)(int err);
361 :
362 : /**
363 : * @typedef bt_csip_set_coordinator_lock_changed_cb
364 : * @brief Callback when the lock value on a set of a connected device changes.
365 : *
366 : * @param inst The Coordinated Set Identification Service instance that was
367 : * changed.
368 : * @param locked Whether the lock is locked or release.
369 : *
370 : * @return int Return 0 on success, or an errno value on error.
371 : */
372 1 : typedef void (*bt_csip_set_coordinator_lock_changed_cb)(
373 : struct bt_csip_set_coordinator_csis_inst *inst, bool locked);
374 :
375 : /**
376 : * @typedef bt_csip_set_coordinator_sirk_changed_cb
377 : * @brief Callback when the SIRK value of a set of a connected device changes.
378 : *
379 : * @param inst The Coordinated Set Identification Service instance that was changed.
380 : * The new SIRK can be accessed via the @p inst.info.
381 : */
382 1 : typedef void (*bt_csip_set_coordinator_sirk_changed_cb)(
383 : struct bt_csip_set_coordinator_csis_inst *inst);
384 :
385 : /**
386 : * @typedef bt_csip_set_coordinator_ordered_access_cb_t
387 : * @brief Callback for bt_csip_set_coordinator_ordered_access()
388 : *
389 : * If any of the set members supplied to bt_csip_set_coordinator_ordered_access() is
390 : * in the locked state, this will be called with @p locked true and @p member
391 : * will be the locked member, and the ordered access procedure is cancelled.
392 : * Likewise, if any error occurs, the procedure will also be aborted.
393 : *
394 : * @param set_info Pointer to the a specific set_info struct.
395 : * @param err Error value. 0 on success, GATT error or errno on fail.
396 : * @param locked Whether the lock is locked or release.
397 : * @param member The locked member if @p locked is true, otherwise NULL.
398 : */
399 1 : typedef void (*bt_csip_set_coordinator_ordered_access_cb_t)(
400 : const struct bt_csip_set_coordinator_set_info *set_info,
401 : int err, bool locked,
402 : struct bt_csip_set_coordinator_set_member *member);
403 :
404 : /**
405 : * @brief Struct to hold the Coordinated Set Identification Profile Set Coordinator callbacks
406 : *
407 : * These can be registered for usage with bt_csip_set_coordinator_register_cb().
408 : */
409 1 : struct bt_csip_set_coordinator_cb {
410 : /** Callback when discovery has finished */
411 1 : bt_csip_set_coordinator_discover_cb discover;
412 : /** Callback when locking a set has finished */
413 1 : bt_csip_set_coordinator_lock_set_cb lock_set;
414 : /** Callback when unlocking a set has finished */
415 1 : bt_csip_set_coordinator_lock_set_cb release_set;
416 : /** Callback when a set's lock state has changed */
417 1 : bt_csip_set_coordinator_lock_changed_cb lock_changed;
418 : /** Callback when a set's SIRK has changed */
419 1 : bt_csip_set_coordinator_sirk_changed_cb sirk_changed;
420 : /** Callback for the ordered access procedure */
421 1 : bt_csip_set_coordinator_ordered_access_cb_t ordered_access;
422 :
423 : /** @internal Internally used field for list handling */
424 : sys_snode_t _node;
425 : };
426 :
427 : /**
428 : * @brief Check if advertising data indicates a set member
429 : *
430 : * @param sirk The SIRK of the set to check against
431 : * @param data The advertising data
432 : *
433 : * @return true if the advertising data indicates a set member, false otherwise
434 : */
435 1 : bool bt_csip_set_coordinator_is_set_member(const uint8_t sirk[BT_CSIP_SIRK_SIZE],
436 : struct bt_data *data);
437 :
438 : /**
439 : * @brief Registers callbacks for csip_set_coordinator.
440 : *
441 : * @param cb Pointer to the callback structure.
442 : *
443 : * @return Return 0 on success, or an errno value on error.
444 : */
445 1 : int bt_csip_set_coordinator_register_cb(struct bt_csip_set_coordinator_cb *cb);
446 :
447 : /**
448 : * @brief Callback function definition for bt_csip_set_coordinator_ordered_access()
449 : *
450 : * @param set_info Pointer to the a specific set_info struct.
451 : * @param members Array of members ordered by rank. The procedure shall be
452 : * done on the members in ascending order.
453 : * @param count Number of members in @p members.
454 : *
455 : * @return true if the procedures can be successfully done, or false to stop the
456 : * procedure.
457 : */
458 1 : typedef bool (*bt_csip_set_coordinator_ordered_access_t)(
459 : const struct bt_csip_set_coordinator_set_info *set_info,
460 : struct bt_csip_set_coordinator_set_member *members[],
461 : size_t count);
462 :
463 : /**
464 : * @brief Access Coordinated Set devices in an ordered manner as a client
465 : *
466 : * This function will read the lock state of all devices and if all devices are
467 : * in the unlocked state, then @p cb will be called with the same members as
468 : * provided by @p members, but where the members are ordered by rank
469 : * (if present). Once this procedure is finished or an error occurs,
470 : * @ref bt_csip_set_coordinator_cb.ordered_access will be called.
471 : *
472 : * This procedure only works if all the members have the lock characteristic,
473 : * and all either has rank = 0 or unique ranks.
474 : *
475 : * If any of the members are in the locked state, the procedure will be
476 : * cancelled.
477 : *
478 : * This can only be done on members that are bonded.
479 : *
480 : * @param members Array of set members to access.
481 : * @param count Number of set members in @p members.
482 : * @param set_info Pointer to the a specific set_info struct, as a member may
483 : * be part of multiple sets.
484 : * @param cb The callback function to be called for each member.
485 : */
486 1 : int bt_csip_set_coordinator_ordered_access(
487 : const struct bt_csip_set_coordinator_set_member *members[],
488 : uint8_t count,
489 : const struct bt_csip_set_coordinator_set_info *set_info,
490 : bt_csip_set_coordinator_ordered_access_t cb);
491 :
492 : /**
493 : * @brief Lock an array of set members
494 : *
495 : * The members will be locked starting from lowest rank going up.
496 : *
497 : * @kconfig_dep{CONFIG_BT_CSIP_SET_COORDINATOR,CONFIG_BT_BONDABLE}
498 : *
499 : * TODO: If locking fails, the already locked members will not be unlocked.
500 : *
501 : * @param members Array of set members to lock.
502 : * @param count Number of set members in @p members.
503 : * @param set_info Pointer to the a specific set_info struct, as a member may
504 : * be part of multiple sets.
505 : *
506 : * @return Return 0 on success, or an errno value on error.
507 : */
508 1 : int bt_csip_set_coordinator_lock(const struct bt_csip_set_coordinator_set_member **members,
509 : uint8_t count,
510 : const struct bt_csip_set_coordinator_set_info *set_info);
511 :
512 : /**
513 : * @brief Release an array of set members
514 : *
515 : * The members will be released starting from highest rank going down.
516 : *
517 : * @kconfig_dep{CONFIG_BT_CSIP_SET_COORDINATOR,CONFIG_BT_BONDABLE}
518 : *
519 : * @param members Array of set members to lock.
520 : * @param count Number of set members in @p members.
521 : * @param set_info Pointer to the a specific set_info struct, as a member may
522 : * be part of multiple sets.
523 : *
524 : * @return Return 0 on success, or an errno value on error.
525 : */
526 1 : int bt_csip_set_coordinator_release(const struct bt_csip_set_coordinator_set_member **members,
527 : uint8_t count,
528 : const struct bt_csip_set_coordinator_set_info *set_info);
529 :
530 : #ifdef __cplusplus
531 : }
532 : #endif
533 :
534 : /**
535 : * @}
536 : */
537 :
538 : #endif /* ZEPHYR_SUBSYS_BLUETOOTH_AUDIO_CSIP_H_ */
|