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