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 #ifdef ENABLE_ATT_DELAYED_READ_RESPONSE 498 int read_request_pending = 0; 499 #endif 500 501 while (att_iterator_has_next(&it)){ 502 att_iterator_fetch_next(&it); 503 504 if (!it.handle) break; 505 if (it.handle < start_handle) continue; 506 if (it.handle > end_handle) break; // (1) 507 508 // does current attribute match 509 if (!att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) continue; 510 511 // skip handles that cannot be read but rembember that there has been at least one 512 if ((it.flags & ATT_PROPERTY_READ) == 0) { 513 if (first_matching_but_unreadable_handle == 0) { 514 first_matching_but_unreadable_handle = it.handle; 515 } 516 continue; 517 } 518 519 // check security requirements 520 if ((it.flags & ATT_DB_FLAGS_READ_WITHOUT_AUTHENTICATION) == 0){ 521 error_code = att_validate_security(att_connection, &it); 522 if (error_code) break; 523 } 524 525 att_update_value_len(&it, att_connection->con_handle); 526 527 #ifdef ENABLE_ATT_DELAYED_READ_RESPONSE 528 if (it.value_len == ATT_READ_RESPONSE_PENDING){ 529 read_request_pending = 1; 530 } 531 if (read_request_pending) continue; 532 #endif 533 534 // check if value has same len as last one 535 uint16_t this_pair_len = 2 + it.value_len; 536 if (offset > 1){ 537 if (pair_len != this_pair_len) { 538 break; 539 } 540 } 541 542 // first 543 if (offset == 1) { 544 pair_len = this_pair_len; 545 response_buffer[offset] = pair_len; 546 offset++; 547 } 548 549 // space? 550 if (offset + pair_len > response_buffer_size) { 551 if (offset > 2) break; 552 it.value_len = response_buffer_size - 4; 553 response_buffer[1] = 2 + it.value_len; 554 } 555 556 // store 557 little_endian_store_16(response_buffer, offset, it.handle); 558 offset += 2; 559 uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len, att_connection->con_handle); 560 offset += bytes_copied; 561 } 562 563 #ifdef ENABLE_ATT_DELAYED_READ_RESPONSE 564 if (read_request_pending) return ATT_READ_RESPONSE_PENDING; 565 #endif 566 567 // at least one attribute could be read 568 if (offset > 1){ 569 response_buffer[0] = ATT_READ_BY_TYPE_RESPONSE; 570 return offset; 571 } 572 573 // first attribute had an error 574 if (error_code){ 575 return setup_error(response_buffer, request_type, start_handle, error_code); 576 } 577 578 // no other errors, but all found attributes had been non-readable 579 if (first_matching_but_unreadable_handle){ 580 return setup_error_read_not_permitted(response_buffer, request_type, first_matching_but_unreadable_handle); 581 } 582 583 // attribute not found 584 return setup_error_atribute_not_found(response_buffer, request_type, start_handle); 585 } 586 587 static uint16_t handle_read_by_type_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 588 uint8_t * response_buffer, uint16_t response_buffer_size){ 589 int attribute_type_len; 590 if (request_len <= 7){ 591 attribute_type_len = 2; 592 } else { 593 attribute_type_len = 16; 594 } 595 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]); 596 } 597 598 // 599 // MARK: ATT_READ_BY_TYPE_REQUEST 600 // 601 static uint16_t handle_read_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle){ 602 603 log_info("ATT_READ_REQUEST: handle %04x", handle); 604 uint8_t request_type = ATT_READ_REQUEST; 605 606 att_iterator_t it; 607 int ok = att_find_handle(&it, handle); 608 if (!ok){ 609 return setup_error_invalid_handle(response_buffer, request_type, handle); 610 } 611 612 // check if handle can be read 613 if ((it.flags & ATT_PROPERTY_READ) == 0) { 614 return setup_error_read_not_permitted(response_buffer, request_type, handle); 615 } 616 617 // check security requirements 618 if ((it.flags & ATT_DB_FLAGS_READ_WITHOUT_AUTHENTICATION) == 0){ 619 uint8_t error_code = att_validate_security(att_connection, &it); 620 if (error_code) { 621 return setup_error(response_buffer, request_type, handle, error_code); 622 } 623 } 624 625 att_update_value_len(&it, att_connection->con_handle); 626 627 #ifdef ENABLE_ATT_DELAYED_READ_RESPONSE 628 if (it.value_len == ATT_READ_RESPONSE_PENDING) return ATT_READ_RESPONSE_PENDING; 629 #endif 630 631 uint16_t offset = 1; 632 // limit data 633 if (offset + it.value_len > response_buffer_size) { 634 it.value_len = response_buffer_size - 1; 635 } 636 637 // store 638 uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len, att_connection->con_handle); 639 offset += bytes_copied; 640 641 response_buffer[0] = ATT_READ_RESPONSE; 642 return offset; 643 } 644 645 static uint16_t handle_read_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 646 uint8_t * response_buffer, uint16_t response_buffer_size){ 647 UNUSED(request_len); 648 return handle_read_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1)); 649 } 650 651 // 652 // MARK: ATT_READ_BLOB_REQUEST 0x0c 653 // 654 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){ 655 log_info("ATT_READ_BLOB_REQUEST: handle %04x, offset %u", handle, value_offset); 656 uint8_t request_type = ATT_READ_BLOB_REQUEST; 657 658 att_iterator_t it; 659 int ok = att_find_handle(&it, handle); 660 if (!ok){ 661 return setup_error_invalid_handle(response_buffer, request_type, handle); 662 } 663 664 // check if handle can be read 665 if ((it.flags & ATT_PROPERTY_READ) == 0) { 666 return setup_error_read_not_permitted(response_buffer, request_type, handle); 667 } 668 669 // check security requirements 670 if ((it.flags & ATT_DB_FLAGS_READ_WITHOUT_AUTHENTICATION) == 0){ 671 uint8_t error_code = att_validate_security(att_connection, &it); 672 if (error_code) { 673 return setup_error(response_buffer, request_type, handle, error_code); 674 } 675 } 676 677 att_update_value_len(&it, att_connection->con_handle); 678 679 #ifdef ENABLE_ATT_DELAYED_READ_RESPONSE 680 if (it.value_len == ATT_READ_RESPONSE_PENDING) return ATT_READ_RESPONSE_PENDING; 681 #endif 682 683 if (value_offset > it.value_len){ 684 return setup_error_invalid_offset(response_buffer, request_type, handle); 685 } 686 687 // limit data 688 uint16_t offset = 1; 689 if (offset + it.value_len - value_offset > response_buffer_size) { 690 it.value_len = response_buffer_size - 1 + value_offset; 691 } 692 693 // store 694 uint16_t bytes_copied = att_copy_value(&it, value_offset, response_buffer + offset, it.value_len - value_offset, att_connection->con_handle); 695 offset += bytes_copied; 696 697 response_buffer[0] = ATT_READ_BLOB_RESPONSE; 698 return offset; 699 } 700 701 static uint16_t handle_read_blob_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 702 uint8_t * response_buffer, uint16_t response_buffer_size){ 703 UNUSED(request_len); 704 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)); 705 } 706 707 // 708 // MARK: ATT_READ_MULTIPLE_REQUEST 0x0e 709 // 710 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){ 711 log_info("ATT_READ_MULTIPLE_REQUEST: num handles %u", num_handles); 712 uint8_t request_type = ATT_READ_MULTIPLE_REQUEST; 713 714 // TODO: figure out which error to respond with 715 // if (num_handles < 2){ 716 // return setup_error(response_buffer, ATT_READ_MULTIPLE_REQUEST, handle, ???); 717 // } 718 719 uint16_t offset = 1; 720 721 int i; 722 uint8_t error_code = 0; 723 uint16_t handle = 0; 724 725 #ifdef ENABLE_ATT_DELAYED_READ_RESPONSE 726 int read_request_pending = 0; 727 #endif 728 729 for (i=0;i<num_handles;i++){ 730 handle = little_endian_read_16(handles, i << 1); 731 732 if (handle == 0){ 733 return setup_error_invalid_handle(response_buffer, request_type, handle); 734 } 735 736 att_iterator_t it; 737 738 int ok = att_find_handle(&it, handle); 739 if (!ok){ 740 return setup_error_invalid_handle(response_buffer, request_type, handle); 741 } 742 743 // check if handle can be read 744 if ((it.flags & ATT_PROPERTY_READ) == 0) { 745 error_code = ATT_ERROR_READ_NOT_PERMITTED; 746 break; 747 } 748 749 // check security requirements 750 if ((it.flags & ATT_DB_FLAGS_READ_WITHOUT_AUTHENTICATION) == 0){ 751 error_code = att_validate_security(att_connection, &it); 752 if (error_code) break; 753 } 754 att_update_value_len(&it, att_connection->con_handle); 755 756 #ifdef ENABLE_ATT_DELAYED_READ_RESPONSE 757 if (it.value_len == ATT_READ_RESPONSE_PENDING) { 758 read_request_pending = 1; 759 } 760 if (read_request_pending) continue; 761 #endif 762 763 // limit data 764 if (offset + it.value_len > response_buffer_size) { 765 it.value_len = response_buffer_size - 1; 766 } 767 768 // store 769 uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len, att_connection->con_handle); 770 offset += bytes_copied; 771 } 772 773 if (error_code){ 774 return setup_error(response_buffer, request_type, handle, error_code); 775 } 776 777 response_buffer[0] = ATT_READ_MULTIPLE_RESPONSE; 778 return offset; 779 } 780 static uint16_t handle_read_multiple_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 781 uint8_t * response_buffer, uint16_t response_buffer_size){ 782 int num_handles = (request_len - 1) >> 1; 783 return handle_read_multiple_request2(att_connection, response_buffer, response_buffer_size, num_handles, &request_buffer[1]); 784 } 785 786 // 787 // MARK: ATT_READ_BY_GROUP_TYPE_REQUEST 0x10 788 // 789 // Only handles GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID 790 // Core v4.0, vol 3, part g, 2.5.3 791 // "The «Primary Service» and «Secondary Service» grouping types may be used in the Read By Group Type Request. 792 // The «Characteristic» grouping type shall not be used in the ATT Read By Group Type Request." 793 // 794 // NOTE: doesn't handle DYNAMIC values 795 // 796 // NOTE: we don't check for security as PRIMARY and SECONDAY SERVICE definition shouldn't be protected 797 // Core 4.0, vol 3, part g, 8.1 798 // "The list of services and characteristics that a device supports is not considered private or 799 // confidential information, and therefore the Service and Characteristic Discovery procedures 800 // shall always be permitted. " 801 // 802 static uint16_t handle_read_by_group_type_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, 803 uint16_t start_handle, uint16_t end_handle, 804 uint16_t attribute_type_len, uint8_t * attribute_type){ 805 806 UNUSED(att_connection); 807 808 log_info("ATT_READ_BY_GROUP_TYPE_REQUEST: from %04X to %04X, buffer size %u, type: ", start_handle, end_handle, response_buffer_size); 809 log_info_hexdump(attribute_type, attribute_type_len); 810 uint8_t request_type = ATT_READ_BY_GROUP_TYPE_REQUEST; 811 812 if (start_handle > end_handle || start_handle == 0){ 813 return setup_error_invalid_handle(response_buffer, request_type, start_handle); 814 } 815 816 // assert UUID is primary or secondary service uuid 817 uint16_t uuid16 = uuid16_from_uuid(attribute_type_len, attribute_type); 818 if (uuid16 != GATT_PRIMARY_SERVICE_UUID && uuid16 != GATT_SECONDARY_SERVICE_UUID){ 819 return setup_error(response_buffer, request_type, start_handle, ATT_ERROR_UNSUPPORTED_GROUP_TYPE); 820 } 821 822 uint16_t offset = 1; 823 uint16_t pair_len = 0; 824 uint16_t in_group = 0; 825 uint16_t group_start_handle = 0; 826 uint8_t const * group_start_value = NULL; 827 uint16_t prev_handle = 0; 828 829 att_iterator_t it; 830 att_iterator_init(&it); 831 while (att_iterator_has_next(&it)){ 832 att_iterator_fetch_next(&it); 833 834 if (it.handle && it.handle < start_handle) continue; 835 if (it.handle > end_handle) break; // (1) 836 837 // log_info("Handle 0x%04x", it.handle); 838 839 // close current tag, if within a group and a new service definition starts or we reach end of att db 840 if (in_group && 841 (it.handle == 0 || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){ 842 // log_info("End of group, handle 0x%04x, val_len: %u", prev_handle, pair_len - 4); 843 844 little_endian_store_16(response_buffer, offset, group_start_handle); 845 offset += 2; 846 little_endian_store_16(response_buffer, offset, prev_handle); 847 offset += 2; 848 memcpy(response_buffer + offset, group_start_value, pair_len - 4); 849 offset += pair_len - 4; 850 in_group = 0; 851 852 // check if space for another handle pair available 853 if (offset + pair_len > response_buffer_size){ 854 break; 855 } 856 } 857 858 // keep track of previous handle 859 prev_handle = it.handle; 860 861 // does current attribute match 862 // log_info("compare: %04x == %04x", *(uint16_t*) context->attribute_type, *(uint16_t*) uuid); 863 if (it.handle && att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) { 864 865 // check if value has same len as last one 866 uint16_t this_pair_len = 4 + it.value_len; 867 if (offset > 1){ 868 if (this_pair_len != pair_len) { 869 break; 870 } 871 } 872 873 // log_info("Begin of group, handle 0x%04x", it.handle); 874 875 // first 876 if (offset == 1) { 877 pair_len = this_pair_len; 878 response_buffer[offset] = this_pair_len; 879 offset++; 880 } 881 882 group_start_handle = it.handle; 883 group_start_value = it.value; 884 in_group = 1; 885 } 886 } 887 888 if (offset == 1){ 889 return setup_error_atribute_not_found(response_buffer, request_type, start_handle); 890 } 891 892 response_buffer[0] = ATT_READ_BY_GROUP_TYPE_RESPONSE; 893 return offset; 894 } 895 static uint16_t handle_read_by_group_type_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 896 uint8_t * response_buffer, uint16_t response_buffer_size){ 897 int attribute_type_len; 898 if (request_len <= 7){ 899 attribute_type_len = 2; 900 } else { 901 attribute_type_len = 16; 902 } 903 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]); 904 } 905 906 // 907 // MARK: ATT_WRITE_REQUEST 0x12 908 static uint16_t handle_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 909 uint8_t * response_buffer, uint16_t response_buffer_size){ 910 911 UNUSED(response_buffer_size); 912 913 uint8_t request_type = ATT_WRITE_REQUEST; 914 915 uint16_t handle = little_endian_read_16(request_buffer, 1); 916 att_iterator_t it; 917 int ok = att_find_handle(&it, handle); 918 if (!ok) { 919 return setup_error_invalid_handle(response_buffer, request_type, handle); 920 } 921 if (!att_write_callback) { 922 return setup_error_write_not_permitted(response_buffer, request_type, handle); 923 } 924 if ((it.flags & ATT_PROPERTY_WRITE) == 0) { 925 return setup_error_write_not_permitted(response_buffer, request_type, handle); 926 } 927 if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) { 928 return setup_error_write_not_permitted(response_buffer, request_type, handle); 929 } 930 // check security requirements 931 uint8_t error_code = att_validate_security(att_connection, &it); 932 if (error_code) { 933 return setup_error(response_buffer, request_type, handle, error_code); 934 } 935 att_persistent_ccc_cache(&it); 936 error_code = (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3); 937 if (error_code) { 938 return setup_error(response_buffer, request_type, handle, error_code); 939 } 940 response_buffer[0] = ATT_WRITE_RESPONSE; 941 return 1; 942 } 943 944 // 945 // MARK: ATT_PREPARE_WRITE_REQUEST 0x16 946 static uint16_t handle_prepare_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 947 uint8_t * response_buffer, uint16_t response_buffer_size){ 948 949 UNUSED(response_buffer_size); 950 951 uint8_t request_type = ATT_PREPARE_WRITE_REQUEST; 952 953 uint16_t handle = little_endian_read_16(request_buffer, 1); 954 uint16_t offset = little_endian_read_16(request_buffer, 3); 955 if (!att_write_callback) { 956 return setup_error_write_not_permitted(response_buffer, request_type, handle); 957 } 958 att_iterator_t it; 959 int ok = att_find_handle(&it, handle); 960 if (!ok) { 961 return setup_error_invalid_handle(response_buffer, request_type, handle); 962 } 963 if ((it.flags & ATT_PROPERTY_WRITE) == 0) { 964 return setup_error_write_not_permitted(response_buffer, request_type, handle); 965 } 966 if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) { 967 return setup_error_write_not_permitted(response_buffer, request_type, handle); 968 } 969 // check security requirements 970 uint8_t error_code = att_validate_security(att_connection, &it); 971 if (error_code) { 972 return setup_error(response_buffer, request_type, handle, error_code); 973 } 974 975 error_code = (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_ACTIVE, offset, request_buffer + 5, request_len - 5); 976 switch (error_code){ 977 case 0: 978 break; 979 case ATT_ERROR_INVALID_OFFSET: 980 case ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH: 981 // postpone to execute write request 982 att_prepare_write_update_errors(error_code, handle); 983 break; 984 default: 985 return setup_error(response_buffer, request_type, handle, error_code); 986 } 987 988 // response: echo request 989 memcpy(response_buffer, request_buffer, request_len); 990 response_buffer[0] = ATT_PREPARE_WRITE_RESPONSE; 991 return request_len; 992 } 993 994 /* 995 * @brief transcation queue of prepared writes, e.g., after disconnect 996 */ 997 void att_clear_transaction_queue(att_connection_t * att_connection){ 998 (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_CANCEL, 0, NULL, 0); 999 } 1000 1001 // MARK: ATT_EXECUTE_WRITE_REQUEST 0x18 1002 // NOTE: security has been verified by handle_prepare_write_request 1003 static uint16_t handle_execute_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 1004 uint8_t * response_buffer, uint16_t response_buffer_size){ 1005 1006 UNUSED(request_len); 1007 UNUSED(response_buffer_size); 1008 1009 uint8_t request_type = ATT_EXECUTE_WRITE_REQUEST; 1010 if (request_buffer[1]) { 1011 // validate queued write 1012 if (att_prepare_write_error_code == 0){ 1013 att_prepare_write_error_code = (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_VALIDATE, 0, NULL, 0); 1014 } 1015 // deliver queued errors 1016 if (att_prepare_write_error_code){ 1017 att_clear_transaction_queue(att_connection); 1018 uint8_t error_code = att_prepare_write_error_code; 1019 uint16_t handle = att_prepare_write_error_handle; 1020 att_prepare_write_reset(); 1021 return setup_error(response_buffer, request_type, handle, error_code); 1022 } 1023 att_write_callback(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_EXECUTE, 0, NULL, 0); 1024 } else { 1025 att_clear_transaction_queue(att_connection); 1026 } 1027 response_buffer[0] = ATT_EXECUTE_WRITE_RESPONSE; 1028 return 1; 1029 } 1030 1031 // MARK: ATT_WRITE_COMMAND 0x52 1032 // Core 4.0, vol 3, part F, 3.4.5.3 1033 // "No Error Response or Write Response shall be sent in response to this command" 1034 static void handle_write_command(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 1035 uint8_t * response_buffer, uint16_t response_buffer_size){ 1036 1037 UNUSED(response_buffer); 1038 UNUSED(response_buffer_size); 1039 1040 uint16_t handle = little_endian_read_16(request_buffer, 1); 1041 if (!att_write_callback) return; 1042 1043 att_iterator_t it; 1044 int ok = att_find_handle(&it, handle); 1045 if (!ok) return; 1046 if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) return; 1047 if ((it.flags & ATT_PROPERTY_WRITE_WITHOUT_RESPONSE) == 0) return; 1048 if (att_validate_security(att_connection, &it)) return; 1049 att_persistent_ccc_cache(&it); 1050 (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3); 1051 } 1052 1053 // MARK: helper for ATT_HANDLE_VALUE_NOTIFICATION and ATT_HANDLE_VALUE_INDICATION 1054 static uint16_t prepare_handle_value(att_connection_t * att_connection, 1055 uint16_t handle, 1056 uint8_t *value, 1057 uint16_t value_len, 1058 uint8_t * response_buffer){ 1059 little_endian_store_16(response_buffer, 1, handle); 1060 if (value_len > att_connection->mtu - 3){ 1061 value_len = att_connection->mtu - 3; 1062 } 1063 memcpy(&response_buffer[3], value, value_len); 1064 return value_len + 3; 1065 } 1066 1067 // MARK: ATT_HANDLE_VALUE_NOTIFICATION 0x1b 1068 uint16_t att_prepare_handle_value_notification(att_connection_t * att_connection, 1069 uint16_t handle, 1070 uint8_t *value, 1071 uint16_t value_len, 1072 uint8_t * response_buffer){ 1073 1074 response_buffer[0] = ATT_HANDLE_VALUE_NOTIFICATION; 1075 return prepare_handle_value(att_connection, handle, value, value_len, response_buffer); 1076 } 1077 1078 // MARK: ATT_HANDLE_VALUE_INDICATION 0x1d 1079 uint16_t att_prepare_handle_value_indication(att_connection_t * att_connection, 1080 uint16_t handle, 1081 uint8_t *value, 1082 uint16_t value_len, 1083 uint8_t * response_buffer){ 1084 1085 response_buffer[0] = ATT_HANDLE_VALUE_INDICATION; 1086 return prepare_handle_value(att_connection, handle, value, value_len, response_buffer); 1087 } 1088 1089 // MARK: Dispatcher 1090 uint16_t att_handle_request(att_connection_t * att_connection, 1091 uint8_t * request_buffer, 1092 uint16_t request_len, 1093 uint8_t * response_buffer){ 1094 uint16_t response_len = 0; 1095 uint16_t response_buffer_size = att_connection->mtu; 1096 1097 switch (request_buffer[0]){ 1098 case ATT_EXCHANGE_MTU_REQUEST: 1099 response_len = handle_exchange_mtu_request(att_connection, request_buffer, request_len, response_buffer); 1100 break; 1101 case ATT_FIND_INFORMATION_REQUEST: 1102 response_len = handle_find_information_request(att_connection, request_buffer, request_len,response_buffer, response_buffer_size); 1103 break; 1104 case ATT_FIND_BY_TYPE_VALUE_REQUEST: 1105 response_len = handle_find_by_type_value_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1106 break; 1107 case ATT_READ_BY_TYPE_REQUEST: 1108 response_len = handle_read_by_type_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1109 break; 1110 case ATT_READ_REQUEST: 1111 response_len = handle_read_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1112 break; 1113 case ATT_READ_BLOB_REQUEST: 1114 response_len = handle_read_blob_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1115 break; 1116 case ATT_READ_MULTIPLE_REQUEST: 1117 response_len = handle_read_multiple_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1118 break; 1119 case ATT_READ_BY_GROUP_TYPE_REQUEST: 1120 response_len = handle_read_by_group_type_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1121 break; 1122 case ATT_WRITE_REQUEST: 1123 response_len = handle_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1124 break; 1125 case ATT_PREPARE_WRITE_REQUEST: 1126 response_len = handle_prepare_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1127 break; 1128 case ATT_EXECUTE_WRITE_REQUEST: 1129 response_len = handle_execute_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1130 break; 1131 case ATT_WRITE_COMMAND: 1132 handle_write_command(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1133 break; 1134 #ifdef ENABLE_LE_SIGNED_WRITE 1135 case ATT_SIGNED_WRITE_COMMAND: 1136 log_info("handle_signed_write_command preprocessed by att_server.c"); 1137 break; 1138 #endif 1139 default: 1140 log_info("Unhandled ATT Command: %02X, DATA: ", request_buffer[0]); 1141 log_info_hexdump(&request_buffer[9], request_len-9); 1142 break; 1143 } 1144 return response_len; 1145 } 1146 1147 // returns 1 if service found. only primary service. 1148 int gatt_server_get_get_handle_range_for_service_with_uuid16(uint16_t uuid16, uint16_t * start_handle, uint16_t * end_handle){ 1149 uint16_t in_group = 0; 1150 uint16_t prev_handle = 0; 1151 1152 uint8_t attribute_value[2]; 1153 int attribute_len = sizeof(attribute_value); 1154 little_endian_store_16(attribute_value, 0, uuid16); 1155 1156 att_iterator_t it; 1157 att_iterator_init(&it); 1158 while (att_iterator_has_next(&it)){ 1159 att_iterator_fetch_next(&it); 1160 int new_service_started = att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID); 1161 1162 // close current tag, if within a group and a new service definition starts or we reach end of att db 1163 if (in_group && 1164 (it.handle == 0 || new_service_started)){ 1165 *end_handle = prev_handle; 1166 return 1; 1167 } 1168 1169 // keep track of previous handle 1170 prev_handle = it.handle; 1171 1172 // check if found 1173 if (it.handle && new_service_started && attribute_len == it.value_len && memcmp(attribute_value, it.value, it.value_len) == 0){ 1174 *start_handle = it.handle; 1175 in_group = 1; 1176 } 1177 } 1178 return 0; 1179 } 1180 1181 // returns 0 if not found 1182 uint16_t gatt_server_get_value_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){ 1183 att_iterator_t it; 1184 att_iterator_init(&it); 1185 while (att_iterator_has_next(&it)){ 1186 att_iterator_fetch_next(&it); 1187 if (it.handle && it.handle < start_handle) continue; 1188 if (it.handle > end_handle) break; // (1) 1189 if (it.handle == 0) break; 1190 if (att_iterator_match_uuid16(&it, uuid16)) return it.handle; 1191 } 1192 return 0; 1193 } 1194 1195 // returns 0 if not found 1196 uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){ 1197 att_iterator_t it; 1198 att_iterator_init(&it); 1199 int characteristic_found = 0; 1200 while (att_iterator_has_next(&it)){ 1201 att_iterator_fetch_next(&it); 1202 if (it.handle && it.handle < start_handle) continue; 1203 if (it.handle > end_handle) break; // (1) 1204 if (it.handle == 0) break; 1205 if (att_iterator_match_uuid16(&it, uuid16)){ 1206 characteristic_found = 1; 1207 continue; 1208 } 1209 if (att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) 1210 || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID) 1211 || att_iterator_match_uuid16(&it, GATT_CHARACTERISTICS_UUID)){ 1212 if (characteristic_found) break; 1213 continue; 1214 } 1215 if (att_iterator_match_uuid16(&it, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION)){ 1216 return it.handle; 1217 } 1218 } 1219 return 0; 1220 } 1221 1222 // 1-item cache to optimize query during write_callback 1223 static void att_persistent_ccc_cache(att_iterator_t * it){ 1224 att_persistent_ccc_handle = it->handle; 1225 if (it->flags & ATT_PROPERTY_UUID128){ 1226 att_persistent_ccc_uuid16 = 0; 1227 } else { 1228 att_persistent_ccc_uuid16 = little_endian_read_16(it->uuid, 0); 1229 } 1230 } 1231 1232 int att_is_persistent_ccc(uint16_t handle){ 1233 if (handle != att_persistent_ccc_handle){ 1234 att_iterator_t it; 1235 int ok = att_find_handle(&it, handle); 1236 if (!ok) return 0; 1237 att_persistent_ccc_cache(&it); 1238 } 1239 return att_persistent_ccc_uuid16 == GATT_CLIENT_CHARACTERISTICS_CONFIGURATION; 1240 } 1241 1242 // att_read_callback helpers 1243 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){ 1244 if (buffer){ 1245 uint16_t bytes_to_copy = btstack_min(blob_size - offset, buffer_size); 1246 memcpy(buffer, &blob[offset], bytes_to_copy); 1247 return bytes_to_copy; 1248 } else { 1249 return blob_size; 1250 } 1251 } 1252 1253 uint16_t att_read_callback_handle_little_endian_32(uint32_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ 1254 uint8_t value_buffer[4]; 1255 little_endian_store_32(value_buffer, 0, value); 1256 return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size); 1257 } 1258 1259 uint16_t att_read_callback_handle_little_endian_16(uint16_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ 1260 uint8_t value_buffer[2]; 1261 little_endian_store_16(value_buffer, 0, value); 1262 return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size); 1263 } 1264 1265 uint16_t att_read_callback_handle_byte(uint8_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ 1266 uint8_t value_buffer[1]; 1267 value_buffer[0] = value; 1268 return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size); 1269 } 1270