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