1 /* 2 * Copyright (C) 2014 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define __BTSTACK_FILE__ "att_db.c" 39 40 41 #include <stdio.h> 42 #include <string.h> 43 44 #include "ble/att_db.h" 45 #include "ble/core.h" 46 #include "bluetooth.h" 47 #include "btstack_debug.h" 48 #include "btstack_util.h" 49 50 // Buetooth Base UUID 00000000-0000-1000-8000-00805F9B34FB in little endian 51 static const uint8_t bluetooth_base_uuid[] = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 52 53 54 static int is_Bluetooth_Base_UUID(uint8_t const *uuid){ 55 if (memcmp(&uuid[0], &bluetooth_base_uuid[0], 12)) return 0; 56 if (memcmp(&uuid[14], &bluetooth_base_uuid[14], 2)) return 0; 57 return 1; 58 59 } 60 61 static uint16_t uuid16_from_uuid(uint16_t uuid_len, uint8_t * uuid){ 62 if (uuid_len == 2) return little_endian_read_16(uuid, 0); 63 if (!is_Bluetooth_Base_UUID(uuid)) return 0; 64 return little_endian_read_16(uuid, 12); 65 } 66 67 // ATT Database 68 69 // new java-style iterator 70 typedef struct att_iterator { 71 // private 72 uint8_t const * att_ptr; 73 // public 74 uint16_t size; 75 uint16_t flags; 76 uint16_t handle; 77 uint8_t const * uuid; 78 uint16_t value_len; 79 uint8_t const * value; 80 } att_iterator_t; 81 82 static void att_persistent_ccc_cache(att_iterator_t * it); 83 84 static uint8_t const * att_db = NULL; 85 static att_read_callback_t att_read_callback = NULL; 86 static att_write_callback_t att_write_callback = NULL; 87 static uint8_t att_prepare_write_error_code = 0; 88 static uint16_t att_prepare_write_error_handle = 0x0000; 89 90 // single cache for att_is_persistent_ccc - stores flags before write callback 91 static uint16_t att_persistent_ccc_handle; 92 static uint16_t att_persistent_ccc_uuid16; 93 94 static void att_iterator_init(att_iterator_t *it){ 95 it->att_ptr = att_db; 96 } 97 98 static int att_iterator_has_next(att_iterator_t *it){ 99 return it->att_ptr != NULL; 100 } 101 102 static void att_iterator_fetch_next(att_iterator_t *it){ 103 it->size = little_endian_read_16(it->att_ptr, 0); 104 if (it->size == 0){ 105 it->flags = 0; 106 it->handle = 0; 107 it->uuid = NULL; 108 it->value_len = 0; 109 it->value = NULL; 110 it->att_ptr = NULL; 111 return; 112 } 113 it->flags = little_endian_read_16(it->att_ptr, 2); 114 it->handle = little_endian_read_16(it->att_ptr, 4); 115 it->uuid = &it->att_ptr[6]; 116 // handle 128 bit UUIDs 117 if (it->flags & ATT_PROPERTY_UUID128){ 118 it->value_len = it->size - 22; 119 it->value = &it->att_ptr[22]; 120 } else { 121 it->value_len = it->size - 8; 122 it->value = &it->att_ptr[8]; 123 } 124 // advance AFTER setting values 125 it->att_ptr += it->size; 126 } 127 128 static int att_iterator_match_uuid16(att_iterator_t *it, uint16_t uuid){ 129 if (it->handle == 0) return 0; 130 if (it->flags & ATT_PROPERTY_UUID128){ 131 if (!is_Bluetooth_Base_UUID(it->uuid)) return 0; 132 return little_endian_read_16(it->uuid, 12) == uuid; 133 } 134 return little_endian_read_16(it->uuid, 0) == uuid; 135 } 136 137 static int att_iterator_match_uuid(att_iterator_t *it, uint8_t *uuid, uint16_t uuid_len){ 138 if (it->handle == 0) return 0; 139 // input: UUID16 140 if (uuid_len == 2) { 141 return att_iterator_match_uuid16(it, little_endian_read_16(uuid, 0)); 142 } 143 // input and db: UUID128 144 if (it->flags & ATT_PROPERTY_UUID128){ 145 return memcmp(it->uuid, uuid, 16) == 0; 146 } 147 // input: UUID128, db: UUID16 148 if (!is_Bluetooth_Base_UUID(uuid)) return 0; 149 return little_endian_read_16(uuid, 12) == little_endian_read_16(it->uuid, 0); 150 } 151 152 153 static int att_find_handle(att_iterator_t *it, uint16_t handle){ 154 if (handle == 0) return 0; 155 att_iterator_init(it); 156 while (att_iterator_has_next(it)){ 157 att_iterator_fetch_next(it); 158 if (it->handle != handle) continue; 159 return 1; 160 } 161 return 0; 162 } 163 164 // experimental client API 165 uint16_t att_uuid_for_handle(uint16_t attribute_handle){ 166 att_iterator_t it; 167 int ok = att_find_handle(&it, attribute_handle); 168 if (!ok) return 0; 169 if (it.flags & ATT_PROPERTY_UUID128) return 0; 170 return little_endian_read_16(it.uuid, 0); 171 } 172 // end of client API 173 174 static void att_update_value_len(att_iterator_t *it, hci_con_handle_t con_handle){ 175 if ((it->flags & ATT_PROPERTY_DYNAMIC) == 0) return; 176 it->value_len = (*att_read_callback)(con_handle, it->handle, 0, NULL, 0); 177 return; 178 } 179 180 // copy attribute value from offset into buffer with given size 181 static int att_copy_value(att_iterator_t *it, uint16_t offset, uint8_t * buffer, uint16_t buffer_size, hci_con_handle_t con_handle){ 182 183 // DYNAMIC 184 if (it->flags & ATT_PROPERTY_DYNAMIC){ 185 return (*att_read_callback)(con_handle, it->handle, offset, buffer, buffer_size); 186 } 187 188 // STATIC 189 uint16_t bytes_to_copy = it->value_len - offset; 190 if (bytes_to_copy > buffer_size){ 191 bytes_to_copy = buffer_size; 192 } 193 memcpy(buffer, it->value, bytes_to_copy); 194 return bytes_to_copy; 195 } 196 197 void att_set_db(uint8_t const * db){ 198 att_db = db; 199 } 200 201 void att_set_read_callback(att_read_callback_t callback){ 202 att_read_callback = callback; 203 } 204 205 void att_set_write_callback(att_write_callback_t callback){ 206 att_write_callback = callback; 207 } 208 209 void att_dump_attributes(void){ 210 att_iterator_t it; 211 att_iterator_init(&it); 212 uint8_t uuid128[16]; 213 while (att_iterator_has_next(&it)){ 214 att_iterator_fetch_next(&it); 215 if (it.handle == 0) { 216 log_info("Handle: END"); 217 return; 218 } 219 log_info("Handle: 0x%04x, flags: 0x%04x, uuid: ", it.handle, it.flags); 220 if (it.flags & ATT_PROPERTY_UUID128){ 221 reverse_128(it.uuid, uuid128); 222 log_info("%s", uuid128_to_str(uuid128)); 223 } else { 224 log_info("%04x", little_endian_read_16(it.uuid, 0)); 225 } 226 log_info(", value_len: %u, value: ", it.value_len); 227 log_info_hexdump(it.value, it.value_len); 228 } 229 } 230 231 static void att_prepare_write_reset(void){ 232 att_prepare_write_error_code = 0; 233 att_prepare_write_error_handle = 0x0000; 234 } 235 236 static void att_prepare_write_update_errors(uint8_t error_code, uint16_t handle){ 237 // first ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH has highest priority 238 if (error_code == ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH && error_code != att_prepare_write_error_code){ 239 att_prepare_write_error_code = error_code; 240 att_prepare_write_error_handle = handle; 241 return; 242 } 243 // first ATT_ERROR_INVALID_OFFSET is next 244 if (error_code == ATT_ERROR_INVALID_OFFSET && att_prepare_write_error_code == 0){ 245 att_prepare_write_error_code = error_code; 246 att_prepare_write_error_handle = handle; 247 return; 248 } 249 } 250 251 static uint16_t setup_error(uint8_t * response_buffer, uint16_t request, uint16_t handle, uint8_t error_code){ 252 response_buffer[0] = ATT_ERROR_RESPONSE; 253 response_buffer[1] = request; 254 little_endian_store_16(response_buffer, 2, handle); 255 response_buffer[4] = error_code; 256 return 5; 257 } 258 259 static inline uint16_t setup_error_read_not_permitted(uint8_t * response_buffer, uint16_t request, uint16_t start_handle){ 260 return setup_error(response_buffer, request, start_handle, ATT_ERROR_READ_NOT_PERMITTED); 261 } 262 263 static inline uint16_t setup_error_write_not_permitted(uint8_t * response_buffer, uint16_t request, uint16_t start_handle){ 264 return setup_error(response_buffer, request, start_handle, ATT_ERROR_WRITE_NOT_PERMITTED); 265 } 266 267 static inline uint16_t setup_error_atribute_not_found(uint8_t * response_buffer, uint16_t request, uint16_t start_handle){ 268 return setup_error(response_buffer, request, start_handle, ATT_ERROR_ATTRIBUTE_NOT_FOUND); 269 } 270 271 static inline uint16_t setup_error_invalid_handle(uint8_t * response_buffer, uint16_t request, uint16_t handle){ 272 return setup_error(response_buffer, request, handle, ATT_ERROR_INVALID_HANDLE); 273 } 274 275 static inline uint16_t setup_error_invalid_offset(uint8_t * response_buffer, uint16_t request, uint16_t handle){ 276 return setup_error(response_buffer, request, handle, ATT_ERROR_INVALID_OFFSET); 277 } 278 279 static uint8_t att_validate_security(att_connection_t * att_connection, att_iterator_t * it){ 280 int required_encryption_size = it->flags >> 12; 281 if (required_encryption_size) required_encryption_size++; // store -1 to fit into 4 bit 282 log_debug("att_validate_security. flags 0x%04x - req enc size %u, authorized %u, authenticated %u, encryption_key_size %u", 283 it->flags, required_encryption_size, att_connection->authorized, att_connection->authenticated, att_connection->encryption_key_size); 284 if ((it->flags & ATT_PROPERTY_AUTHENTICATION_REQUIRED) && att_connection->authenticated == 0) { 285 return ATT_ERROR_INSUFFICIENT_AUTHENTICATION; 286 } 287 if ((it->flags & ATT_PROPERTY_AUTHORIZATION_REQUIRED) && att_connection->authorized == 0) { 288 return ATT_ERROR_INSUFFICIENT_AUTHORIZATION; 289 } 290 if (required_encryption_size > 0 && att_connection->encryption_key_size == 0){ 291 return ATT_ERROR_INSUFFICIENT_ENCRYPTION; 292 } 293 if (required_encryption_size > att_connection->encryption_key_size){ 294 return ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE; 295 } 296 return 0; 297 } 298 299 // 300 // MARK: ATT_EXCHANGE_MTU_REQUEST 301 // 302 static uint16_t handle_exchange_mtu_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 303 uint8_t * response_buffer){ 304 305 UNUSED(request_len); 306 307 uint16_t client_rx_mtu = little_endian_read_16(request_buffer, 1); 308 309 // find min(local max mtu, remote mtu) and use as mtu for this connection 310 if (client_rx_mtu < att_connection->max_mtu){ 311 att_connection->mtu = client_rx_mtu; 312 } else { 313 att_connection->mtu = att_connection->max_mtu; 314 } 315 316 response_buffer[0] = ATT_EXCHANGE_MTU_RESPONSE; 317 little_endian_store_16(response_buffer, 1, att_connection->mtu); 318 return 3; 319 } 320 321 322 // 323 // MARK: ATT_FIND_INFORMATION_REQUEST 324 // 325 // TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID 326 // 327 static uint16_t handle_find_information_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, 328 uint16_t start_handle, uint16_t end_handle){ 329 330 UNUSED(att_connection); 331 332 log_info("ATT_FIND_INFORMATION_REQUEST: from %04X to %04X", start_handle, end_handle); 333 uint8_t request_type = ATT_FIND_INFORMATION_REQUEST; 334 335 if (start_handle > end_handle || start_handle == 0){ 336 return setup_error_invalid_handle(response_buffer, request_type, start_handle); 337 } 338 339 uint16_t offset = 1; 340 uint16_t uuid_len = 0; 341 342 att_iterator_t it; 343 att_iterator_init(&it); 344 while (att_iterator_has_next(&it)){ 345 att_iterator_fetch_next(&it); 346 if (!it.handle) break; 347 if (it.handle > end_handle) break; 348 if (it.handle < start_handle) continue; 349 350 // log_info("Handle 0x%04x", it.handle); 351 352 uint16_t this_uuid_len = (it.flags & ATT_PROPERTY_UUID128) ? 16 : 2; 353 354 // check if value has same len as last one if not first result 355 if (offset > 1){ 356 if (this_uuid_len != uuid_len) { 357 break; 358 } 359 } 360 361 // first 362 if (offset == 1) { 363 uuid_len = this_uuid_len; 364 // set format field 365 response_buffer[offset] = (it.flags & ATT_PROPERTY_UUID128) ? 0x02 : 0x01; 366 offset++; 367 } 368 369 // space? 370 if (offset + 2 + uuid_len > response_buffer_size) break; 371 372 // store 373 little_endian_store_16(response_buffer, offset, it.handle); 374 offset += 2; 375 376 memcpy(response_buffer + offset, it.uuid, uuid_len); 377 offset += uuid_len; 378 } 379 380 if (offset == 1){ 381 return setup_error_atribute_not_found(response_buffer, request_type, start_handle); 382 } 383 384 response_buffer[0] = ATT_FIND_INFORMATION_REPLY; 385 return offset; 386 } 387 388 static uint16_t handle_find_information_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 389 uint8_t * response_buffer, uint16_t response_buffer_size){ 390 UNUSED(request_len); 391 return handle_find_information_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), little_endian_read_16(request_buffer, 3)); 392 } 393 394 // 395 // MARK: ATT_FIND_BY_TYPE_VALUE 396 // 397 // "Only attributes with attribute handles between and including the Starting Handle parameter 398 // and the Ending Handle parameter that match the requested attri- bute type and the attribute 399 // value that have sufficient permissions to allow reading will be returned" -> (1) 400 // 401 // TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID 402 // 403 // NOTE: doesn't handle DYNAMIC values 404 // NOTE: only supports 16 bit UUIDs 405 // 406 static uint16_t handle_find_by_type_value_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, 407 uint16_t start_handle, uint16_t end_handle, 408 uint16_t attribute_type, uint16_t attribute_len, uint8_t* attribute_value){ 409 410 UNUSED(att_connection); 411 412 log_info("ATT_FIND_BY_TYPE_VALUE_REQUEST: from %04X to %04X, type %04X, value: ", start_handle, end_handle, attribute_type); 413 log_info_hexdump(attribute_value, attribute_len); 414 uint8_t request_type = ATT_FIND_BY_TYPE_VALUE_REQUEST; 415 416 if (start_handle > end_handle || start_handle == 0){ 417 return setup_error_invalid_handle(response_buffer, request_type, start_handle); 418 } 419 420 uint16_t offset = 1; 421 uint16_t in_group = 0; 422 uint16_t prev_handle = 0; 423 424 att_iterator_t it; 425 att_iterator_init(&it); 426 while (att_iterator_has_next(&it)){ 427 att_iterator_fetch_next(&it); 428 429 if (it.handle && it.handle < start_handle) continue; 430 if (it.handle > end_handle) break; // (1) 431 432 // close current tag, if within a group and a new service definition starts or we reach end of att db 433 if (in_group && 434 (it.handle == 0 || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){ 435 436 log_info("End of group, handle 0x%04x", prev_handle); 437 little_endian_store_16(response_buffer, offset, prev_handle); 438 offset += 2; 439 in_group = 0; 440 441 // check if space for another handle pair available 442 if (offset + 4 > response_buffer_size){ 443 break; 444 } 445 } 446 447 // keep track of previous handle 448 prev_handle = it.handle; 449 450 // does current attribute match 451 if (it.handle && att_iterator_match_uuid16(&it, attribute_type) && attribute_len == it.value_len && memcmp(attribute_value, it.value, it.value_len) == 0){ 452 log_info("Begin of group, handle 0x%04x", it.handle); 453 little_endian_store_16(response_buffer, offset, it.handle); 454 offset += 2; 455 in_group = 1; 456 } 457 } 458 459 if (offset == 1){ 460 return setup_error_atribute_not_found(response_buffer, request_type, start_handle); 461 } 462 463 response_buffer[0] = ATT_FIND_BY_TYPE_VALUE_RESPONSE; 464 return offset; 465 } 466 467 static uint16_t handle_find_by_type_value_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 468 uint8_t * response_buffer, uint16_t response_buffer_size){ 469 int attribute_len = request_len - 7; 470 return handle_find_by_type_value_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), 471 little_endian_read_16(request_buffer, 3), little_endian_read_16(request_buffer, 5), attribute_len, &request_buffer[7]); 472 } 473 474 // 475 // MARK: ATT_READ_BY_TYPE_REQUEST 476 // 477 static uint16_t handle_read_by_type_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, 478 uint16_t start_handle, uint16_t end_handle, 479 uint16_t attribute_type_len, uint8_t * attribute_type){ 480 481 log_info("ATT_READ_BY_TYPE_REQUEST: from %04X to %04X, type: ", start_handle, end_handle); 482 log_info_hexdump(attribute_type, attribute_type_len); 483 uint8_t request_type = ATT_READ_BY_TYPE_REQUEST; 484 485 if (start_handle > end_handle || start_handle == 0){ 486 return setup_error_invalid_handle(response_buffer, request_type, start_handle); 487 } 488 489 uint16_t offset = 1; 490 uint16_t pair_len = 0; 491 492 att_iterator_t it; 493 att_iterator_init(&it); 494 uint8_t error_code = 0; 495 uint16_t first_matching_but_unreadable_handle = 0; 496 497 while (att_iterator_has_next(&it)){ 498 att_iterator_fetch_next(&it); 499 500 if (!it.handle) break; 501 if (it.handle < start_handle) continue; 502 if (it.handle > end_handle) break; // (1) 503 504 // does current attribute match 505 if (!att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) continue; 506 507 // skip handles that cannot be read but rembember that there has been at least one 508 if ((it.flags & ATT_PROPERTY_READ) == 0) { 509 if (first_matching_but_unreadable_handle == 0) { 510 first_matching_but_unreadable_handle = it.handle; 511 } 512 continue; 513 } 514 515 // check security requirements 516 if ((it.flags & ATT_DB_FLAGS_READ_WITHOUT_AUTHENTICATION) == 0){ 517 error_code = att_validate_security(att_connection, &it); 518 if (error_code) break; 519 } 520 521 att_update_value_len(&it, att_connection->con_handle); 522 523 // check if value has same len as last one 524 uint16_t this_pair_len = 2 + it.value_len; 525 if (offset > 1){ 526 if (pair_len != this_pair_len) { 527 break; 528 } 529 } 530 531 // first 532 if (offset == 1) { 533 pair_len = this_pair_len; 534 response_buffer[offset] = pair_len; 535 offset++; 536 } 537 538 // space? 539 if (offset + pair_len > response_buffer_size) { 540 if (offset > 2) break; 541 it.value_len = response_buffer_size - 4; 542 response_buffer[1] = 2 + it.value_len; 543 } 544 545 // store 546 little_endian_store_16(response_buffer, offset, it.handle); 547 offset += 2; 548 uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len, att_connection->con_handle); 549 offset += bytes_copied; 550 } 551 552 // at least one attribute could be read 553 if (offset > 1){ 554 response_buffer[0] = ATT_READ_BY_TYPE_RESPONSE; 555 return offset; 556 } 557 558 // first attribute had an error 559 if (error_code){ 560 return setup_error(response_buffer, request_type, start_handle, error_code); 561 } 562 563 // no other errors, but all found attributes had been non-readable 564 if (first_matching_but_unreadable_handle){ 565 return setup_error_read_not_permitted(response_buffer, request_type, first_matching_but_unreadable_handle); 566 } 567 568 // attribute not found 569 return setup_error_atribute_not_found(response_buffer, request_type, start_handle); 570 } 571 572 static uint16_t handle_read_by_type_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 573 uint8_t * response_buffer, uint16_t response_buffer_size){ 574 int attribute_type_len; 575 if (request_len <= 7){ 576 attribute_type_len = 2; 577 } else { 578 attribute_type_len = 16; 579 } 580 return handle_read_by_type_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), little_endian_read_16(request_buffer, 3), attribute_type_len, &request_buffer[5]); 581 } 582 583 // 584 // MARK: ATT_READ_BY_TYPE_REQUEST 585 // 586 static uint16_t handle_read_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle){ 587 588 log_info("ATT_READ_REQUEST: handle %04x", handle); 589 uint8_t request_type = ATT_READ_REQUEST; 590 591 att_iterator_t it; 592 int ok = att_find_handle(&it, handle); 593 if (!ok){ 594 return setup_error_invalid_handle(response_buffer, request_type, handle); 595 } 596 597 // check if handle can be read 598 if ((it.flags & ATT_PROPERTY_READ) == 0) { 599 return setup_error_read_not_permitted(response_buffer, request_type, handle); 600 } 601 602 // check security requirements 603 if ((it.flags & ATT_DB_FLAGS_READ_WITHOUT_AUTHENTICATION) == 0){ 604 uint8_t error_code = att_validate_security(att_connection, &it); 605 if (error_code) { 606 return setup_error(response_buffer, request_type, handle, error_code); 607 } 608 } 609 610 att_update_value_len(&it, att_connection->con_handle); 611 612 uint16_t offset = 1; 613 // limit data 614 if (offset + it.value_len > response_buffer_size) { 615 it.value_len = response_buffer_size - 1; 616 } 617 618 // store 619 uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len, att_connection->con_handle); 620 offset += bytes_copied; 621 622 response_buffer[0] = ATT_READ_RESPONSE; 623 return offset; 624 } 625 626 static uint16_t handle_read_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 627 uint8_t * response_buffer, uint16_t response_buffer_size){ 628 UNUSED(request_len); 629 return handle_read_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1)); 630 } 631 632 // 633 // MARK: ATT_READ_BLOB_REQUEST 0x0c 634 // 635 static uint16_t handle_read_blob_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle, uint16_t value_offset){ 636 log_info("ATT_READ_BLOB_REQUEST: handle %04x, offset %u", handle, value_offset); 637 uint8_t request_type = ATT_READ_BLOB_REQUEST; 638 639 att_iterator_t it; 640 int ok = att_find_handle(&it, handle); 641 if (!ok){ 642 return setup_error_invalid_handle(response_buffer, request_type, handle); 643 } 644 645 // check if handle can be read 646 if ((it.flags & ATT_PROPERTY_READ) == 0) { 647 return setup_error_read_not_permitted(response_buffer, request_type, handle); 648 } 649 650 // check security requirements 651 if ((it.flags & ATT_DB_FLAGS_READ_WITHOUT_AUTHENTICATION) == 0){ 652 uint8_t error_code = att_validate_security(att_connection, &it); 653 if (error_code) { 654 return setup_error(response_buffer, request_type, handle, error_code); 655 } 656 } 657 658 att_update_value_len(&it, att_connection->con_handle); 659 660 if (value_offset > it.value_len){ 661 return setup_error_invalid_offset(response_buffer, request_type, handle); 662 } 663 664 // limit data 665 uint16_t offset = 1; 666 if (offset + it.value_len - value_offset > response_buffer_size) { 667 it.value_len = response_buffer_size - 1 + value_offset; 668 } 669 670 // store 671 uint16_t bytes_copied = att_copy_value(&it, value_offset, response_buffer + offset, it.value_len - value_offset, att_connection->con_handle); 672 offset += bytes_copied; 673 674 response_buffer[0] = ATT_READ_BLOB_RESPONSE; 675 return offset; 676 } 677 678 static uint16_t handle_read_blob_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 679 uint8_t * response_buffer, uint16_t response_buffer_size){ 680 UNUSED(request_len); 681 return handle_read_blob_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), little_endian_read_16(request_buffer, 3)); 682 } 683 684 // 685 // MARK: ATT_READ_MULTIPLE_REQUEST 0x0e 686 // 687 static uint16_t handle_read_multiple_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t num_handles, uint8_t * handles){ 688 log_info("ATT_READ_MULTIPLE_REQUEST: num handles %u", num_handles); 689 uint8_t request_type = ATT_READ_MULTIPLE_REQUEST; 690 691 // TODO: figure out which error to respond with 692 // if (num_handles < 2){ 693 // return setup_error(response_buffer, ATT_READ_MULTIPLE_REQUEST, handle, ???); 694 // } 695 696 uint16_t offset = 1; 697 698 int i; 699 uint8_t error_code = 0; 700 uint16_t handle = 0; 701 for (i=0;i<num_handles;i++){ 702 handle = little_endian_read_16(handles, i << 1); 703 704 if (handle == 0){ 705 return setup_error_invalid_handle(response_buffer, request_type, handle); 706 } 707 708 att_iterator_t it; 709 710 int ok = att_find_handle(&it, handle); 711 if (!ok){ 712 return setup_error_invalid_handle(response_buffer, request_type, handle); 713 } 714 715 // check if handle can be read 716 if ((it.flags & ATT_PROPERTY_READ) == 0) { 717 error_code = ATT_ERROR_READ_NOT_PERMITTED; 718 break; 719 } 720 721 // check security requirements 722 if ((it.flags & ATT_DB_FLAGS_READ_WITHOUT_AUTHENTICATION) == 0){ 723 error_code = att_validate_security(att_connection, &it); 724 if (error_code) break; 725 } 726 att_update_value_len(&it, att_connection->con_handle); 727 728 // limit data 729 if (offset + it.value_len > response_buffer_size) { 730 it.value_len = response_buffer_size - 1; 731 } 732 733 // store 734 uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len, att_connection->con_handle); 735 offset += bytes_copied; 736 } 737 738 if (error_code){ 739 return setup_error(response_buffer, request_type, handle, error_code); 740 } 741 742 response_buffer[0] = ATT_READ_MULTIPLE_RESPONSE; 743 return offset; 744 } 745 static uint16_t handle_read_multiple_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 746 uint8_t * response_buffer, uint16_t response_buffer_size){ 747 int num_handles = (request_len - 1) >> 1; 748 return handle_read_multiple_request2(att_connection, response_buffer, response_buffer_size, num_handles, &request_buffer[1]); 749 } 750 751 // 752 // MARK: ATT_READ_BY_GROUP_TYPE_REQUEST 0x10 753 // 754 // Only handles GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID 755 // Core v4.0, vol 3, part g, 2.5.3 756 // "The «Primary Service» and «Secondary Service» grouping types may be used in the Read By Group Type Request. 757 // The «Characteristic» grouping type shall not be used in the ATT Read By Group Type Request." 758 // 759 // NOTE: doesn't handle DYNAMIC values 760 // 761 // NOTE: we don't check for security as PRIMARY and SECONDAY SERVICE definition shouldn't be protected 762 // Core 4.0, vol 3, part g, 8.1 763 // "The list of services and characteristics that a device supports is not considered private or 764 // confidential information, and therefore the Service and Characteristic Discovery procedures 765 // shall always be permitted. " 766 // 767 static uint16_t handle_read_by_group_type_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, 768 uint16_t start_handle, uint16_t end_handle, 769 uint16_t attribute_type_len, uint8_t * attribute_type){ 770 771 UNUSED(att_connection); 772 773 log_info("ATT_READ_BY_GROUP_TYPE_REQUEST: from %04X to %04X, buffer size %u, type: ", start_handle, end_handle, response_buffer_size); 774 log_info_hexdump(attribute_type, attribute_type_len); 775 uint8_t request_type = ATT_READ_BY_GROUP_TYPE_REQUEST; 776 777 if (start_handle > end_handle || start_handle == 0){ 778 return setup_error_invalid_handle(response_buffer, request_type, start_handle); 779 } 780 781 // assert UUID is primary or secondary service uuid 782 uint16_t uuid16 = uuid16_from_uuid(attribute_type_len, attribute_type); 783 if (uuid16 != GATT_PRIMARY_SERVICE_UUID && uuid16 != GATT_SECONDARY_SERVICE_UUID){ 784 return setup_error(response_buffer, request_type, start_handle, ATT_ERROR_UNSUPPORTED_GROUP_TYPE); 785 } 786 787 uint16_t offset = 1; 788 uint16_t pair_len = 0; 789 uint16_t in_group = 0; 790 uint16_t group_start_handle = 0; 791 uint8_t const * group_start_value = NULL; 792 uint16_t prev_handle = 0; 793 794 att_iterator_t it; 795 att_iterator_init(&it); 796 while (att_iterator_has_next(&it)){ 797 att_iterator_fetch_next(&it); 798 799 if (it.handle && it.handle < start_handle) continue; 800 if (it.handle > end_handle) break; // (1) 801 802 // log_info("Handle 0x%04x", it.handle); 803 804 // close current tag, if within a group and a new service definition starts or we reach end of att db 805 if (in_group && 806 (it.handle == 0 || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){ 807 // log_info("End of group, handle 0x%04x, val_len: %u", prev_handle, pair_len - 4); 808 809 little_endian_store_16(response_buffer, offset, group_start_handle); 810 offset += 2; 811 little_endian_store_16(response_buffer, offset, prev_handle); 812 offset += 2; 813 memcpy(response_buffer + offset, group_start_value, pair_len - 4); 814 offset += pair_len - 4; 815 in_group = 0; 816 817 // check if space for another handle pair available 818 if (offset + pair_len > response_buffer_size){ 819 break; 820 } 821 } 822 823 // keep track of previous handle 824 prev_handle = it.handle; 825 826 // does current attribute match 827 // log_info("compare: %04x == %04x", *(uint16_t*) context->attribute_type, *(uint16_t*) uuid); 828 if (it.handle && att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) { 829 830 // check if value has same len as last one 831 uint16_t this_pair_len = 4 + it.value_len; 832 if (offset > 1){ 833 if (this_pair_len != pair_len) { 834 break; 835 } 836 } 837 838 // log_info("Begin of group, handle 0x%04x", it.handle); 839 840 // first 841 if (offset == 1) { 842 pair_len = this_pair_len; 843 response_buffer[offset] = this_pair_len; 844 offset++; 845 } 846 847 group_start_handle = it.handle; 848 group_start_value = it.value; 849 in_group = 1; 850 } 851 } 852 853 if (offset == 1){ 854 return setup_error_atribute_not_found(response_buffer, request_type, start_handle); 855 } 856 857 response_buffer[0] = ATT_READ_BY_GROUP_TYPE_RESPONSE; 858 return offset; 859 } 860 static uint16_t handle_read_by_group_type_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 861 uint8_t * response_buffer, uint16_t response_buffer_size){ 862 int attribute_type_len; 863 if (request_len <= 7){ 864 attribute_type_len = 2; 865 } else { 866 attribute_type_len = 16; 867 } 868 return handle_read_by_group_type_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), little_endian_read_16(request_buffer, 3), attribute_type_len, &request_buffer[5]); 869 } 870 871 // 872 // MARK: ATT_WRITE_REQUEST 0x12 873 static uint16_t handle_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 874 uint8_t * response_buffer, uint16_t response_buffer_size){ 875 876 UNUSED(response_buffer_size); 877 878 uint8_t request_type = ATT_WRITE_REQUEST; 879 880 uint16_t handle = little_endian_read_16(request_buffer, 1); 881 att_iterator_t it; 882 int ok = att_find_handle(&it, handle); 883 if (!ok) { 884 return setup_error_invalid_handle(response_buffer, request_type, handle); 885 } 886 if (!att_write_callback) { 887 return setup_error_write_not_permitted(response_buffer, request_type, handle); 888 } 889 if ((it.flags & ATT_PROPERTY_WRITE) == 0) { 890 return setup_error_write_not_permitted(response_buffer, request_type, handle); 891 } 892 if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) { 893 return setup_error_write_not_permitted(response_buffer, request_type, handle); 894 } 895 // check security requirements 896 uint8_t error_code = att_validate_security(att_connection, &it); 897 if (error_code) { 898 return setup_error(response_buffer, request_type, handle, error_code); 899 } 900 att_persistent_ccc_cache(&it); 901 error_code = (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3); 902 if (error_code) { 903 return setup_error(response_buffer, request_type, handle, error_code); 904 } 905 response_buffer[0] = ATT_WRITE_RESPONSE; 906 return 1; 907 } 908 909 // 910 // MARK: ATT_PREPARE_WRITE_REQUEST 0x16 911 static uint16_t handle_prepare_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 912 uint8_t * response_buffer, uint16_t response_buffer_size){ 913 914 UNUSED(response_buffer_size); 915 916 uint8_t request_type = ATT_PREPARE_WRITE_REQUEST; 917 918 uint16_t handle = little_endian_read_16(request_buffer, 1); 919 uint16_t offset = little_endian_read_16(request_buffer, 3); 920 if (!att_write_callback) { 921 return setup_error_write_not_permitted(response_buffer, request_type, handle); 922 } 923 att_iterator_t it; 924 int ok = att_find_handle(&it, handle); 925 if (!ok) { 926 return setup_error_invalid_handle(response_buffer, request_type, handle); 927 } 928 if ((it.flags & ATT_PROPERTY_WRITE) == 0) { 929 return setup_error_write_not_permitted(response_buffer, request_type, handle); 930 } 931 if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) { 932 return setup_error_write_not_permitted(response_buffer, request_type, handle); 933 } 934 // check security requirements 935 uint8_t error_code = att_validate_security(att_connection, &it); 936 if (error_code) { 937 return setup_error(response_buffer, request_type, handle, error_code); 938 } 939 940 error_code = (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_ACTIVE, offset, request_buffer + 5, request_len - 5); 941 switch (error_code){ 942 case 0: 943 break; 944 case ATT_ERROR_INVALID_OFFSET: 945 case ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH: 946 // postpone to execute write request 947 att_prepare_write_update_errors(error_code, handle); 948 break; 949 default: 950 return setup_error(response_buffer, request_type, handle, error_code); 951 } 952 953 // response: echo request 954 memcpy(response_buffer, request_buffer, request_len); 955 response_buffer[0] = ATT_PREPARE_WRITE_RESPONSE; 956 return request_len; 957 } 958 959 /* 960 * @brief transcation queue of prepared writes, e.g., after disconnect 961 */ 962 void att_clear_transaction_queue(att_connection_t * att_connection){ 963 (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_CANCEL, 0, NULL, 0); 964 } 965 966 // MARK: ATT_EXECUTE_WRITE_REQUEST 0x18 967 // NOTE: security has been verified by handle_prepare_write_request 968 static uint16_t handle_execute_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 969 uint8_t * response_buffer, uint16_t response_buffer_size){ 970 971 UNUSED(request_len); 972 UNUSED(response_buffer_size); 973 974 uint8_t request_type = ATT_EXECUTE_WRITE_REQUEST; 975 if (request_buffer[1]) { 976 // validate queued write 977 if (att_prepare_write_error_code == 0){ 978 att_prepare_write_error_code = (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_VALIDATE, 0, NULL, 0); 979 } 980 // deliver queued errors 981 if (att_prepare_write_error_code){ 982 att_clear_transaction_queue(att_connection); 983 uint8_t error_code = att_prepare_write_error_code; 984 uint16_t handle = att_prepare_write_error_handle; 985 att_prepare_write_reset(); 986 return setup_error(response_buffer, request_type, handle, error_code); 987 } 988 att_write_callback(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_EXECUTE, 0, NULL, 0); 989 } else { 990 att_clear_transaction_queue(att_connection); 991 } 992 response_buffer[0] = ATT_EXECUTE_WRITE_RESPONSE; 993 return 1; 994 } 995 996 // MARK: ATT_WRITE_COMMAND 0x52 997 // Core 4.0, vol 3, part F, 3.4.5.3 998 // "No Error Response or Write Response shall be sent in response to this command" 999 static void handle_write_command(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 1000 uint8_t * response_buffer, uint16_t response_buffer_size){ 1001 1002 UNUSED(response_buffer); 1003 UNUSED(response_buffer_size); 1004 1005 uint16_t handle = little_endian_read_16(request_buffer, 1); 1006 if (!att_write_callback) return; 1007 1008 att_iterator_t it; 1009 int ok = att_find_handle(&it, handle); 1010 if (!ok) return; 1011 if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) return; 1012 if ((it.flags & ATT_PROPERTY_WRITE_WITHOUT_RESPONSE) == 0) return; 1013 if (att_validate_security(att_connection, &it)) return; 1014 att_persistent_ccc_cache(&it); 1015 (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3); 1016 } 1017 1018 // MARK: helper for ATT_HANDLE_VALUE_NOTIFICATION and ATT_HANDLE_VALUE_INDICATION 1019 static uint16_t prepare_handle_value(att_connection_t * att_connection, 1020 uint16_t handle, 1021 uint8_t *value, 1022 uint16_t value_len, 1023 uint8_t * response_buffer){ 1024 little_endian_store_16(response_buffer, 1, handle); 1025 if (value_len > att_connection->mtu - 3){ 1026 value_len = att_connection->mtu - 3; 1027 } 1028 memcpy(&response_buffer[3], value, value_len); 1029 return value_len + 3; 1030 } 1031 1032 // MARK: ATT_HANDLE_VALUE_NOTIFICATION 0x1b 1033 uint16_t att_prepare_handle_value_notification(att_connection_t * att_connection, 1034 uint16_t handle, 1035 uint8_t *value, 1036 uint16_t value_len, 1037 uint8_t * response_buffer){ 1038 1039 response_buffer[0] = ATT_HANDLE_VALUE_NOTIFICATION; 1040 return prepare_handle_value(att_connection, handle, value, value_len, response_buffer); 1041 } 1042 1043 // MARK: ATT_HANDLE_VALUE_INDICATION 0x1d 1044 uint16_t att_prepare_handle_value_indication(att_connection_t * att_connection, 1045 uint16_t handle, 1046 uint8_t *value, 1047 uint16_t value_len, 1048 uint8_t * response_buffer){ 1049 1050 response_buffer[0] = ATT_HANDLE_VALUE_INDICATION; 1051 return prepare_handle_value(att_connection, handle, value, value_len, response_buffer); 1052 } 1053 1054 // MARK: Dispatcher 1055 uint16_t att_handle_request(att_connection_t * att_connection, 1056 uint8_t * request_buffer, 1057 uint16_t request_len, 1058 uint8_t * response_buffer){ 1059 uint16_t response_len = 0; 1060 uint16_t response_buffer_size = att_connection->mtu; 1061 1062 switch (request_buffer[0]){ 1063 case ATT_EXCHANGE_MTU_REQUEST: 1064 response_len = handle_exchange_mtu_request(att_connection, request_buffer, request_len, response_buffer); 1065 break; 1066 case ATT_FIND_INFORMATION_REQUEST: 1067 response_len = handle_find_information_request(att_connection, request_buffer, request_len,response_buffer, response_buffer_size); 1068 break; 1069 case ATT_FIND_BY_TYPE_VALUE_REQUEST: 1070 response_len = handle_find_by_type_value_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1071 break; 1072 case ATT_READ_BY_TYPE_REQUEST: 1073 response_len = handle_read_by_type_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1074 break; 1075 case ATT_READ_REQUEST: 1076 response_len = handle_read_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1077 break; 1078 case ATT_READ_BLOB_REQUEST: 1079 response_len = handle_read_blob_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1080 break; 1081 case ATT_READ_MULTIPLE_REQUEST: 1082 response_len = handle_read_multiple_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1083 break; 1084 case ATT_READ_BY_GROUP_TYPE_REQUEST: 1085 response_len = handle_read_by_group_type_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1086 break; 1087 case ATT_WRITE_REQUEST: 1088 response_len = handle_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1089 break; 1090 case ATT_PREPARE_WRITE_REQUEST: 1091 response_len = handle_prepare_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1092 break; 1093 case ATT_EXECUTE_WRITE_REQUEST: 1094 response_len = handle_execute_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1095 break; 1096 case ATT_WRITE_COMMAND: 1097 handle_write_command(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1098 break; 1099 #ifdef ENABLE_LE_SIGNED_WRITE 1100 case ATT_SIGNED_WRITE_COMMAND: 1101 log_info("handle_signed_write_command preprocessed by att_server.c"); 1102 break; 1103 #endif 1104 default: 1105 log_info("Unhandled ATT Command: %02X, DATA: ", request_buffer[0]); 1106 log_info_hexdump(&request_buffer[9], request_len-9); 1107 break; 1108 } 1109 return response_len; 1110 } 1111 1112 // returns 1 if service found. only primary service. 1113 int gatt_server_get_get_handle_range_for_service_with_uuid16(uint16_t uuid16, uint16_t * start_handle, uint16_t * end_handle){ 1114 uint16_t in_group = 0; 1115 uint16_t prev_handle = 0; 1116 1117 uint8_t attribute_value[2]; 1118 int attribute_len = sizeof(attribute_value); 1119 little_endian_store_16(attribute_value, 0, uuid16); 1120 1121 att_iterator_t it; 1122 att_iterator_init(&it); 1123 while (att_iterator_has_next(&it)){ 1124 att_iterator_fetch_next(&it); 1125 int new_service_started = att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID); 1126 1127 // close current tag, if within a group and a new service definition starts or we reach end of att db 1128 if (in_group && 1129 (it.handle == 0 || new_service_started)){ 1130 *end_handle = prev_handle; 1131 return 1; 1132 } 1133 1134 // keep track of previous handle 1135 prev_handle = it.handle; 1136 1137 // check if found 1138 if (it.handle && new_service_started && attribute_len == it.value_len && memcmp(attribute_value, it.value, it.value_len) == 0){ 1139 *start_handle = it.handle; 1140 in_group = 1; 1141 } 1142 } 1143 return 0; 1144 } 1145 1146 // returns 0 if not found 1147 uint16_t gatt_server_get_value_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){ 1148 att_iterator_t it; 1149 att_iterator_init(&it); 1150 while (att_iterator_has_next(&it)){ 1151 att_iterator_fetch_next(&it); 1152 if (it.handle && it.handle < start_handle) continue; 1153 if (it.handle > end_handle) break; // (1) 1154 if (it.handle == 0) break; 1155 if (att_iterator_match_uuid16(&it, uuid16)) return it.handle; 1156 } 1157 return 0; 1158 } 1159 1160 // returns 0 if not found 1161 uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){ 1162 att_iterator_t it; 1163 att_iterator_init(&it); 1164 int characteristic_found = 0; 1165 while (att_iterator_has_next(&it)){ 1166 att_iterator_fetch_next(&it); 1167 if (it.handle && it.handle < start_handle) continue; 1168 if (it.handle > end_handle) break; // (1) 1169 if (it.handle == 0) break; 1170 if (att_iterator_match_uuid16(&it, uuid16)){ 1171 characteristic_found = 1; 1172 continue; 1173 } 1174 if (att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) 1175 || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID) 1176 || att_iterator_match_uuid16(&it, GATT_CHARACTERISTICS_UUID)){ 1177 if (characteristic_found) break; 1178 continue; 1179 } 1180 if (att_iterator_match_uuid16(&it, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION)){ 1181 return it.handle; 1182 } 1183 } 1184 return 0; 1185 } 1186 1187 // 1-item cache to optimize query during write_callback 1188 static void att_persistent_ccc_cache(att_iterator_t * it){ 1189 att_persistent_ccc_handle = it->handle; 1190 if (it->flags & ATT_PROPERTY_UUID128){ 1191 att_persistent_ccc_uuid16 = 0; 1192 } else { 1193 att_persistent_ccc_uuid16 = little_endian_read_16(it->uuid, 0); 1194 } 1195 } 1196 1197 int att_is_persistent_ccc(uint16_t handle){ 1198 if (handle != att_persistent_ccc_handle){ 1199 att_iterator_t it; 1200 int ok = att_find_handle(&it, handle); 1201 if (!ok) return 0; 1202 att_persistent_ccc_cache(&it); 1203 } 1204 return att_persistent_ccc_uuid16 == GATT_CLIENT_CHARACTERISTICS_CONFIGURATION; 1205 } 1206 1207 // att_read_callback helpers 1208 uint16_t att_read_callback_handle_blob(const uint8_t * blob, uint16_t blob_size, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ 1209 if (buffer){ 1210 uint16_t bytes_to_copy = btstack_min(blob_size - offset, buffer_size); 1211 memcpy(buffer, &blob[offset], bytes_to_copy); 1212 return bytes_to_copy; 1213 } else { 1214 return blob_size; 1215 } 1216 } 1217 1218 uint16_t att_read_callback_handle_little_endian_32(uint32_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ 1219 uint8_t value_buffer[4]; 1220 little_endian_store_32(value_buffer, 0, value); 1221 return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size); 1222 } 1223 1224 uint16_t att_read_callback_handle_little_endian_16(uint16_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ 1225 uint8_t value_buffer[2]; 1226 little_endian_store_16(value_buffer, 0, value); 1227 return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size); 1228 } 1229 1230 uint16_t att_read_callback_handle_byte(uint8_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ 1231 uint8_t value_buffer[1]; 1232 value_buffer[0] = value; 1233 return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size); 1234 } 1235