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