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