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 BLUEKITCHEN 24 * GMBH 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 #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 // check for ENABLE_ATT_DELAYED_READ_RESPONSE -> ENABLE_ATT_DELAYED_RESPONSE, 49 #ifdef ENABLE_ATT_DELAYED_READ_RESPONSE 50 #error "ENABLE_ATT_DELAYED_READ_RESPONSE was replaced by ENABLE_ATT_DELAYED_RESPONSE. Please update btstack_config.h" 51 #endif 52 53 typedef enum { 54 ATT_READ, 55 ATT_WRITE, 56 } att_operation_t; 57 58 59 static bool is_Bluetooth_Base_UUID(uint8_t const *uuid){ 60 // Bluetooth Base UUID 00000000-0000-1000-8000-00805F9B34FB in little endian 61 static const uint8_t bluetooth_base_uuid[] = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 62 63 if (memcmp(&uuid[0], &bluetooth_base_uuid[0], 12) != 0){ 64 return false; 65 } 66 if (memcmp(&uuid[14], &bluetooth_base_uuid[14], 2) != 0){ 67 return false; 68 } 69 return true; 70 71 } 72 73 static uint16_t uuid16_from_uuid(uint16_t uuid_len, uint8_t * uuid){ 74 if (uuid_len == 2u){ 75 return little_endian_read_16(uuid, 0u); 76 } 77 if (!is_Bluetooth_Base_UUID(uuid)){ 78 return 0; 79 } 80 return little_endian_read_16(uuid, 12); 81 } 82 83 // ATT Database 84 85 // new java-style iterator 86 typedef struct att_iterator { 87 // private 88 uint8_t const * att_ptr; 89 // public 90 uint16_t size; 91 uint16_t flags; 92 uint16_t handle; 93 uint8_t const * uuid; 94 uint16_t value_len; 95 uint8_t const * value; 96 } att_iterator_t; 97 98 static void att_persistent_ccc_cache(att_iterator_t * it); 99 100 static uint8_t const * att_database = NULL; 101 static att_read_callback_t att_read_callback = NULL; 102 static att_write_callback_t att_write_callback = NULL; 103 static int att_prepare_write_error_code = 0; 104 static uint16_t att_prepare_write_error_handle = 0x0000; 105 106 // single cache for att_is_persistent_ccc - stores flags before write callback 107 static uint16_t att_persistent_ccc_handle; 108 static uint16_t att_persistent_ccc_uuid16; 109 110 static void att_iterator_init(att_iterator_t *it){ 111 it->att_ptr = att_database; 112 } 113 114 static bool att_iterator_has_next(att_iterator_t *it){ 115 return it->att_ptr != NULL; 116 } 117 118 static void att_iterator_fetch_next(att_iterator_t *it){ 119 it->size = little_endian_read_16(it->att_ptr, 0); 120 if (it->size == 0u){ 121 it->flags = 0; 122 it->handle = 0; 123 it->uuid = NULL; 124 it->value_len = 0; 125 it->value = NULL; 126 it->att_ptr = NULL; 127 return; 128 } 129 it->flags = little_endian_read_16(it->att_ptr, 2); 130 it->handle = little_endian_read_16(it->att_ptr, 4); 131 it->uuid = &it->att_ptr[6]; 132 // handle 128 bit UUIDs 133 if ((it->flags & (uint16_t)ATT_PROPERTY_UUID128) != 0u){ 134 it->value_len = it->size - 22u; 135 it->value = &it->att_ptr[22]; 136 } else { 137 it->value_len = it->size - 8u; 138 it->value = &it->att_ptr[8]; 139 } 140 // advance AFTER setting values 141 it->att_ptr += it->size; 142 } 143 144 static bool att_iterator_match_uuid16(att_iterator_t *it, uint16_t uuid){ 145 if (it->handle == 0u){ 146 return false; 147 } 148 if ((it->flags & (uint16_t)ATT_PROPERTY_UUID128) != 0u){ 149 if (!is_Bluetooth_Base_UUID(it->uuid)){ 150 return false; 151 } 152 return little_endian_read_16(it->uuid, 12) == uuid; 153 } 154 return little_endian_read_16(it->uuid, 0) == uuid; 155 } 156 157 static bool att_iterator_match_uuid(att_iterator_t *it, uint8_t *uuid, uint16_t uuid_len){ 158 if (it->handle == 0u){ 159 return false; 160 } 161 // input: UUID16 162 if (uuid_len == 2u) { 163 return att_iterator_match_uuid16(it, little_endian_read_16(uuid, 0)); 164 } 165 // input and db: UUID128 166 if ((it->flags & (uint16_t)ATT_PROPERTY_UUID128) != 0u){ 167 return memcmp(it->uuid, uuid, 16) == 0; 168 } 169 // input: UUID128, db: UUID16 170 if (!is_Bluetooth_Base_UUID(uuid)){ 171 return false; 172 } 173 return little_endian_read_16(uuid, 12) == little_endian_read_16(it->uuid, 0); 174 } 175 176 177 static bool att_find_handle(att_iterator_t *it, uint16_t handle){ 178 if (handle == 0u){ 179 return false; 180 } 181 att_iterator_init(it); 182 while (att_iterator_has_next(it)){ 183 att_iterator_fetch_next(it); 184 if (it->handle == handle){ 185 return true; 186 } 187 } 188 return false; 189 } 190 191 // experimental client API 192 uint16_t att_uuid_for_handle(uint16_t attribute_handle){ 193 att_iterator_t it; 194 bool ok = att_find_handle(&it, attribute_handle); 195 if (!ok){ 196 return 0u; 197 } 198 if ((it.flags & (uint16_t)ATT_PROPERTY_UUID128) != 0u){ 199 return 0u; 200 } 201 return little_endian_read_16(it.uuid, 0); 202 } 203 204 const uint8_t * gatt_server_get_const_value_for_handle(uint16_t attribute_handle, uint16_t * out_value_len){ 205 att_iterator_t it; 206 bool ok = att_find_handle(&it, attribute_handle); 207 if (!ok){ 208 return NULL; 209 } 210 if ((it.flags & (uint16_t)ATT_PROPERTY_DYNAMIC) != 0u){ 211 return NULL; 212 } 213 *out_value_len = it.value_len; 214 return it.value; 215 } 216 217 // end of client API 218 219 static void att_update_value_len(att_iterator_t *it, uint16_t offset, hci_con_handle_t con_handle) { 220 if ((it->flags & (uint16_t)ATT_PROPERTY_DYNAMIC) == 0u){ 221 return; 222 } 223 it->value_len = (*att_read_callback)(con_handle, it->handle, offset, NULL, 0); 224 return; 225 } 226 227 // copy attribute value from offset into buffer with given size 228 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){ 229 230 // DYNAMIC 231 if ((it->flags & (uint16_t)ATT_PROPERTY_DYNAMIC) != 0u){ 232 return (*att_read_callback)(con_handle, it->handle, offset, buffer, buffer_size); 233 } 234 235 // STATIC 236 uint16_t bytes_to_copy = btstack_min(it->value_len - offset, buffer_size); 237 (void)memcpy(buffer, it->value, bytes_to_copy); 238 return bytes_to_copy; 239 } 240 241 void att_set_db(uint8_t const * db){ 242 // validate db version 243 if (db == NULL){ 244 return; 245 } 246 if (*db != (uint8_t)ATT_DB_VERSION){ 247 log_error("ATT DB version differs, please regenerate .h from .gatt file or update att_db_util.c"); 248 return; 249 } 250 log_info("att_set_db %p", db); 251 // ignore db version 252 att_database = &db[1]; 253 } 254 255 void att_set_read_callback(att_read_callback_t callback){ 256 att_read_callback = callback; 257 } 258 259 void att_set_write_callback(att_write_callback_t callback){ 260 att_write_callback = callback; 261 } 262 263 void att_dump_attributes(void){ 264 att_iterator_t it; 265 att_iterator_init(&it); 266 uint8_t uuid128[16]; 267 log_info("att_dump_attributes, table %p", att_database); 268 while (att_iterator_has_next(&it)){ 269 att_iterator_fetch_next(&it); 270 if (it.handle == 0u) { 271 log_info("Handle: END"); 272 return; 273 } 274 log_info("Handle: 0x%04x, flags: 0x%04x, uuid: ", it.handle, it.flags); 275 if ((it.flags & (uint16_t)ATT_PROPERTY_UUID128) != 0u){ 276 reverse_128(it.uuid, uuid128); 277 log_info("%s", uuid128_to_str(uuid128)); 278 } else { 279 log_info("%04x", little_endian_read_16(it.uuid, 0)); 280 } 281 log_info(", value_len: %u, value: ", it.value_len); 282 log_info_hexdump(it.value, it.value_len); 283 } 284 } 285 286 static void att_prepare_write_reset(void){ 287 att_prepare_write_error_code = 0; 288 att_prepare_write_error_handle = 0x0000; 289 } 290 291 static void att_prepare_write_update_errors(uint8_t error_code, uint16_t handle){ 292 // first ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH has highest priority 293 if ((error_code == (uint8_t)ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH) && (error_code != (uint8_t)att_prepare_write_error_code)){ 294 att_prepare_write_error_code = error_code; 295 att_prepare_write_error_handle = handle; 296 return; 297 } 298 // first ATT_ERROR_INVALID_OFFSET is next 299 if ((error_code == (uint8_t)ATT_ERROR_INVALID_OFFSET) && (att_prepare_write_error_code == 0)){ 300 att_prepare_write_error_code = error_code; 301 att_prepare_write_error_handle = handle; 302 return; 303 } 304 } 305 306 static uint16_t setup_error(uint8_t * response_buffer, uint8_t request_opcode, uint16_t handle, uint8_t error_code){ 307 response_buffer[0] = (uint8_t)ATT_ERROR_RESPONSE; 308 response_buffer[1] = request_opcode; 309 little_endian_store_16(response_buffer, 2, handle); 310 response_buffer[4] = error_code; 311 return 5; 312 } 313 314 static inline uint16_t setup_error_read_not_permitted(uint8_t * response_buffer, uint8_t request_opcode, uint16_t start_handle){ 315 return setup_error(response_buffer, request_opcode, start_handle, ATT_ERROR_READ_NOT_PERMITTED); 316 } 317 318 static inline uint16_t setup_error_write_not_permitted(uint8_t * response_buffer, uint8_t request, uint16_t start_handle){ 319 return setup_error(response_buffer, request, start_handle, ATT_ERROR_WRITE_NOT_PERMITTED); 320 } 321 322 static inline uint16_t setup_error_atribute_not_found(uint8_t * response_buffer, uint8_t request_opcode, uint16_t start_handle){ 323 return setup_error(response_buffer, request_opcode, start_handle, ATT_ERROR_ATTRIBUTE_NOT_FOUND); 324 } 325 326 static inline uint16_t setup_error_invalid_handle(uint8_t * response_buffer, uint8_t request_opcode, uint16_t handle){ 327 return setup_error(response_buffer, request_opcode, handle, ATT_ERROR_INVALID_HANDLE); 328 } 329 330 static inline uint16_t setup_error_invalid_offset(uint8_t * response_buffer, uint8_t request_opcode, uint16_t handle){ 331 return setup_error(response_buffer, request_opcode, handle, ATT_ERROR_INVALID_OFFSET); 332 } 333 334 static inline uint16_t setup_error_invalid_pdu(uint8_t *response_buffer, uint8_t request_opcode) { 335 return setup_error(response_buffer, request_opcode, 0, ATT_ERROR_INVALID_PDU); 336 } 337 338 struct att_security_settings { 339 uint8_t required_security_level; 340 bool requires_secure_connection; 341 }; 342 343 static void att_validate_security_get_settings(struct att_security_settings * security_settings, att_operation_t operation, att_iterator_t *it){ 344 security_settings->required_security_level = 0u; 345 security_settings->requires_secure_connection = false; 346 switch (operation){ 347 case ATT_READ: 348 if ((it->flags & (uint16_t)ATT_PROPERTY_READ_PERMISSION_BIT_0) != 0u){ 349 security_settings->required_security_level |= 1u; 350 } 351 if ((it->flags & (uint16_t)ATT_PROPERTY_READ_PERMISSION_BIT_1) != 0u){ 352 security_settings->required_security_level |= 2u; 353 } 354 if ((it->flags & (uint16_t)ATT_PROPERTY_READ_PERMISSION_SC) != 0u){ 355 security_settings->requires_secure_connection = true; 356 } 357 break; 358 case ATT_WRITE: 359 if ((it->flags & (uint16_t)ATT_PROPERTY_WRITE_PERMISSION_BIT_0) != 0u){ 360 security_settings->required_security_level |= 1u; 361 } 362 if ((it->flags & (uint16_t)ATT_PROPERTY_WRITE_PERMISSION_BIT_1) != 0u){ 363 security_settings->required_security_level |= 2u; 364 } 365 if ((it->flags & (uint16_t)ATT_PROPERTY_WRITE_PERMISSION_SC) != 0u){ 366 security_settings->requires_secure_connection = true; 367 } 368 break; 369 default: 370 btstack_assert(false); 371 break; 372 } 373 } 374 375 static uint8_t att_validate_security(att_connection_t * att_connection, att_operation_t operation, att_iterator_t * it){ 376 struct att_security_settings security_settings; 377 att_validate_security_get_settings(&security_settings, operation, it); 378 379 uint8_t required_encryption_size = (uint8_t)(it->flags >> 12); 380 if (required_encryption_size != 0u){ 381 required_encryption_size++; // store -1 to fit into 4 bit 382 } 383 log_debug("att_validate_security. flags 0x%04x (=> security level %u, key size %u) authorized %u, authenticated %u, encryption_key_size %u, secure connection %u", 384 it->flags, security_settings.required_security_level, required_encryption_size, att_connection->authorized, att_connection->authenticated, att_connection->encryption_key_size, att_connection->secure_connection); 385 386 bool sc_missing = security_settings.requires_secure_connection && (att_connection->secure_connection == 0u); 387 switch (security_settings.required_security_level){ 388 case ATT_SECURITY_AUTHORIZED: 389 if ((att_connection->authorized == 0u) || sc_missing){ 390 return ATT_ERROR_INSUFFICIENT_AUTHORIZATION; 391 } 392 /* fall through */ 393 case ATT_SECURITY_AUTHENTICATED: 394 if ((att_connection->authenticated == 0u) || sc_missing){ 395 return ATT_ERROR_INSUFFICIENT_AUTHENTICATION; 396 } 397 /* fall through */ 398 case ATT_SECURITY_ENCRYPTED: 399 if ((required_encryption_size > 0u) && ((att_connection->encryption_key_size == 0u) || sc_missing)){ 400 return ATT_ERROR_INSUFFICIENT_ENCRYPTION; 401 } 402 if (required_encryption_size > att_connection->encryption_key_size){ 403 return ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE; 404 } 405 break; 406 default: 407 break; 408 } 409 return ATT_ERROR_SUCCESS; 410 } 411 412 // 413 // MARK: ATT_EXCHANGE_MTU_REQUEST 414 // 415 static uint16_t handle_exchange_mtu_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 416 uint8_t * response_buffer){ 417 418 if (request_len != 3u){ 419 return setup_error_invalid_pdu(response_buffer, ATT_EXCHANGE_MTU_REQUEST); 420 } 421 422 uint16_t client_rx_mtu = little_endian_read_16(request_buffer, 1); 423 424 // find min(local max mtu, remote mtu) >= ATT_DEFAULT_MTU and use as mtu for this connection 425 uint16_t min_mtu = btstack_min(client_rx_mtu, att_connection->max_mtu); 426 uint16_t new_mtu = btstack_max(ATT_DEFAULT_MTU, min_mtu); 427 att_connection->mtu_exchanged = true; 428 att_connection->mtu = new_mtu; 429 430 response_buffer[0] = ATT_EXCHANGE_MTU_RESPONSE; 431 little_endian_store_16(response_buffer, 1, att_connection->mtu); 432 return 3; 433 } 434 435 436 // 437 // MARK: ATT_FIND_INFORMATION_REQUEST 438 // 439 // TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID 440 // 441 static uint16_t handle_find_information_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, 442 uint16_t start_handle, uint16_t end_handle){ 443 444 UNUSED(att_connection); 445 446 log_info("ATT_FIND_INFORMATION_REQUEST: from %04X to %04X", start_handle, end_handle); 447 uint8_t request_type = ATT_FIND_INFORMATION_REQUEST; 448 449 if ((start_handle > end_handle) || (start_handle == 0u)){ 450 return setup_error_invalid_handle(response_buffer, request_type, start_handle); 451 } 452 453 uint16_t offset = 1; 454 uint16_t uuid_len = 0; 455 456 att_iterator_t it; 457 att_iterator_init(&it); 458 while (att_iterator_has_next(&it)){ 459 att_iterator_fetch_next(&it); 460 if (!it.handle){ 461 break; 462 } 463 if (it.handle > end_handle){ 464 break; 465 } 466 if (it.handle < start_handle){ 467 continue; 468 } 469 470 // log_info("Handle 0x%04x", it.handle); 471 472 uint16_t this_uuid_len = (it.flags & (uint16_t)ATT_PROPERTY_UUID128) ? 16u : 2u; 473 474 // check if value has same len as last one if not first result 475 if (offset > 1u){ 476 if (this_uuid_len != uuid_len) { 477 break; 478 } 479 } 480 481 // first 482 if (offset == 1u) { 483 uuid_len = this_uuid_len; 484 // set format field 485 response_buffer[offset] = (it.flags & (uint16_t)ATT_PROPERTY_UUID128) ? 0x02u : 0x01u; 486 offset++; 487 } 488 489 // space? 490 if ((offset + 2u + uuid_len) > response_buffer_size){ 491 break; 492 } 493 494 // store 495 little_endian_store_16(response_buffer, offset, it.handle); 496 offset += 2u; 497 498 (void)memcpy(response_buffer + offset, it.uuid, uuid_len); 499 offset += uuid_len; 500 } 501 502 if (offset == 1u){ 503 return setup_error_atribute_not_found(response_buffer, request_type, start_handle); 504 } 505 506 response_buffer[0] = ATT_FIND_INFORMATION_REPLY; 507 return offset; 508 } 509 510 static uint16_t handle_find_information_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 511 uint8_t * response_buffer, uint16_t response_buffer_size){ 512 513 if (request_len != 5u){ 514 return setup_error_invalid_pdu(response_buffer, ATT_FIND_INFORMATION_REQUEST); 515 } 516 517 uint16_t start_handle = little_endian_read_16(request_buffer, 1); 518 uint16_t end_handle = little_endian_read_16(request_buffer, 3); 519 return handle_find_information_request2(att_connection, response_buffer, response_buffer_size, start_handle, end_handle); 520 } 521 522 // 523 // MARK: ATT_FIND_BY_TYPE_VALUE 524 // 525 // "Only attributes with attribute handles between and including the Starting Handle parameter 526 // and the Ending Handle parameter that match the requested attri- bute type and the attribute 527 // value that have sufficient permissions to allow reading will be returned" -> (1) 528 // 529 // TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID 530 // 531 // NOTE: doesn't handle DYNAMIC values 532 // NOTE: only supports 16 bit UUIDs 533 // 534 static uint16_t handle_find_by_type_value_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 535 uint8_t * response_buffer, uint16_t response_buffer_size){ 536 UNUSED(att_connection); 537 538 if (request_len < 7u){ 539 return setup_error_invalid_pdu(response_buffer, ATT_FIND_BY_TYPE_VALUE_REQUEST); 540 } 541 542 // parse request 543 uint16_t start_handle = little_endian_read_16(request_buffer, 1); 544 uint16_t end_handle = little_endian_read_16(request_buffer, 3); 545 uint16_t attribute_type = little_endian_read_16(request_buffer, 5); 546 const uint8_t *attribute_value = &request_buffer[7]; 547 uint16_t attribute_len = request_len - 7u; 548 549 log_info("ATT_FIND_BY_TYPE_VALUE_REQUEST: from %04X to %04X, type %04X, value: ", start_handle, end_handle, attribute_type); 550 log_info_hexdump(attribute_value, attribute_len); 551 uint8_t request_type = ATT_FIND_BY_TYPE_VALUE_REQUEST; 552 553 if ((start_handle > end_handle) || (start_handle == 0u)){ 554 return setup_error_invalid_handle(response_buffer, request_type, start_handle); 555 } 556 557 uint16_t offset = 1; 558 bool in_group = false; 559 uint16_t prev_handle = 0; 560 561 att_iterator_t it; 562 att_iterator_init(&it); 563 while (att_iterator_has_next(&it)){ 564 att_iterator_fetch_next(&it); 565 566 if ((it.handle != 0u) && (it.handle < start_handle)){ 567 continue; 568 } 569 if (it.handle > end_handle){ 570 break; // (1) 571 } 572 573 // close current tag, if within a group and a new service definition starts or we reach end of att db 574 if (in_group && 575 ((it.handle == 0u) || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){ 576 577 log_info("End of group, handle 0x%04x", prev_handle); 578 little_endian_store_16(response_buffer, offset, prev_handle); 579 offset += 2u; 580 in_group = false; 581 582 // check if space for another handle pair available 583 if ((offset + 4u) > response_buffer_size){ 584 break; 585 } 586 } 587 588 // keep track of previous handle 589 prev_handle = it.handle; 590 591 // does current attribute match 592 if ((it.handle != 0u) && att_iterator_match_uuid16(&it, attribute_type) && (attribute_len == it.value_len) && (memcmp(attribute_value, it.value, it.value_len) == 0)){ 593 log_info("Begin of group, handle 0x%04x", it.handle); 594 little_endian_store_16(response_buffer, offset, it.handle); 595 offset += 2u; 596 in_group = true; 597 } 598 } 599 600 if (offset == 1u){ 601 return setup_error_atribute_not_found(response_buffer, request_type, start_handle); 602 } 603 604 response_buffer[0] = ATT_FIND_BY_TYPE_VALUE_RESPONSE; 605 return offset; 606 } 607 608 // 609 // MARK: ATT_READ_BY_TYPE_REQUEST 610 // 611 static uint16_t handle_read_by_type_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, 612 uint16_t start_handle, uint16_t end_handle, 613 uint16_t attribute_type_len, uint8_t * attribute_type){ 614 615 log_info("ATT_READ_BY_TYPE_REQUEST: from %04X to %04X, type: ", start_handle, end_handle); 616 log_info_hexdump(attribute_type, attribute_type_len); 617 uint8_t request_type = ATT_READ_BY_TYPE_REQUEST; 618 619 if ((start_handle > end_handle) || (start_handle == 0u)){ 620 return setup_error_invalid_handle(response_buffer, request_type, start_handle); 621 } 622 623 uint16_t offset = 1; 624 uint16_t pair_len = 0; 625 626 att_iterator_t it; 627 att_iterator_init(&it); 628 uint8_t error_code = 0; 629 uint16_t first_matching_but_unreadable_handle = 0; 630 631 while (att_iterator_has_next(&it)){ 632 att_iterator_fetch_next(&it); 633 634 if ((it.handle == 0u ) || (it.handle > end_handle)){ 635 break; 636 } 637 638 // does current attribute match 639 if ((it.handle < start_handle) || !att_iterator_match_uuid(&it, attribute_type, attribute_type_len)){ 640 continue; 641 } 642 643 // skip handles that cannot be read but remember that there has been at least one 644 if ((it.flags & (uint16_t)ATT_PROPERTY_READ) == 0u) { 645 if (first_matching_but_unreadable_handle == 0u) { 646 first_matching_but_unreadable_handle = it.handle; 647 } 648 continue; 649 } 650 651 // check security requirements 652 error_code = att_validate_security(att_connection, ATT_READ, &it); 653 if (error_code != 0u){ 654 break; 655 } 656 657 att_update_value_len(&it, 0, att_connection->con_handle); 658 659 #ifdef ENABLE_ATT_DELAYED_RESPONSE 660 if (it.value_len == (uint16_t)ATT_READ_RESPONSE_PENDING){ 661 return ATT_READ_RESPONSE_PENDING; 662 } 663 #endif 664 665 // allow to return ATT Error Code in ATT Read Callback 666 if (it.value_len > (uint16_t)ATT_READ_ERROR_CODE_OFFSET){ 667 error_code = (uint8_t)(it.value_len - (uint16_t)ATT_READ_ERROR_CODE_OFFSET); 668 break; 669 } 670 671 // check if value has same len as last one 672 uint16_t this_pair_len = 2u + it.value_len; 673 if ((offset > 1u) && (pair_len != this_pair_len)) { 674 break; 675 } 676 677 // first 678 if (offset == 1u) { 679 pair_len = this_pair_len; 680 response_buffer[offset] = (uint8_t) pair_len; 681 offset++; 682 } 683 684 // space? 685 if ((offset + pair_len) > response_buffer_size) { 686 if (offset > 2u){ 687 break; 688 } 689 it.value_len = response_buffer_size - 4u; 690 response_buffer[1u] = 2u + it.value_len; 691 } 692 693 // store 694 little_endian_store_16(response_buffer, offset, it.handle); 695 offset += 2u; 696 uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len, att_connection->con_handle); 697 offset += bytes_copied; 698 } 699 700 // at least one attribute could be read 701 if (offset > 1u){ 702 response_buffer[0] = ATT_READ_BY_TYPE_RESPONSE; 703 return offset; 704 } 705 706 // first attribute had an error 707 if (error_code != 0u){ 708 return setup_error(response_buffer, request_type, start_handle, error_code); 709 } 710 711 // no other errors, but all found attributes had been non-readable 712 if (first_matching_but_unreadable_handle != 0u){ 713 return setup_error_read_not_permitted(response_buffer, request_type, first_matching_but_unreadable_handle); 714 } 715 716 // attribute not found 717 return setup_error_atribute_not_found(response_buffer, request_type, start_handle); 718 } 719 720 static uint16_t handle_read_by_type_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 721 uint8_t * response_buffer, uint16_t response_buffer_size){ 722 723 uint16_t attribute_type_len; 724 switch (request_len){ 725 case 7: 726 attribute_type_len = 2; 727 break; 728 case 21: 729 attribute_type_len = 16; 730 break; 731 default: 732 return setup_error_invalid_pdu(response_buffer, ATT_READ_BY_TYPE_REQUEST); 733 } 734 735 uint16_t start_handle = little_endian_read_16(request_buffer, 1); 736 uint16_t end_handle = little_endian_read_16(request_buffer, 3); 737 return handle_read_by_type_request2(att_connection, response_buffer, response_buffer_size, start_handle, end_handle, attribute_type_len, &request_buffer[5]); 738 } 739 740 // 741 // MARK: ATT_READ_BY_TYPE_REQUEST 742 // 743 static uint16_t handle_read_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle){ 744 745 log_info("ATT_READ_REQUEST: handle %04x", handle); 746 uint8_t request_type = ATT_READ_REQUEST; 747 748 att_iterator_t it; 749 bool ok = att_find_handle(&it, handle); 750 if (!ok){ 751 return setup_error_invalid_handle(response_buffer, request_type, handle); 752 } 753 754 // check if handle can be read 755 if ((it.flags & (uint16_t)ATT_PROPERTY_READ) == 0u) { 756 return setup_error_read_not_permitted(response_buffer, request_type, handle); 757 } 758 759 // check security requirements 760 uint8_t error_code = att_validate_security(att_connection, ATT_READ, &it); 761 if (error_code != 0u) { 762 return setup_error(response_buffer, request_type, handle, error_code); 763 } 764 765 att_update_value_len(&it, 0, att_connection->con_handle); 766 767 #ifdef ENABLE_ATT_DELAYED_RESPONSE 768 if (it.value_len == (uint16_t)ATT_READ_RESPONSE_PENDING){ 769 return ATT_READ_RESPONSE_PENDING; 770 } 771 #endif 772 773 // allow to return ATT Error Code in ATT Read Callback 774 if (it.value_len > (uint16_t)ATT_READ_ERROR_CODE_OFFSET){ 775 error_code = (uint8_t)(it.value_len - (uint16_t)ATT_READ_ERROR_CODE_OFFSET); 776 return setup_error(response_buffer, request_type, handle, error_code); 777 } 778 779 // store 780 uint16_t offset = 1; 781 uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, response_buffer_size - offset, att_connection->con_handle); 782 offset += bytes_copied; 783 784 response_buffer[0] = ATT_READ_RESPONSE; 785 return offset; 786 } 787 788 static uint16_t handle_read_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 789 uint8_t * response_buffer, uint16_t response_buffer_size){ 790 791 if (request_len != 3u){ 792 return setup_error_invalid_pdu(response_buffer, ATT_READ_REQUEST); 793 } 794 795 uint16_t handle = little_endian_read_16(request_buffer, 1); 796 return handle_read_request2(att_connection, response_buffer, response_buffer_size, handle); 797 } 798 799 //s 800 // MARK: ATT_READ_BLOB_REQUEST 0x0c 801 // 802 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){ 803 log_info("ATT_READ_BLOB_REQUEST: handle %04x, offset %u", handle, value_offset); 804 uint8_t request_type = ATT_READ_BLOB_REQUEST; 805 806 att_iterator_t it; 807 bool ok = att_find_handle(&it, handle); 808 if (!ok){ 809 return setup_error_invalid_handle(response_buffer, request_type, handle); 810 } 811 812 // check if handle can be read 813 if ((it.flags & (uint16_t)ATT_PROPERTY_READ) == 0u) { 814 return setup_error_read_not_permitted(response_buffer, request_type, handle); 815 } 816 817 // check security requirements 818 uint8_t error_code = att_validate_security(att_connection, ATT_READ, &it); 819 if (error_code != 0u) { 820 return setup_error(response_buffer, request_type, handle, error_code); 821 } 822 823 att_update_value_len(&it, value_offset, att_connection->con_handle); 824 825 #ifdef ENABLE_ATT_DELAYED_RESPONSE 826 if (it.value_len == (uint16_t)ATT_READ_RESPONSE_PENDING){ 827 return ATT_READ_RESPONSE_PENDING; 828 } 829 #endif 830 831 // allow to return ATT Error Code in ATT Read Callback 832 if (it.value_len > (uint16_t)ATT_READ_ERROR_CODE_OFFSET){ 833 error_code = (uint8_t)(it.value_len - (uint16_t)ATT_READ_ERROR_CODE_OFFSET); 834 return setup_error(response_buffer, request_type, handle, error_code); 835 } 836 837 if (value_offset > it.value_len){ 838 return setup_error_invalid_offset(response_buffer, request_type, handle); 839 } 840 841 // prepare response 842 response_buffer[0] = ATT_READ_BLOB_RESPONSE; 843 uint16_t offset = 1; 844 845 // fetch more data if available 846 if (value_offset < it.value_len){ 847 uint16_t bytes_copied = att_copy_value(&it, value_offset, &response_buffer[offset], response_buffer_size - offset, att_connection->con_handle); 848 offset += bytes_copied; 849 } 850 return offset; 851 } 852 853 static uint16_t handle_read_blob_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 854 uint8_t * response_buffer, uint16_t response_buffer_size){ 855 856 if (request_len != 5u){ 857 return setup_error_invalid_pdu(response_buffer, ATT_READ_BLOB_REQUEST); 858 } 859 860 uint16_t handle = little_endian_read_16(request_buffer, 1); 861 uint16_t value_offset = little_endian_read_16(request_buffer, 3); 862 return handle_read_blob_request2(att_connection, response_buffer, response_buffer_size, handle, value_offset); 863 } 864 865 // 866 // MARK: ATT_READ_MULTIPLE_REQUEST 0x0e 867 // MARK: ATT_READ_MULTIPLE_REQUEST 0x20 868 // 869 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, bool store_length){ 870 log_info("ATT_READ_MULTIPLE_(VARIABLE_)REQUEST: num handles %u", num_handles); 871 uint8_t request_type = store_length ? ATT_READ_MULTIPLE_VARIABLE_REQ : ATT_READ_MULTIPLE_REQUEST; 872 uint8_t response_type = store_length ? ATT_READ_MULTIPLE_VARIABLE_RSP : ATT_READ_MULTIPLE_RESPONSE; 873 uint16_t offset = 1; 874 875 uint16_t i; 876 uint8_t error_code = 0; 877 uint16_t handle = 0; 878 879 #ifdef ENABLE_ATT_DELAYED_RESPONSE 880 bool read_request_pending = false; 881 #endif 882 883 for (i=0; i<num_handles; i++){ 884 handle = little_endian_read_16(handles, i << 1); 885 886 if (handle == 0u){ 887 return setup_error_invalid_handle(response_buffer, request_type, handle); 888 } 889 890 att_iterator_t it; 891 892 bool ok = att_find_handle(&it, handle); 893 if (!ok){ 894 return setup_error_invalid_handle(response_buffer, request_type, handle); 895 } 896 897 // check if handle can be read 898 if ((it.flags & (uint16_t)ATT_PROPERTY_READ) == 0u) { 899 error_code = (uint8_t)ATT_ERROR_READ_NOT_PERMITTED; 900 break; 901 } 902 903 // check security requirements 904 error_code = att_validate_security(att_connection, ATT_READ, &it); 905 if (error_code != 0u){ 906 break; 907 } 908 909 att_update_value_len(&it, 0, att_connection->con_handle); 910 911 #ifdef ENABLE_ATT_DELAYED_RESPONSE 912 if (it.value_len == (uint16_t)ATT_READ_RESPONSE_PENDING) { 913 read_request_pending = true; 914 } 915 if (read_request_pending){ 916 continue; 917 } 918 #endif 919 920 // allow to return ATT Error Code in ATT Read Callback 921 if (it.value_len > (uint16_t)ATT_READ_ERROR_CODE_OFFSET){ 922 error_code = (uint8_t)(it.value_len - (uint16_t)ATT_READ_ERROR_CODE_OFFSET); 923 break; 924 } 925 926 #ifdef ENABLE_GATT_OVER_EATT 927 // assert that at least Value Length can be stored 928 if (store_length && ((offset + 2) >= response_buffer_size)){ 929 break; 930 } 931 // skip length field 932 uint16_t offset_value_length = offset; 933 if (store_length){ 934 offset += 2; 935 } 936 #endif 937 // store data 938 uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, response_buffer_size - offset, att_connection->con_handle); 939 offset += bytes_copied; 940 #ifdef ENABLE_GATT_OVER_EATT 941 // set length field 942 if (store_length) { 943 little_endian_store_16(response_buffer, offset_value_length, bytes_copied); 944 } 945 #endif 946 } 947 948 if (error_code != 0u){ 949 return setup_error(response_buffer, request_type, handle, error_code); 950 } 951 952 response_buffer[0] = (uint8_t)response_type; 953 return offset; 954 } 955 956 static uint16_t 957 handle_read_multiple_request(att_connection_t *att_connection, uint8_t *request_buffer, uint16_t request_len, 958 uint8_t *response_buffer, uint16_t response_buffer_size, bool store_length) { 959 960 uint8_t request_type = store_length ? ATT_READ_MULTIPLE_VARIABLE_REQ : ATT_READ_MULTIPLE_REQUEST; 961 962 // 1 byte opcode + two or more attribute handles (2 bytes each) 963 if ( (request_len < 5u) || ((request_len & 1u) == 0u) ){ 964 return setup_error_invalid_pdu(response_buffer, request_type); 965 } 966 967 uint8_t num_handles = (request_len - 1u) >> 1u; 968 return handle_read_multiple_request2(att_connection, response_buffer, response_buffer_size, num_handles, 969 &request_buffer[1], store_length); 970 } 971 972 // 973 // MARK: ATT_READ_BY_GROUP_TYPE_REQUEST 0x10 974 // 975 // Only handles GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID 976 // Core v4.0, vol 3, part g, 2.5.3 977 // "The «Primary Service» and «Secondary Service» grouping types may be used in the Read By Group Type Request. 978 // The «Characteristic» grouping type shall not be used in the ATT Read By Group Type Request." 979 // 980 // NOTE: doesn't handle DYNAMIC values 981 // 982 // NOTE: we don't check for security as PRIMARY and SECONDAY SERVICE definition shouldn't be protected 983 // Core 4.0, vol 3, part g, 8.1 984 // "The list of services and characteristics that a device supports is not considered private or 985 // confidential information, and therefore the Service and Characteristic Discovery procedures 986 // shall always be permitted. " 987 // 988 static uint16_t handle_read_by_group_type_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, 989 uint16_t start_handle, uint16_t end_handle, 990 uint16_t attribute_type_len, uint8_t * attribute_type){ 991 992 UNUSED(att_connection); 993 994 log_info("ATT_READ_BY_GROUP_TYPE_REQUEST: from %04X to %04X, buffer size %u, type: ", start_handle, end_handle, response_buffer_size); 995 log_info_hexdump(attribute_type, attribute_type_len); 996 uint8_t request_type = ATT_READ_BY_GROUP_TYPE_REQUEST; 997 998 if ((start_handle > end_handle) || (start_handle == 0u)){ 999 return setup_error_invalid_handle(response_buffer, request_type, start_handle); 1000 } 1001 1002 // assert UUID is primary or secondary service uuid 1003 uint16_t uuid16 = uuid16_from_uuid(attribute_type_len, attribute_type); 1004 if ((uuid16 != (uint16_t)GATT_PRIMARY_SERVICE_UUID) && (uuid16 != (uint16_t)GATT_SECONDARY_SERVICE_UUID)){ 1005 return setup_error(response_buffer, request_type, start_handle, ATT_ERROR_UNSUPPORTED_GROUP_TYPE); 1006 } 1007 1008 uint16_t offset = 1; 1009 uint16_t pair_len = 0; 1010 bool in_group = false; 1011 uint16_t group_start_handle = 0; 1012 uint8_t const * group_start_value = NULL; 1013 uint16_t prev_handle = 0; 1014 1015 att_iterator_t it; 1016 att_iterator_init(&it); 1017 while (att_iterator_has_next(&it)){ 1018 att_iterator_fetch_next(&it); 1019 1020 if ((it.handle != 0u) && (it.handle < start_handle)){ 1021 continue; 1022 } 1023 if (it.handle > end_handle){ 1024 break; // (1) 1025 } 1026 1027 // log_info("Handle 0x%04x", it.handle); 1028 1029 // close current tag, if within a group and a new service definition starts or we reach end of att db 1030 if (in_group && 1031 ((it.handle == 0u) || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){ 1032 // log_info("End of group, handle 0x%04x, val_len: %u", prev_handle, pair_len - 4); 1033 1034 little_endian_store_16(response_buffer, offset, group_start_handle); 1035 offset += 2u; 1036 little_endian_store_16(response_buffer, offset, prev_handle); 1037 offset += 2u; 1038 (void)memcpy(response_buffer + offset, group_start_value, 1039 pair_len - 4u); 1040 offset += pair_len - 4u; 1041 in_group = false; 1042 1043 // check if space for another handle pair available 1044 if ((offset + pair_len) > response_buffer_size){ 1045 break; 1046 } 1047 } 1048 1049 // keep track of previous handle 1050 prev_handle = it.handle; 1051 1052 // does current attribute match 1053 // log_info("compare: %04x == %04x", *(uint16_t*) context->attribute_type, *(uint16_t*) uuid); 1054 if ((it.handle != 0u) && att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) { 1055 1056 // check if value has same len as last one 1057 uint16_t this_pair_len = 4u + it.value_len; 1058 if (offset > 1u){ 1059 if (this_pair_len != pair_len) { 1060 break; 1061 } 1062 } 1063 1064 // log_info("Begin of group, handle 0x%04x", it.handle); 1065 1066 // first 1067 if (offset == 1u) { 1068 pair_len = this_pair_len; 1069 response_buffer[offset] = (uint8_t) this_pair_len; 1070 offset++; 1071 } 1072 1073 group_start_handle = it.handle; 1074 group_start_value = it.value; 1075 in_group = true; 1076 } 1077 } 1078 1079 if (offset == 1u){ 1080 return setup_error_atribute_not_found(response_buffer, request_type, start_handle); 1081 } 1082 1083 response_buffer[0] = ATT_READ_BY_GROUP_TYPE_RESPONSE; 1084 return offset; 1085 } 1086 1087 static uint16_t handle_read_by_group_type_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 1088 uint8_t * response_buffer, uint16_t response_buffer_size){ 1089 uint16_t attribute_type_len; 1090 switch (request_len){ 1091 case 7: 1092 attribute_type_len = 2; 1093 break; 1094 case 21: 1095 attribute_type_len = 16; 1096 break; 1097 default: 1098 return setup_error_invalid_pdu(response_buffer, ATT_READ_BY_GROUP_TYPE_REQUEST); 1099 } 1100 1101 uint16_t start_handle = little_endian_read_16(request_buffer, 1); 1102 uint16_t end_handle = little_endian_read_16(request_buffer, 3); 1103 return handle_read_by_group_type_request2(att_connection, response_buffer, response_buffer_size, start_handle, end_handle, attribute_type_len, &request_buffer[5]); 1104 } 1105 1106 // 1107 // MARK: ATT_WRITE_REQUEST 0x12 1108 static uint16_t handle_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 1109 uint8_t * response_buffer, uint16_t response_buffer_size){ 1110 1111 UNUSED(response_buffer_size); 1112 1113 if (request_len < 3u){ 1114 return setup_error_invalid_pdu(response_buffer, ATT_WRITE_REQUEST); 1115 } 1116 1117 uint8_t request_type = ATT_WRITE_REQUEST; 1118 1119 uint16_t handle = little_endian_read_16(request_buffer, 1); 1120 att_iterator_t it; 1121 bool ok = att_find_handle(&it, handle); 1122 if (!ok) { 1123 return setup_error_invalid_handle(response_buffer, request_type, handle); 1124 } 1125 if (att_write_callback == NULL) { 1126 return setup_error_write_not_permitted(response_buffer, request_type, handle); 1127 } 1128 if ((it.flags & (uint16_t)ATT_PROPERTY_WRITE) == 0u) { 1129 return setup_error_write_not_permitted(response_buffer, request_type, handle); 1130 } 1131 if ((it.flags & (uint16_t)ATT_PROPERTY_DYNAMIC) == 0u) { 1132 return setup_error_write_not_permitted(response_buffer, request_type, handle); 1133 } 1134 // check security requirements 1135 int error_code = att_validate_security(att_connection, ATT_WRITE, &it); 1136 if (error_code != 0) { 1137 return setup_error(response_buffer, request_type, handle, error_code); 1138 } 1139 att_persistent_ccc_cache(&it); 1140 error_code = (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0u, request_buffer + 3u, request_len - 3u); 1141 1142 #ifdef ENABLE_ATT_DELAYED_RESPONSE 1143 if (error_code == ATT_ERROR_WRITE_RESPONSE_PENDING){ 1144 return ATT_INTERNAL_WRITE_RESPONSE_PENDING; 1145 } 1146 #endif 1147 1148 if (error_code != 0) { 1149 return setup_error(response_buffer, request_type, handle, error_code); 1150 } 1151 response_buffer[0] = (uint8_t)ATT_WRITE_RESPONSE; 1152 return 1; 1153 } 1154 1155 // 1156 // MARK: ATT_PREPARE_WRITE_REQUEST 0x16 1157 static uint16_t handle_prepare_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 1158 uint8_t * response_buffer, uint16_t response_buffer_size){ 1159 1160 uint8_t request_type = ATT_PREPARE_WRITE_REQUEST; 1161 1162 if (request_len < 5u){ 1163 return setup_error_invalid_pdu(response_buffer, request_type); 1164 } 1165 1166 uint16_t handle = little_endian_read_16(request_buffer, 1); 1167 uint16_t offset = little_endian_read_16(request_buffer, 3); 1168 if (att_write_callback == NULL) { 1169 return setup_error_write_not_permitted(response_buffer, request_type, handle); 1170 } 1171 att_iterator_t it; 1172 if (att_find_handle(&it, handle) == false) { 1173 return setup_error_invalid_handle(response_buffer, request_type, handle); 1174 } 1175 if ((it.flags & (uint16_t)ATT_PROPERTY_WRITE) == 0u) { 1176 return setup_error_write_not_permitted(response_buffer, request_type, handle); 1177 } 1178 if ((it.flags & (uint16_t)ATT_PROPERTY_DYNAMIC) == 0u) { 1179 return setup_error_write_not_permitted(response_buffer, request_type, handle); 1180 } 1181 // check security requirements 1182 int error_code = att_validate_security(att_connection, ATT_WRITE, &it); 1183 if (error_code != 0) { 1184 return setup_error(response_buffer, request_type, handle, error_code); 1185 } 1186 1187 error_code = (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_ACTIVE, offset, request_buffer + 5u, request_len - 5u); 1188 switch (error_code){ 1189 case 0: 1190 break; 1191 case ATT_ERROR_INVALID_OFFSET: 1192 case ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH: 1193 // postpone to execute write request 1194 att_prepare_write_update_errors(error_code, handle); 1195 break; 1196 #ifdef ENABLE_ATT_DELAYED_RESPONSE 1197 case ATT_ERROR_WRITE_RESPONSE_PENDING: 1198 return ATT_INTERNAL_WRITE_RESPONSE_PENDING; 1199 #endif 1200 default: 1201 return setup_error(response_buffer, request_type, handle, error_code); 1202 } 1203 1204 // response: echo request 1205 uint16_t bytes_to_echo = btstack_min(request_len, response_buffer_size); 1206 (void)memcpy(response_buffer, request_buffer, bytes_to_echo); 1207 response_buffer[0] = ATT_PREPARE_WRITE_RESPONSE; 1208 return request_len; 1209 } 1210 1211 /* 1212 * @brief transcation queue of prepared writes, e.g., after disconnect 1213 */ 1214 void att_clear_transaction_queue(att_connection_t * att_connection){ 1215 (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_CANCEL, 0, NULL, 0); 1216 } 1217 1218 // MARK: ATT_EXECUTE_WRITE_REQUEST 0x18 1219 // NOTE: security has been verified by handle_prepare_write_request 1220 static uint16_t handle_execute_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, 1221 uint8_t * response_buffer, uint16_t response_buffer_size){ 1222 1223 UNUSED(response_buffer_size); 1224 1225 uint8_t request_type = ATT_EXECUTE_WRITE_REQUEST; 1226 1227 if (request_len < 2u){ 1228 return setup_error_invalid_pdu(response_buffer, request_type); 1229 } 1230 1231 if (att_write_callback == NULL) { 1232 return setup_error_write_not_permitted(response_buffer, request_type, 0); 1233 } 1234 1235 if (request_buffer[1] != 0) { 1236 // validate queued write 1237 if (att_prepare_write_error_code == 0){ 1238 att_prepare_write_error_code = (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_VALIDATE, 0, NULL, 0); 1239 } 1240 #ifdef ENABLE_ATT_DELAYED_RESPONSE 1241 if (att_prepare_write_error_code == ATT_ERROR_WRITE_RESPONSE_PENDING){ 1242 return ATT_INTERNAL_WRITE_RESPONSE_PENDING; 1243 } 1244 #endif 1245 // deliver queued errors 1246 if (att_prepare_write_error_code != 0){ 1247 att_clear_transaction_queue(att_connection); 1248 uint8_t error_code = att_prepare_write_error_code; 1249 uint16_t handle = att_prepare_write_error_handle; 1250 att_prepare_write_reset(); 1251 return setup_error(response_buffer, request_type, handle, error_code); 1252 } 1253 att_write_callback(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_EXECUTE, 0, NULL, 0); 1254 } else { 1255 att_clear_transaction_queue(att_connection); 1256 } 1257 response_buffer[0] = ATT_EXECUTE_WRITE_RESPONSE; 1258 return 1; 1259 } 1260 1261 // MARK: ATT_WRITE_COMMAND 0x52 1262 // Core 4.0, vol 3, part F, 3.4.5.3 1263 // "No Error Response or Write Response shall be sent in response to this command" 1264 static void handle_write_command(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, uint16_t required_flags){ 1265 1266 if (request_len < 3u){ 1267 return; 1268 } 1269 1270 uint16_t handle = little_endian_read_16(request_buffer, 1); 1271 if (att_write_callback == NULL){ 1272 return; 1273 } 1274 1275 att_iterator_t it; 1276 bool ok = att_find_handle(&it, handle); 1277 if (!ok){ 1278 return; 1279 } 1280 if ((it.flags & (uint16_t)ATT_PROPERTY_DYNAMIC) == 0u){ 1281 return; 1282 } 1283 if ((it.flags & required_flags) == 0u){ 1284 return; 1285 } 1286 if (att_validate_security(att_connection, ATT_WRITE, &it) != ATT_ERROR_SUCCESS){ 1287 return; 1288 } 1289 att_persistent_ccc_cache(&it); 1290 (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0u, request_buffer + 3u, request_len - 3u); 1291 } 1292 1293 // MARK: helper for ATT_HANDLE_VALUE_NOTIFICATION and ATT_HANDLE_VALUE_INDICATION 1294 static uint16_t prepare_handle_value(att_connection_t * att_connection, 1295 uint16_t handle, 1296 const uint8_t *value, 1297 uint16_t value_len, 1298 uint8_t * response_buffer){ 1299 little_endian_store_16(response_buffer, 1, handle); 1300 uint16_t bytes_to_copy = btstack_min(value_len, att_connection->mtu - 3u); 1301 (void)memcpy(&response_buffer[3], value, bytes_to_copy); 1302 return value_len + 3u; 1303 } 1304 1305 // MARK: ATT_HANDLE_VALUE_NOTIFICATION 0x1b 1306 uint16_t att_prepare_handle_value_notification(att_connection_t * att_connection, 1307 uint16_t attribute_handle, 1308 const uint8_t *value, 1309 uint16_t value_len, 1310 uint8_t * response_buffer){ 1311 1312 response_buffer[0] = ATT_HANDLE_VALUE_NOTIFICATION; 1313 return prepare_handle_value(att_connection, attribute_handle, value, value_len, response_buffer); 1314 } 1315 1316 // MARK: ATT_MULTIPLE_HANDLE_VALUE_NTF 0x23u 1317 uint16_t att_prepare_handle_value_multiple_notification(att_connection_t * att_connection, 1318 uint8_t num_attributes, 1319 const uint16_t * attribute_handles, 1320 const uint8_t ** values_data, 1321 const uint16_t * values_len, 1322 uint8_t * response_buffer){ 1323 1324 response_buffer[0] = ATT_MULTIPLE_HANDLE_VALUE_NTF; 1325 uint8_t i; 1326 uint16_t offset = 1; 1327 uint16_t response_buffer_size = att_connection->mtu - 3u; 1328 for (i = 0; i < num_attributes; i++) { 1329 uint16_t value_len = values_len[i]; 1330 if ((offset + 4 + value_len) > response_buffer_size){ 1331 break; 1332 } 1333 little_endian_store_16(response_buffer, offset, attribute_handles[i]); 1334 offset += 2; 1335 little_endian_store_16(response_buffer, offset, value_len); 1336 offset += 2; 1337 (void) memcpy(&response_buffer[offset], values_data[i], value_len); 1338 offset += value_len; 1339 } 1340 return offset; 1341 } 1342 1343 // MARK: ATT_HANDLE_VALUE_INDICATION 0x1d 1344 uint16_t att_prepare_handle_value_indication(att_connection_t * att_connection, 1345 uint16_t attribute_handle, 1346 const uint8_t *value, 1347 uint16_t value_len, 1348 uint8_t * response_buffer){ 1349 1350 response_buffer[0] = ATT_HANDLE_VALUE_INDICATION; 1351 return prepare_handle_value(att_connection, attribute_handle, value, value_len, response_buffer); 1352 } 1353 1354 // MARK: Dispatcher 1355 uint16_t att_handle_request(att_connection_t * att_connection, 1356 uint8_t * request_buffer, 1357 uint16_t request_len, 1358 uint8_t * response_buffer){ 1359 uint16_t response_len = 0; 1360 const uint16_t response_buffer_size = att_connection->mtu; 1361 const uint8_t request_opcode = request_buffer[0]; 1362 1363 switch (request_opcode){ 1364 case ATT_EXCHANGE_MTU_REQUEST: 1365 response_len = handle_exchange_mtu_request(att_connection, request_buffer, request_len, response_buffer); 1366 break; 1367 case ATT_FIND_INFORMATION_REQUEST: 1368 response_len = handle_find_information_request(att_connection, request_buffer, request_len,response_buffer, response_buffer_size); 1369 break; 1370 case ATT_FIND_BY_TYPE_VALUE_REQUEST: 1371 response_len = handle_find_by_type_value_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1372 break; 1373 case ATT_READ_BY_TYPE_REQUEST: 1374 response_len = handle_read_by_type_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1375 break; 1376 case ATT_READ_REQUEST: 1377 response_len = handle_read_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1378 break; 1379 case ATT_READ_BLOB_REQUEST: 1380 response_len = handle_read_blob_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1381 break; 1382 case ATT_READ_MULTIPLE_REQUEST: 1383 response_len = handle_read_multiple_request(att_connection, request_buffer, request_len, response_buffer, 1384 response_buffer_size, false); 1385 break; 1386 case ATT_READ_MULTIPLE_VARIABLE_REQ: 1387 response_len = handle_read_multiple_request(att_connection, request_buffer, request_len, response_buffer, 1388 response_buffer_size, true); 1389 break; 1390 case ATT_READ_BY_GROUP_TYPE_REQUEST: 1391 response_len = handle_read_by_group_type_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1392 break; 1393 case ATT_WRITE_REQUEST: 1394 response_len = handle_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1395 break; 1396 case ATT_PREPARE_WRITE_REQUEST: 1397 response_len = handle_prepare_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1398 break; 1399 case ATT_EXECUTE_WRITE_REQUEST: 1400 response_len = handle_execute_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); 1401 break; 1402 case ATT_WRITE_COMMAND: 1403 handle_write_command(att_connection, request_buffer, request_len, ATT_PROPERTY_WRITE_WITHOUT_RESPONSE); 1404 break; 1405 #ifdef ENABLE_LE_SIGNED_WRITE 1406 case ATT_SIGNED_WRITE_COMMAND: 1407 handle_write_command(att_connection, request_buffer, request_len, ATT_PROPERTY_AUTHENTICATED_SIGNED_WRITE); 1408 break; 1409 #endif 1410 default: 1411 response_len = setup_error(response_buffer, request_opcode, 0, ATT_ERROR_REQUEST_NOT_SUPPORTED); 1412 break; 1413 } 1414 return response_len; 1415 } 1416 1417 // returns 1 if service found. only primary service. 1418 bool gatt_server_get_handle_range_for_service_with_uuid16(uint16_t uuid16, uint16_t * start_handle, uint16_t * end_handle){ 1419 bool in_group = false; 1420 uint16_t prev_handle = 0; 1421 uint16_t service_start = 0; 1422 1423 uint8_t attribute_value[2]; 1424 int attribute_len = sizeof(attribute_value); 1425 little_endian_store_16(attribute_value, 0, uuid16); 1426 1427 att_iterator_t it; 1428 att_iterator_init(&it); 1429 while (att_iterator_has_next(&it)){ 1430 att_iterator_fetch_next(&it); 1431 int new_service_started = att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID); 1432 1433 // close current tag, if within a group and a new service definition starts or we reach end of att db 1434 if (in_group && 1435 ((it.handle == 0u) || new_service_started)){ 1436 in_group = false; 1437 // check range 1438 if ((service_start >= *start_handle) && (prev_handle <= *end_handle)){ 1439 *start_handle = service_start; 1440 *end_handle = prev_handle; 1441 return true; 1442 } 1443 } 1444 1445 // keep track of previous handle 1446 prev_handle = it.handle; 1447 1448 // check if found 1449 if ( (it.handle != 0u) && new_service_started && (attribute_len == it.value_len) && (memcmp(attribute_value, it.value, it.value_len) == 0)){ 1450 service_start = it.handle; 1451 in_group = true; 1452 } 1453 } 1454 return false; 1455 } 1456 1457 // returns false if not found 1458 uint16_t gatt_server_get_value_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){ 1459 att_iterator_t it; 1460 att_iterator_init(&it); 1461 while (att_iterator_has_next(&it)){ 1462 att_iterator_fetch_next(&it); 1463 if ((it.handle != 0u) && (it.handle < start_handle)){ 1464 continue; 1465 } 1466 if (it.handle > end_handle){ 1467 break; // (1) 1468 } 1469 if (it.handle == 0u){ 1470 break; 1471 } 1472 if (att_iterator_match_uuid16(&it, uuid16)){ 1473 return it.handle; 1474 } 1475 } 1476 return 0; 1477 } 1478 1479 uint16_t gatt_server_get_descriptor_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t characteristic_uuid16, uint16_t descriptor_uuid16){ 1480 att_iterator_t it; 1481 att_iterator_init(&it); 1482 bool characteristic_found = false; 1483 while (att_iterator_has_next(&it)){ 1484 att_iterator_fetch_next(&it); 1485 if ((it.handle != 0u) && (it.handle < start_handle)){ 1486 continue; 1487 } 1488 if (it.handle > end_handle){ 1489 break; // (1) 1490 } 1491 if (it.handle == 0u){ 1492 break; 1493 } 1494 if (att_iterator_match_uuid16(&it, characteristic_uuid16)){ 1495 characteristic_found = true; 1496 continue; 1497 } 1498 if (att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) 1499 || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID) 1500 || att_iterator_match_uuid16(&it, GATT_CHARACTERISTICS_UUID)){ 1501 if (characteristic_found){ 1502 break; 1503 } 1504 continue; 1505 } 1506 if (characteristic_found && att_iterator_match_uuid16(&it, descriptor_uuid16)){ 1507 return it.handle; 1508 } 1509 } 1510 return 0; 1511 } 1512 1513 // returns 0 if not found 1514 uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t characteristic_uuid16){ 1515 return gatt_server_get_descriptor_handle_for_characteristic_with_uuid16(start_handle, end_handle, characteristic_uuid16, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION); 1516 } 1517 // returns 0 if not found 1518 1519 uint16_t gatt_server_get_server_configuration_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t characteristic_uuid16){ 1520 return gatt_server_get_descriptor_handle_for_characteristic_with_uuid16(start_handle, end_handle, characteristic_uuid16, GATT_SERVER_CHARACTERISTICS_CONFIGURATION); 1521 } 1522 1523 // returns true if service found. only primary service. 1524 bool gatt_server_get_handle_range_for_service_with_uuid128(const uint8_t * uuid128, uint16_t * start_handle, uint16_t * end_handle){ 1525 bool in_group = false; 1526 uint16_t prev_handle = 0; 1527 1528 uint8_t attribute_value[16]; 1529 uint16_t attribute_len = (uint16_t)sizeof(attribute_value); 1530 reverse_128(uuid128, attribute_value); 1531 1532 att_iterator_t it; 1533 att_iterator_init(&it); 1534 while (att_iterator_has_next(&it)){ 1535 att_iterator_fetch_next(&it); 1536 int new_service_started = att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID); 1537 1538 // close current tag, if within a group and a new service definition starts or we reach end of att db 1539 if (in_group && 1540 ((it.handle == 0u) || new_service_started)){ 1541 *end_handle = prev_handle; 1542 return true; 1543 } 1544 1545 // keep track of previous handle 1546 prev_handle = it.handle; 1547 1548 // check if found 1549 if ( (it.handle != 0u) && new_service_started && (attribute_len == it.value_len) && (memcmp(attribute_value, it.value, it.value_len) == 0)){ 1550 *start_handle = it.handle; 1551 in_group = true; 1552 } 1553 } 1554 return false; 1555 } 1556 1557 // returns 0 if not found 1558 uint16_t gatt_server_get_value_handle_for_characteristic_with_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128){ 1559 uint8_t attribute_value[16]; 1560 reverse_128(uuid128, attribute_value); 1561 att_iterator_t it; 1562 att_iterator_init(&it); 1563 while (att_iterator_has_next(&it)){ 1564 att_iterator_fetch_next(&it); 1565 if ((it.handle != 0u) && (it.handle < start_handle)){ 1566 continue; 1567 } 1568 if (it.handle > end_handle){ 1569 break; // (1) 1570 } 1571 if (it.handle == 0u){ 1572 break; 1573 } 1574 if (att_iterator_match_uuid(&it, attribute_value, 16)){ 1575 return it.handle; 1576 } 1577 } 1578 return 0; 1579 } 1580 1581 // returns 0 if not found 1582 uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128){ 1583 uint8_t attribute_value[16]; 1584 reverse_128(uuid128, attribute_value); 1585 att_iterator_t it; 1586 att_iterator_init(&it); 1587 bool characteristic_found = false; 1588 while (att_iterator_has_next(&it)){ 1589 att_iterator_fetch_next(&it); 1590 if ((it.handle != 0u) && (it.handle < start_handle)){ 1591 continue; 1592 } 1593 if (it.handle > end_handle){ 1594 break; // (1) 1595 } 1596 if (it.handle == 0u){ 1597 break; 1598 } 1599 if (att_iterator_match_uuid(&it, attribute_value, 16)){ 1600 characteristic_found = true; 1601 continue; 1602 } 1603 if (att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) 1604 || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID) 1605 || att_iterator_match_uuid16(&it, GATT_CHARACTERISTICS_UUID)){ 1606 if (characteristic_found){ 1607 break; 1608 } 1609 continue; 1610 } 1611 if (characteristic_found && att_iterator_match_uuid16(&it, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION)){ 1612 return it.handle; 1613 } 1614 } 1615 return 0; 1616 } 1617 1618 1619 bool gatt_server_get_included_service_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16, 1620 uint16_t * out_included_service_handle, uint16_t * out_included_service_start_handle, uint16_t * out_included_service_end_handle){ 1621 1622 att_iterator_t it; 1623 att_iterator_init(&it); 1624 while (att_iterator_has_next(&it)){ 1625 att_iterator_fetch_next(&it); 1626 if ((it.handle != 0u) && (it.handle < start_handle)){ 1627 continue; 1628 } 1629 if (it.handle > end_handle){ 1630 break; // (1) 1631 } 1632 if (it.handle == 0u){ 1633 break; 1634 } 1635 if ((it.value_len == 6) && (att_iterator_match_uuid16(&it, GATT_INCLUDE_SERVICE_UUID))){ 1636 if (little_endian_read_16(it.value, 4) == uuid16){ 1637 *out_included_service_handle = it.handle; 1638 *out_included_service_start_handle = little_endian_read_16(it.value, 0); 1639 *out_included_service_end_handle = little_endian_read_16(it.value, 2); 1640 return true; 1641 } 1642 } 1643 } 1644 return false; 1645 } 1646 1647 // 1-item cache to optimize query during write_callback 1648 static void att_persistent_ccc_cache(att_iterator_t * it){ 1649 att_persistent_ccc_handle = it->handle; 1650 if ((it->flags & (uint16_t)ATT_PROPERTY_UUID128) != 0u){ 1651 att_persistent_ccc_uuid16 = 0u; 1652 } else { 1653 att_persistent_ccc_uuid16 = little_endian_read_16(it->uuid, 0); 1654 } 1655 } 1656 1657 bool att_is_persistent_ccc(uint16_t handle){ 1658 if (handle != att_persistent_ccc_handle){ 1659 att_iterator_t it; 1660 bool ok = att_find_handle(&it, handle); 1661 if (!ok){ 1662 return false; 1663 } 1664 att_persistent_ccc_cache(&it); 1665 } 1666 switch (att_persistent_ccc_uuid16){ 1667 case GATT_CLIENT_CHARACTERISTICS_CONFIGURATION: 1668 case GATT_CLIENT_SUPPORTED_FEATURES: 1669 return true; 1670 default: 1671 return false; 1672 } 1673 } 1674 1675 // att_read_callback helpers 1676 uint16_t att_read_callback_handle_blob(const uint8_t * blob, uint16_t blob_size, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ 1677 btstack_assert(blob != NULL); 1678 1679 if (buffer != NULL){ 1680 uint16_t bytes_to_copy = 0; 1681 if (blob_size >= offset){ 1682 bytes_to_copy = btstack_min(blob_size - offset, buffer_size); 1683 (void)memcpy(buffer, &blob[offset], bytes_to_copy); 1684 } 1685 return bytes_to_copy; 1686 } else { 1687 return blob_size; 1688 } 1689 } 1690 1691 uint16_t att_read_callback_handle_little_endian_32(uint32_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ 1692 uint8_t value_buffer[4]; 1693 little_endian_store_32(value_buffer, 0, value); 1694 return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size); 1695 } 1696 1697 uint16_t att_read_callback_handle_little_endian_16(uint16_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ 1698 uint8_t value_buffer[2]; 1699 little_endian_store_16(value_buffer, 0, value); 1700 return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size); 1701 } 1702 1703 uint16_t att_read_callback_handle_byte(uint8_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){ 1704 uint8_t value_buffer[1]; 1705 value_buffer[0] = value; 1706 return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size); 1707 } 1708 1709 1710 #ifdef ENABLE_BTP 1711 1712 // start of auto-PTS testing code, not used in production 1713 // LCOV_EXCL_START 1714 #include "btp.h" 1715 1716 static uint8_t btp_permissions_for_flags(uint16_t flags){ 1717 1718 // see BT_GATT_PERM_* 1719 // https://docs.zephyrproject.org/latest/reference/bluetooth/gatt.html 1720 // set bit indicates requirement, e.g. BTP_GATT_PERM_READ_AUTHN requires authenticated connection 1721 1722 uint8_t permissions = 0; 1723 1724 uint8_t read_security_level = 0; 1725 uint8_t write_security_level = 0; 1726 if (flags & (uint16_t)ATT_PROPERTY_READ){ 1727 if (flags & (uint16_t)ATT_PROPERTY_READ_PERMISSION_BIT_0) { 1728 read_security_level |= 1; 1729 } 1730 if (flags & (uint16_t)ATT_PROPERTY_READ_PERMISSION_BIT_1) { 1731 read_security_level |= 2; 1732 } 1733 if (read_security_level == ATT_SECURITY_AUTHORIZED) { 1734 permissions |= BTP_GATT_PERM_READ_AUTHZ; 1735 } 1736 if (read_security_level == ATT_SECURITY_AUTHENTICATED) { 1737 permissions |= BTP_GATT_PERM_READ_AUTHN; 1738 } 1739 if (read_security_level == ATT_SECURITY_ENCRYPTED) { 1740 permissions |= BTP_GATT_PERM_READ_ENC; 1741 } 1742 if (read_security_level == ATT_SECURITY_NONE) { 1743 permissions |= BTP_GATT_PERM_READ; 1744 } 1745 } 1746 if (flags & (ATT_PROPERTY_WRITE | ATT_PROPERTY_WRITE_WITHOUT_RESPONSE)){ 1747 if (flags & (uint16_t)ATT_PROPERTY_WRITE_PERMISSION_BIT_0) { 1748 write_security_level |= 1; 1749 } 1750 if (flags & (uint16_t)ATT_PROPERTY_WRITE_PERMISSION_BIT_1) { 1751 write_security_level |= 2; 1752 } 1753 if (write_security_level == ATT_SECURITY_AUTHORIZED) { 1754 permissions |= BTP_GATT_PERM_WRITE_AUTHZ; 1755 } 1756 if (write_security_level == ATT_SECURITY_AUTHENTICATED) { 1757 permissions |= BTP_GATT_PERM_WRITE_AUTHN; 1758 } 1759 if (write_security_level == ATT_SECURITY_ENCRYPTED) { 1760 permissions |= BTP_GATT_PERM_WRITE_ENC; 1761 } 1762 if (write_security_level == ATT_SECURITY_NONE) { 1763 permissions |= BTP_GATT_PERM_WRITE; 1764 } 1765 } 1766 return permissions; 1767 } 1768 1769 uint16_t btp_att_get_attributes_by_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16, uint8_t * response_buffer, uint16_t response_buffer_size){ 1770 log_info("btp_att_get_attributes_by_uuid16 %04x from 0x%04x to 0x%04x, db %p", uuid16, start_handle, end_handle, att_database); 1771 att_dump_attributes(); 1772 1773 uint8_t num_attributes = 0; 1774 uint16_t pos = 1; 1775 1776 att_iterator_t it; 1777 att_iterator_init(&it); 1778 while (att_iterator_has_next(&it) && ((pos + 6) < response_buffer_size)){ 1779 att_iterator_fetch_next(&it); 1780 log_info("handle %04x", it.handle); 1781 if (it.handle == 0){ 1782 break; 1783 } 1784 if (it.handle < start_handle){ 1785 continue; 1786 } 1787 if (it.handle > end_handle){ 1788 break; 1789 } 1790 if ((uuid16 == 0) || att_iterator_match_uuid16(&it, uuid16)){ 1791 little_endian_store_16(response_buffer, pos, it.handle); 1792 pos += 2; 1793 response_buffer[pos++] = btp_permissions_for_flags(it.flags); 1794 response_buffer[pos++] = 2; 1795 little_endian_store_16(response_buffer, pos, uuid16); 1796 pos += 2; 1797 num_attributes++; 1798 } 1799 } 1800 response_buffer[0] = num_attributes; 1801 return pos; 1802 } 1803 1804 uint16_t btp_att_get_attributes_by_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128, uint8_t * response_buffer, uint16_t response_buffer_size){ 1805 uint8_t num_attributes = 0; 1806 uint16_t pos = 1; 1807 att_iterator_t it; 1808 att_iterator_init(&it); 1809 while (att_iterator_has_next(&it) && ((pos + 20) < response_buffer_size)){ 1810 att_iterator_fetch_next(&it); 1811 if (it.handle == 0){ 1812 break; 1813 } 1814 if (it.handle < start_handle){ 1815 continue; 1816 } 1817 if (it.handle > end_handle){ 1818 break; 1819 } 1820 if (att_iterator_match_uuid(&it, (uint8_t*) uuid128, 16)){ 1821 little_endian_store_16(response_buffer, pos, it.handle); 1822 pos += 2; 1823 response_buffer[pos++] = btp_permissions_for_flags(it.flags); 1824 response_buffer[pos++] = 16; 1825 reverse_128(uuid128, &response_buffer[pos]); 1826 pos += 16; 1827 num_attributes++; 1828 } 1829 } 1830 response_buffer[0] = num_attributes; 1831 return pos; 1832 } 1833 1834 uint16_t btp_att_get_attribute_value(att_connection_t * att_connection, uint16_t attribute_handle, uint8_t * response_buffer, uint16_t response_buffer_size){ 1835 att_iterator_t it; 1836 bool ok = att_find_handle(&it, attribute_handle); 1837 if (!ok){ 1838 return 0; 1839 } 1840 1841 uint16_t pos = 0; 1842 // field: ATT_Response - simulate READ operation on given connection 1843 response_buffer[pos++] = att_validate_security(att_connection, ATT_READ, &it); 1844 // fetch len 1845 // assume: con handle not relevant here, else, it needs to get passed in 1846 // att_update_value_len(&it, HCI_CON_HANDLE_INVALID); 1847 uint16_t bytes_to_copy = btstack_min( response_buffer_size - 3, it.value_len); 1848 little_endian_store_16(response_buffer, pos, bytes_to_copy); 1849 pos += 2; 1850 // get value - only works for non-dynamic data 1851 if (it.value){ 1852 memcpy(&response_buffer[pos], it.value, bytes_to_copy); 1853 pos += bytes_to_copy; 1854 } 1855 return pos; 1856 } 1857 // LCOV_EXCL_STOP 1858 #endif 1859