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