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