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