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_gatt_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 #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 #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 #define BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT        0x00
60 /** Accept the request to read the SIRK, but return encrypted SIRK */
61 #define BT_CSIP_READ_SIRK_REQ_RSP_ACCEPT_ENC    0x01
62 /** Reject the request to read the SIRK */
63 #define BT_CSIP_READ_SIRK_REQ_RSP_REJECT        0x02
64 /** SIRK is available only via an OOB procedure */
65 #define BT_CSIP_READ_SIRK_REQ_RSP_OOB_ONLY      0x03
66 
67 /** Size of the Set Identification Resolving Key (SIRK) */
68 #define BT_CSIP_SIRK_SIZE 16
69 
70 /** Size of the Resolvable Set Identifier (RSI) */
71 #define BT_CSIP_RSI_SIZE                        6
72 
73 /* Coordinate Set Identification Service Error codes */
74 /** Service is already locked */
75 #define BT_CSIP_ERROR_LOCK_DENIED               0x80
76 /** Service is not locked */
77 #define BT_CSIP_ERROR_LOCK_RELEASE_DENIED       0x81
78 /** Invalid lock value */
79 #define BT_CSIP_ERROR_LOCK_INVAL_VALUE          0x82
80 /** SIRK only available out-of-band */
81 #define BT_CSIP_ERROR_SIRK_OOB_ONLY             0x83
82 /** Client is already owner of the lock */
83 #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 #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 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 	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 	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 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 	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 	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 	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 	uint8_t rank;
164 
165 	/** Pointer to the callback structure. */
166 	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 	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 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 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 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 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 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 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 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 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 	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 	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 	uint8_t rank;
290 
291 	/** Whether or not the set can be locked on this device */
292 	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 struct bt_csip_set_coordinator_csis_inst {
302 	/** Information about the coordinated set */
303 	struct bt_csip_set_coordinator_set_info info;
304 
305 	/** Internally used pointer value */
306 	void *svc_inst;
307 };
308 
309 /** Struct representing a remote device as a set member */
310 struct bt_csip_set_coordinator_set_member {
311 	/** Array of Coordinated Set Identification Service instances for the remote device */
312 	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 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 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 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 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 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 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 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 struct bt_csip_set_coordinator_cb {
410 	/** Callback when discovery has finished */
411 	bt_csip_set_coordinator_discover_cb discover;
412 	/** Callback when locking a set has finished */
413 	bt_csip_set_coordinator_lock_set_cb lock_set;
414 	/** Callback when unlocking a set has finished */
415 	bt_csip_set_coordinator_lock_set_cb release_set;
416 	/** Callback when a set's lock state has changed */
417 	bt_csip_set_coordinator_lock_changed_cb lock_changed;
418 	/** Callback when a set's SIRK has changed */
419 	bt_csip_set_coordinator_sirk_changed_cb sirk_changed;
420 	/** Callback for the ordered access procedure */
421 	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 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 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 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 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  * TODO: If locking fails, the already locked members will not be unlocked.
498  *
499  * @param members   Array of set members to lock.
500  * @param count     Number of set members in @p members.
501  * @param set_info  Pointer to the a specific set_info struct, as a member may
502  *                  be part of multiple sets.
503  *
504  * @return Return 0 on success, or an errno value on error.
505  */
506 int bt_csip_set_coordinator_lock(const struct bt_csip_set_coordinator_set_member **members,
507 				 uint8_t count,
508 				 const struct bt_csip_set_coordinator_set_info *set_info);
509 
510 /**
511  * @brief Release an array of set members
512  *
513  * The members will be released starting from highest rank going down.
514  *
515  * @param members   Array of set members to lock.
516  * @param count     Number of set members in @p members.
517  * @param set_info  Pointer to the a specific set_info struct, as a member may
518  *                  be part of multiple sets.
519  *
520  * @return Return 0 on success, or an errno value on error.
521  */
522 int bt_csip_set_coordinator_release(const struct bt_csip_set_coordinator_set_member **members,
523 				    uint8_t count,
524 				    const struct bt_csip_set_coordinator_set_info *set_info);
525 
526 #ifdef __cplusplus
527 }
528 #endif
529 
530 /**
531  * @}
532  */
533 
534 #endif /* ZEPHYR_SUBSYS_BLUETOOTH_AUDIO_CSIP_H_ */
535