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