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