xref: /btstack/src/ble/att_db.c (revision 2c4384eb9acac2c7d33d97c4f1edd7a7283b2f72)
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 // MARK: ATT_READ_MULTIPLE_REQUEST 0x20
869 //
870 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){
871     log_info("ATT_READ_MULTIPLE_(VARIABLE_)REQUEST: num handles %u", num_handles);
872     uint8_t request_type  = store_length ? ATT_READ_MULTIPLE_VARIABLE_REQ : ATT_READ_MULTIPLE_REQUEST;
873     uint8_t response_type = store_length ? ATT_READ_MULTIPLE_VARIABLE_RSP : ATT_READ_MULTIPLE_RESPONSE;
874     uint16_t offset   = 1;
875 
876     uint16_t i;
877     uint8_t  error_code = 0;
878     uint16_t handle = 0;
879 
880 #ifdef ENABLE_ATT_DELAYED_RESPONSE
881     bool read_request_pending = false;
882 #endif
883 
884     for (i=0; i<num_handles; i++){
885         handle = little_endian_read_16(handles, i << 1);
886 
887         if (handle == 0u){
888             return setup_error_invalid_handle(response_buffer, request_type, handle);
889         }
890 
891         att_iterator_t it;
892 
893         int ok = att_find_handle(&it, handle);
894         if (!ok){
895             return setup_error_invalid_handle(response_buffer, request_type, handle);
896         }
897 
898         // check if handle can be read
899         if ((it.flags & (uint16_t)ATT_PROPERTY_READ) == 0u) {
900             error_code = (uint8_t)ATT_ERROR_READ_NOT_PERMITTED;
901             break;
902         }
903 
904         // check security requirements
905         error_code = att_validate_security(att_connection, ATT_READ, &it);
906         if (error_code != 0u){
907             break;
908         }
909 
910         att_update_value_len(&it, 0, att_connection->con_handle);
911 
912 #ifdef ENABLE_ATT_DELAYED_RESPONSE
913         if (it.value_len == (uint16_t)ATT_READ_RESPONSE_PENDING) {
914             read_request_pending = true;
915         }
916         if (read_request_pending){
917             continue;
918         }
919 #endif
920 
921         // allow to return ATT Error Code in ATT Read Callback
922         if (it.value_len > (uint16_t)ATT_READ_ERROR_CODE_OFFSET){
923             error_code = (uint8_t)(it.value_len - (uint16_t)ATT_READ_ERROR_CODE_OFFSET);
924             break;
925         }
926 
927 #ifdef ENABLE_GATT_OVER_EATT
928         // assert that at least Value Length can be stored
929         if (store_length && ((offset + 2) >= response_buffer_size)){
930             break;
931         }
932         // skip length field
933         uint16_t offset_value_length = offset;
934         if (store_length){
935             offset += 2;
936         }
937 #endif
938         // store data
939         uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, response_buffer_size - offset, att_connection->con_handle);
940         offset += bytes_copied;
941 #ifdef ENABLE_GATT_OVER_EATT
942         // set length field
943         if (store_length) {
944             little_endian_store_16(response_buffer, offset_value_length, bytes_copied);
945         }
946 #endif
947     }
948 
949     if (error_code != 0u){
950         return setup_error(response_buffer, request_type, handle, error_code);
951     }
952 
953     response_buffer[0] = (uint8_t)response_type;
954     return offset;
955 }
956 
957 static uint16_t
958 handle_read_multiple_request(att_connection_t *att_connection, uint8_t *request_buffer, uint16_t request_len,
959                              uint8_t *response_buffer, uint16_t response_buffer_size, bool store_length) {
960 
961     uint8_t request_type = store_length ? ATT_READ_MULTIPLE_VARIABLE_REQ : ATT_READ_MULTIPLE_REQUEST;
962 
963     // 1 byte opcode + two or more attribute handles (2 bytes each)
964     if ( (request_len < 5u) || ((request_len & 1u) == 0u) ){
965         return setup_error_invalid_pdu(response_buffer, request_type);
966     }
967 
968     uint8_t num_handles = (request_len - 1u) >> 1u;
969     return handle_read_multiple_request2(att_connection, response_buffer, response_buffer_size, num_handles,
970                                          &request_buffer[1], store_length);
971 }
972 
973 //
974 // MARK: ATT_READ_BY_GROUP_TYPE_REQUEST 0x10
975 //
976 // Only handles GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID
977 // Core v4.0, vol 3, part g, 2.5.3
978 // "The «Primary Service» and «Secondary Service» grouping types may be used in the Read By Group Type Request.
979 //  The «Characteristic» grouping type shall not be used in the ATT Read By Group Type Request."
980 //
981 // NOTE: doesn't handle DYNAMIC values
982 //
983 // NOTE: we don't check for security as PRIMARY and SECONDAY SERVICE definition shouldn't be protected
984 // Core 4.0, vol 3, part g, 8.1
985 // "The list of services and characteristics that a device supports is not considered private or
986 //  confidential information, and therefore the Service and Characteristic Discovery procedures
987 //  shall always be permitted. "
988 //
989 static uint16_t handle_read_by_group_type_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size,
990                                             uint16_t start_handle, uint16_t end_handle,
991                                             uint16_t attribute_type_len, uint8_t * attribute_type){
992 
993     UNUSED(att_connection);
994 
995     log_info("ATT_READ_BY_GROUP_TYPE_REQUEST: from %04X to %04X, buffer size %u, type: ", start_handle, end_handle, response_buffer_size);
996     log_info_hexdump(attribute_type, attribute_type_len);
997     uint8_t request_type = ATT_READ_BY_GROUP_TYPE_REQUEST;
998 
999     if ((start_handle > end_handle) || (start_handle == 0u)){
1000         return setup_error_invalid_handle(response_buffer, request_type, start_handle);
1001     }
1002 
1003     // assert UUID is primary or secondary service uuid
1004     uint16_t uuid16 = uuid16_from_uuid(attribute_type_len, attribute_type);
1005     if ((uuid16 != (uint16_t)GATT_PRIMARY_SERVICE_UUID) && (uuid16 != (uint16_t)GATT_SECONDARY_SERVICE_UUID)){
1006         return setup_error(response_buffer, request_type, start_handle, ATT_ERROR_UNSUPPORTED_GROUP_TYPE);
1007     }
1008 
1009     uint16_t offset   = 1;
1010     uint16_t pair_len = 0;
1011     bool     in_group = false;
1012     uint16_t group_start_handle = 0;
1013     uint8_t const * group_start_value = NULL;
1014     uint16_t prev_handle = 0;
1015 
1016     att_iterator_t it;
1017     att_iterator_init(&it);
1018     while (att_iterator_has_next(&it)){
1019         att_iterator_fetch_next(&it);
1020 
1021         if ((it.handle != 0u) && (it.handle < start_handle)){
1022             continue;
1023         }
1024         if (it.handle > end_handle){
1025             break;  // (1)
1026         }
1027 
1028         // log_info("Handle 0x%04x", it.handle);
1029 
1030         // close current tag, if within a group and a new service definition starts or we reach end of att db
1031         if (in_group &&
1032             ((it.handle == 0u) || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){
1033             // log_info("End of group, handle 0x%04x, val_len: %u", prev_handle, pair_len - 4);
1034 
1035             little_endian_store_16(response_buffer, offset, group_start_handle);
1036             offset += 2u;
1037             little_endian_store_16(response_buffer, offset, prev_handle);
1038             offset += 2u;
1039             (void)memcpy(response_buffer + offset, group_start_value,
1040                          pair_len - 4u);
1041             offset += pair_len - 4u;
1042             in_group = false;
1043 
1044             // check if space for another handle pair available
1045             if ((offset + pair_len) > response_buffer_size){
1046                 break;
1047             }
1048         }
1049 
1050         // keep track of previous handle
1051         prev_handle = it.handle;
1052 
1053         // does current attribute match
1054         // log_info("compare: %04x == %04x", *(uint16_t*) context->attribute_type, *(uint16_t*) uuid);
1055         if ((it.handle != 0u) && att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) {
1056 
1057             // check if value has same len as last one
1058             uint16_t this_pair_len = 4u + it.value_len;
1059             if (offset > 1u){
1060                 if (this_pair_len != pair_len) {
1061                     break;
1062                 }
1063             }
1064 
1065             // log_info("Begin of group, handle 0x%04x", it.handle);
1066 
1067             // first
1068             if (offset == 1u) {
1069                 pair_len = this_pair_len;
1070                 response_buffer[offset] = (uint8_t) this_pair_len;
1071                 offset++;
1072             }
1073 
1074             group_start_handle = it.handle;
1075             group_start_value  = it.value;
1076             in_group = true;
1077         }
1078     }
1079 
1080     if (offset == 1u){
1081         return setup_error_atribute_not_found(response_buffer, request_type, start_handle);
1082     }
1083 
1084     response_buffer[0] = ATT_READ_BY_GROUP_TYPE_RESPONSE;
1085     return offset;
1086 }
1087 
1088 static uint16_t handle_read_by_group_type_request(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len,
1089                                            uint8_t * response_buffer, uint16_t response_buffer_size){
1090     uint16_t attribute_type_len;
1091     switch (request_len){
1092         case 7:
1093             attribute_type_len = 2;
1094             break;
1095         case 21:
1096             attribute_type_len = 16;
1097             break;
1098         default:
1099             return setup_error_invalid_pdu(response_buffer, ATT_READ_BY_GROUP_TYPE_REQUEST);
1100     }
1101 
1102     uint16_t start_handle = little_endian_read_16(request_buffer, 1);
1103     uint16_t end_handle = little_endian_read_16(request_buffer, 3);
1104     return handle_read_by_group_type_request2(att_connection, response_buffer, response_buffer_size, start_handle, end_handle, attribute_type_len, &request_buffer[5]);
1105 }
1106 
1107 //
1108 // MARK: ATT_WRITE_REQUEST 0x12
1109 static uint16_t handle_write_request(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len,
1110                               uint8_t * response_buffer, uint16_t response_buffer_size){
1111 
1112     UNUSED(response_buffer_size);
1113 
1114     if (request_len < 3u){
1115         return setup_error_invalid_pdu(response_buffer, ATT_WRITE_REQUEST);
1116     }
1117 
1118     uint8_t request_type = ATT_WRITE_REQUEST;
1119 
1120     uint16_t handle = little_endian_read_16(request_buffer, 1);
1121     att_iterator_t it;
1122     int ok = att_find_handle(&it, handle);
1123     if (!ok) {
1124         return setup_error_invalid_handle(response_buffer, request_type, handle);
1125     }
1126     if (att_write_callback == NULL) {
1127         return setup_error_write_not_permitted(response_buffer, request_type, handle);
1128     }
1129     if ((it.flags & (uint16_t)ATT_PROPERTY_WRITE) == 0u) {
1130         return setup_error_write_not_permitted(response_buffer, request_type, handle);
1131     }
1132     if ((it.flags & (uint16_t)ATT_PROPERTY_DYNAMIC) == 0u) {
1133         return setup_error_write_not_permitted(response_buffer, request_type, handle);
1134     }
1135     // check security requirements
1136     int error_code = att_validate_security(att_connection, ATT_WRITE, &it);
1137     if (error_code != 0) {
1138         return setup_error(response_buffer, request_type, handle, error_code);
1139     }
1140     att_persistent_ccc_cache(&it);
1141     error_code = (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0u, request_buffer + 3u, request_len - 3u);
1142 
1143 #ifdef ENABLE_ATT_DELAYED_RESPONSE
1144     if (error_code == ATT_ERROR_WRITE_RESPONSE_PENDING){
1145         return ATT_INTERNAL_WRITE_RESPONSE_PENDING;
1146     }
1147 #endif
1148 
1149     if (error_code != 0) {
1150         return setup_error(response_buffer, request_type, handle, error_code);
1151     }
1152     response_buffer[0] = (uint8_t)ATT_WRITE_RESPONSE;
1153     return 1;
1154 }
1155 
1156 //
1157 // MARK: ATT_PREPARE_WRITE_REQUEST 0x16
1158 static uint16_t handle_prepare_write_request(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len,
1159                                       uint8_t * response_buffer, uint16_t response_buffer_size){
1160 
1161     uint8_t request_type = ATT_PREPARE_WRITE_REQUEST;
1162 
1163     if (request_len < 5u){
1164         return setup_error_invalid_pdu(response_buffer, request_type);
1165     }
1166 
1167     uint16_t handle = little_endian_read_16(request_buffer, 1);
1168     uint16_t offset = little_endian_read_16(request_buffer, 3);
1169     if (att_write_callback == NULL) {
1170         return setup_error_write_not_permitted(response_buffer, request_type, handle);
1171     }
1172     att_iterator_t it;
1173     if (att_find_handle(&it, handle) == 0) {
1174         return setup_error_invalid_handle(response_buffer, request_type, handle);
1175     }
1176     if ((it.flags & (uint16_t)ATT_PROPERTY_WRITE) == 0u) {
1177         return setup_error_write_not_permitted(response_buffer, request_type, handle);
1178     }
1179     if ((it.flags & (uint16_t)ATT_PROPERTY_DYNAMIC) == 0u) {
1180         return setup_error_write_not_permitted(response_buffer, request_type, handle);
1181     }
1182     // check security requirements
1183     int error_code = att_validate_security(att_connection, ATT_WRITE, &it);
1184     if (error_code != 0) {
1185         return setup_error(response_buffer, request_type, handle, error_code);
1186     }
1187 
1188     error_code = (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_ACTIVE, offset, request_buffer + 5u, request_len - 5u);
1189     switch (error_code){
1190         case 0:
1191             break;
1192         case ATT_ERROR_INVALID_OFFSET:
1193         case ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH:
1194             // postpone to execute write request
1195             att_prepare_write_update_errors(error_code, handle);
1196             break;
1197 #ifdef ENABLE_ATT_DELAYED_RESPONSE
1198         case ATT_ERROR_WRITE_RESPONSE_PENDING:
1199             return ATT_INTERNAL_WRITE_RESPONSE_PENDING;
1200 #endif
1201         default:
1202             return setup_error(response_buffer, request_type, handle, error_code);
1203     }
1204 
1205     // response: echo request
1206     uint16_t bytes_to_echo = btstack_min(request_len, response_buffer_size);
1207     (void)memcpy(response_buffer, request_buffer, bytes_to_echo);
1208     response_buffer[0] = ATT_PREPARE_WRITE_RESPONSE;
1209     return request_len;
1210 }
1211 
1212 /*
1213  * @brief transcation queue of prepared writes, e.g., after disconnect
1214  */
1215 void att_clear_transaction_queue(att_connection_t * att_connection){
1216     (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_CANCEL, 0, NULL, 0);
1217 }
1218 
1219 // MARK: ATT_EXECUTE_WRITE_REQUEST 0x18
1220 // NOTE: security has been verified by handle_prepare_write_request
1221 static uint16_t handle_execute_write_request(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len,
1222                                       uint8_t * response_buffer, uint16_t response_buffer_size){
1223 
1224     UNUSED(response_buffer_size);
1225 
1226     uint8_t request_type = ATT_EXECUTE_WRITE_REQUEST;
1227 
1228     if (request_len < 2u){
1229         return setup_error_invalid_pdu(response_buffer, request_type);
1230     }
1231 
1232     if (att_write_callback == NULL) {
1233         return setup_error_write_not_permitted(response_buffer, request_type, 0);
1234     }
1235 
1236     if (request_buffer[1]) {
1237         // validate queued write
1238         if (att_prepare_write_error_code == 0){
1239             att_prepare_write_error_code = (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_VALIDATE, 0, NULL, 0);
1240         }
1241 #ifdef ENABLE_ATT_DELAYED_RESPONSE
1242         if (att_prepare_write_error_code == ATT_ERROR_WRITE_RESPONSE_PENDING){
1243             return ATT_INTERNAL_WRITE_RESPONSE_PENDING;
1244         }
1245 #endif
1246         // deliver queued errors
1247         if (att_prepare_write_error_code != 0){
1248             att_clear_transaction_queue(att_connection);
1249             uint8_t  error_code = att_prepare_write_error_code;
1250             uint16_t handle     = att_prepare_write_error_handle;
1251             att_prepare_write_reset();
1252             return setup_error(response_buffer, request_type, handle, error_code);
1253         }
1254         att_write_callback(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_EXECUTE, 0, NULL, 0);
1255     } else {
1256         att_clear_transaction_queue(att_connection);
1257     }
1258     response_buffer[0] = ATT_EXECUTE_WRITE_RESPONSE;
1259     return 1;
1260 }
1261 
1262 // MARK: ATT_WRITE_COMMAND 0x52
1263 // Core 4.0, vol 3, part F, 3.4.5.3
1264 // "No Error Response or Write Response shall be sent in response to this command"
1265 static void handle_write_command(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len, uint16_t required_flags){
1266 
1267     if (request_len < 3u){
1268         return;
1269     }
1270 
1271     uint16_t handle = little_endian_read_16(request_buffer, 1);
1272     if (att_write_callback == NULL){
1273         return;
1274     }
1275 
1276     att_iterator_t it;
1277     int ok = att_find_handle(&it, handle);
1278     if (!ok){
1279         return;
1280     }
1281     if ((it.flags & (uint16_t)ATT_PROPERTY_DYNAMIC) == 0u){
1282         return;
1283     }
1284     if ((it.flags & required_flags) == 0u){
1285         return;
1286     }
1287     if (att_validate_security(att_connection, ATT_WRITE, &it)){
1288         return;
1289     }
1290     att_persistent_ccc_cache(&it);
1291     (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0u, request_buffer + 3u, request_len - 3u);
1292 }
1293 
1294 // MARK: helper for ATT_HANDLE_VALUE_NOTIFICATION and ATT_HANDLE_VALUE_INDICATION
1295 static uint16_t prepare_handle_value(att_connection_t * att_connection,
1296                                      uint16_t handle,
1297                                      const uint8_t *value,
1298                                      uint16_t value_len,
1299                                      uint8_t * response_buffer){
1300     little_endian_store_16(response_buffer, 1, handle);
1301     uint16_t bytes_to_copy = btstack_min(value_len, att_connection->mtu - 3u);
1302     (void)memcpy(&response_buffer[3], value, bytes_to_copy);
1303     return value_len + 3u;
1304 }
1305 
1306 // MARK: ATT_HANDLE_VALUE_NOTIFICATION 0x1b
1307 uint16_t att_prepare_handle_value_notification(att_connection_t * att_connection,
1308                                                uint16_t attribute_handle,
1309                                                const uint8_t *value,
1310                                                uint16_t value_len,
1311                                                uint8_t * response_buffer){
1312 
1313     response_buffer[0] = ATT_HANDLE_VALUE_NOTIFICATION;
1314     return prepare_handle_value(att_connection, attribute_handle, value, value_len, response_buffer);
1315 }
1316 
1317 // MARK: ATT_HANDLE_VALUE_INDICATION 0x1d
1318 uint16_t att_prepare_handle_value_indication(att_connection_t * att_connection,
1319                                              uint16_t attribute_handle,
1320                                              const uint8_t *value,
1321                                              uint16_t value_len,
1322                                              uint8_t * response_buffer){
1323 
1324     response_buffer[0] = ATT_HANDLE_VALUE_INDICATION;
1325     return prepare_handle_value(att_connection, attribute_handle, value, value_len, response_buffer);
1326 }
1327 
1328 // MARK: Dispatcher
1329 uint16_t att_handle_request(att_connection_t * att_connection,
1330                             uint8_t * request_buffer,
1331                             uint16_t request_len,
1332                             uint8_t * response_buffer){
1333     uint16_t response_len = 0;
1334     const uint16_t response_buffer_size = att_connection->mtu;
1335     const uint8_t  request_opcode = request_buffer[0];
1336 
1337     switch (request_opcode){
1338         case ATT_EXCHANGE_MTU_REQUEST:
1339             response_len = handle_exchange_mtu_request(att_connection, request_buffer, request_len, response_buffer);
1340             break;
1341         case ATT_FIND_INFORMATION_REQUEST:
1342             response_len = handle_find_information_request(att_connection, request_buffer, request_len,response_buffer, response_buffer_size);
1343             break;
1344         case ATT_FIND_BY_TYPE_VALUE_REQUEST:
1345             response_len = handle_find_by_type_value_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1346             break;
1347         case ATT_READ_BY_TYPE_REQUEST:
1348             response_len = handle_read_by_type_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1349             break;
1350         case ATT_READ_REQUEST:
1351             response_len = handle_read_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1352             break;
1353         case ATT_READ_BLOB_REQUEST:
1354             response_len = handle_read_blob_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1355             break;
1356         case ATT_READ_MULTIPLE_REQUEST:
1357             response_len = handle_read_multiple_request(att_connection, request_buffer, request_len, response_buffer,
1358                                                         response_buffer_size, false);
1359             break;
1360         case ATT_READ_MULTIPLE_VARIABLE_REQ:
1361             response_len = handle_read_multiple_request(att_connection, request_buffer, request_len, response_buffer,
1362                                                         response_buffer_size, true);
1363             break;
1364         case ATT_READ_BY_GROUP_TYPE_REQUEST:
1365             response_len = handle_read_by_group_type_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1366             break;
1367         case ATT_WRITE_REQUEST:
1368             response_len = handle_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1369             break;
1370         case ATT_PREPARE_WRITE_REQUEST:
1371             response_len = handle_prepare_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1372             break;
1373         case ATT_EXECUTE_WRITE_REQUEST:
1374             response_len = handle_execute_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1375             break;
1376         case ATT_WRITE_COMMAND:
1377             handle_write_command(att_connection, request_buffer, request_len, ATT_PROPERTY_WRITE_WITHOUT_RESPONSE);
1378             break;
1379 #ifdef ENABLE_LE_SIGNED_WRITE
1380         case ATT_SIGNED_WRITE_COMMAND:
1381             handle_write_command(att_connection, request_buffer, request_len, ATT_PROPERTY_AUTHENTICATED_SIGNED_WRITE);
1382             break;
1383 #endif
1384         default:
1385             response_len = setup_error(response_buffer, request_opcode, 0, ATT_ERROR_REQUEST_NOT_SUPPORTED);
1386             break;
1387     }
1388     return response_len;
1389 }
1390 
1391 // returns 1 if service found. only primary service.
1392 bool gatt_server_get_handle_range_for_service_with_uuid16(uint16_t uuid16, uint16_t * start_handle, uint16_t * end_handle){
1393     bool in_group    = false;
1394     uint16_t prev_handle = 0;
1395     uint16_t service_start = 0;
1396 
1397     uint8_t attribute_value[2];
1398     int attribute_len = sizeof(attribute_value);
1399     little_endian_store_16(attribute_value, 0, uuid16);
1400 
1401     att_iterator_t it;
1402     att_iterator_init(&it);
1403     while (att_iterator_has_next(&it)){
1404         att_iterator_fetch_next(&it);
1405         int new_service_started = att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID);
1406 
1407         // close current tag, if within a group and a new service definition starts or we reach end of att db
1408         if (in_group &&
1409             ((it.handle == 0u) || new_service_started)){
1410             in_group = false;
1411             // check range
1412             if ((service_start >= *start_handle) && (prev_handle <= *end_handle)){
1413                 *start_handle = service_start;
1414                 *end_handle = prev_handle;
1415                 return true;
1416             }
1417         }
1418 
1419         // keep track of previous handle
1420         prev_handle = it.handle;
1421 
1422         // check if found
1423         if ( (it.handle != 0u) && new_service_started && (attribute_len == it.value_len) && (memcmp(attribute_value, it.value, it.value_len) == 0)){
1424             service_start = it.handle;
1425             in_group = true;
1426         }
1427     }
1428     return false;
1429 }
1430 
1431 // returns false if not found
1432 uint16_t gatt_server_get_value_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){
1433     att_iterator_t it;
1434     att_iterator_init(&it);
1435     while (att_iterator_has_next(&it)){
1436         att_iterator_fetch_next(&it);
1437         if ((it.handle != 0u) && (it.handle < start_handle)){
1438             continue;
1439         }
1440         if (it.handle > end_handle){
1441             break;  // (1)
1442         }
1443         if (it.handle == 0u){
1444             break;
1445         }
1446         if (att_iterator_match_uuid16(&it, uuid16)){
1447             return it.handle;
1448         }
1449     }
1450     return 0;
1451 }
1452 
1453 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){
1454     att_iterator_t it;
1455     att_iterator_init(&it);
1456     bool characteristic_found = false;
1457     while (att_iterator_has_next(&it)){
1458         att_iterator_fetch_next(&it);
1459         if ((it.handle != 0u) && (it.handle < start_handle)){
1460             continue;
1461         }
1462         if (it.handle > end_handle){
1463             break;  // (1)
1464         }
1465         if (it.handle == 0u){
1466             break;
1467         }
1468         if (att_iterator_match_uuid16(&it, characteristic_uuid16)){
1469             characteristic_found = true;
1470             continue;
1471         }
1472         if (att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID)
1473          || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID)
1474          || att_iterator_match_uuid16(&it, GATT_CHARACTERISTICS_UUID)){
1475             if (characteristic_found){
1476                 break;
1477             }
1478             continue;
1479         }
1480         if (characteristic_found && att_iterator_match_uuid16(&it, descriptor_uuid16)){
1481             return it.handle;
1482         }
1483     }
1484     return 0;
1485 }
1486 
1487 // returns 0 if not found
1488 uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t characteristic_uuid16){
1489     return gatt_server_get_descriptor_handle_for_characteristic_with_uuid16(start_handle, end_handle, characteristic_uuid16, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION);
1490 }
1491 // returns 0 if not found
1492 
1493 uint16_t gatt_server_get_server_configuration_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t characteristic_uuid16){
1494     return gatt_server_get_descriptor_handle_for_characteristic_with_uuid16(start_handle, end_handle, characteristic_uuid16, GATT_SERVER_CHARACTERISTICS_CONFIGURATION);
1495 }
1496 
1497 // returns true if service found. only primary service.
1498 bool gatt_server_get_handle_range_for_service_with_uuid128(const uint8_t * uuid128, uint16_t * start_handle, uint16_t * end_handle){
1499     bool in_group    = false;
1500     uint16_t prev_handle = 0;
1501 
1502     uint8_t attribute_value[16];
1503     uint16_t attribute_len = (uint16_t)sizeof(attribute_value);
1504     reverse_128(uuid128, attribute_value);
1505 
1506     att_iterator_t it;
1507     att_iterator_init(&it);
1508     while (att_iterator_has_next(&it)){
1509         att_iterator_fetch_next(&it);
1510         int new_service_started = att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID);
1511 
1512         // close current tag, if within a group and a new service definition starts or we reach end of att db
1513         if (in_group &&
1514             ((it.handle == 0u) || new_service_started)){
1515             *end_handle = prev_handle;
1516             return true;
1517         }
1518 
1519         // keep track of previous handle
1520         prev_handle = it.handle;
1521 
1522         // check if found
1523         if ( (it.handle != 0u) && new_service_started && (attribute_len == it.value_len) && (memcmp(attribute_value, it.value, it.value_len) == 0)){
1524             *start_handle = it.handle;
1525             in_group = true;
1526         }
1527     }
1528     return false;
1529 }
1530 
1531 // returns 0 if not found
1532 uint16_t gatt_server_get_value_handle_for_characteristic_with_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128){
1533     uint8_t attribute_value[16];
1534     reverse_128(uuid128, attribute_value);
1535     att_iterator_t it;
1536     att_iterator_init(&it);
1537     while (att_iterator_has_next(&it)){
1538         att_iterator_fetch_next(&it);
1539         if ((it.handle != 0u) && (it.handle < start_handle)){
1540             continue;
1541         }
1542         if (it.handle > end_handle){
1543             break;  // (1)
1544         }
1545         if (it.handle == 0u){
1546             break;
1547         }
1548         if (att_iterator_match_uuid(&it, attribute_value, 16)){
1549             return it.handle;
1550         }
1551     }
1552     return 0;
1553 }
1554 
1555 // returns 0 if not found
1556 uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128){
1557     uint8_t attribute_value[16];
1558     reverse_128(uuid128, attribute_value);
1559     att_iterator_t it;
1560     att_iterator_init(&it);
1561     int characteristic_found = 0;
1562     while (att_iterator_has_next(&it)){
1563         att_iterator_fetch_next(&it);
1564         if ((it.handle != 0u) && (it.handle < start_handle)){
1565             continue;
1566         }
1567         if (it.handle > end_handle){
1568             break;  // (1)
1569         }
1570         if (it.handle == 0u){
1571             break;
1572         }
1573         if (att_iterator_match_uuid(&it, attribute_value, 16)){
1574             characteristic_found = 1;
1575             continue;
1576         }
1577         if (att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID)
1578          || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID)
1579          || att_iterator_match_uuid16(&it, GATT_CHARACTERISTICS_UUID)){
1580             if (characteristic_found){
1581                 break;
1582             }
1583             continue;
1584         }
1585         if (characteristic_found && att_iterator_match_uuid16(&it, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION)){
1586             return it.handle;
1587         }
1588     }
1589     return 0;
1590 }
1591 
1592 
1593 bool gatt_server_get_included_service_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16,
1594     uint16_t * out_included_service_handle, uint16_t * out_included_service_start_handle, uint16_t * out_included_service_end_handle){
1595 
1596     att_iterator_t it;
1597     att_iterator_init(&it);
1598     while (att_iterator_has_next(&it)){
1599         att_iterator_fetch_next(&it);
1600         if ((it.handle != 0u) && (it.handle < start_handle)){
1601             continue;
1602         }
1603         if (it.handle > end_handle){
1604             break;  // (1)
1605         }
1606         if (it.handle == 0u){
1607             break;
1608         }
1609         if ((it.value_len == 6) && (att_iterator_match_uuid16(&it, GATT_INCLUDE_SERVICE_UUID))){
1610             if (little_endian_read_16(it.value, 4) == uuid16){
1611                 *out_included_service_handle = it.handle;
1612                 *out_included_service_start_handle = little_endian_read_16(it.value, 0);
1613                 *out_included_service_end_handle = little_endian_read_16(it.value, 2);
1614                 return true;
1615             }
1616         }
1617     }
1618     return false;
1619 }
1620 
1621 // 1-item cache to optimize query during write_callback
1622 static void att_persistent_ccc_cache(att_iterator_t * it){
1623     att_persistent_ccc_handle = it->handle;
1624     if (it->flags & (uint16_t)ATT_PROPERTY_UUID128){
1625         att_persistent_ccc_uuid16 = 0u;
1626     } else {
1627         att_persistent_ccc_uuid16 = little_endian_read_16(it->uuid, 0);
1628     }
1629 }
1630 
1631 bool att_is_persistent_ccc(uint16_t handle){
1632     if (handle != att_persistent_ccc_handle){
1633         att_iterator_t it;
1634         int ok = att_find_handle(&it, handle);
1635         if (!ok){
1636             return false;
1637         }
1638         att_persistent_ccc_cache(&it);
1639     }
1640     return att_persistent_ccc_uuid16 == (uint16_t)GATT_CLIENT_CHARACTERISTICS_CONFIGURATION;
1641 }
1642 
1643 // att_read_callback helpers
1644 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){
1645     btstack_assert(blob != NULL);
1646 
1647     if (buffer != NULL){
1648         uint16_t bytes_to_copy = 0;
1649         if (blob_size >= offset){
1650             bytes_to_copy = btstack_min(blob_size - offset, buffer_size);
1651             (void)memcpy(buffer, &blob[offset], bytes_to_copy);
1652         }
1653         return bytes_to_copy;
1654     } else {
1655         return blob_size;
1656     }
1657 }
1658 
1659 uint16_t att_read_callback_handle_little_endian_32(uint32_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
1660     uint8_t value_buffer[4];
1661     little_endian_store_32(value_buffer, 0, value);
1662     return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size);
1663 }
1664 
1665 uint16_t att_read_callback_handle_little_endian_16(uint16_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
1666     uint8_t value_buffer[2];
1667     little_endian_store_16(value_buffer, 0, value);
1668     return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size);
1669 }
1670 
1671 uint16_t att_read_callback_handle_byte(uint8_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
1672     uint8_t value_buffer[1];
1673     value_buffer[0] = value;
1674     return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size);
1675 }
1676 
1677 
1678 #ifdef ENABLE_BTP
1679 
1680 // start of auto-PTS testing code, not used in production
1681 // LCOV_EXCL_START
1682 #include "btp.h"
1683 
1684 static uint8_t btp_permissions_for_flags(uint16_t flags){
1685 
1686     // see BT_GATT_PERM_*
1687     // https://docs.zephyrproject.org/latest/reference/bluetooth/gatt.html
1688     // set bit indicates requirement, e.g. BTP_GATT_PERM_READ_AUTHN requires authenticated connection
1689 
1690     uint8_t permissions = 0;
1691 
1692     uint8_t read_security_level = 0;
1693     uint8_t write_security_level = 0;
1694     if (flags & (uint16_t)ATT_PROPERTY_READ){
1695         if (flags & (uint16_t)ATT_PROPERTY_READ_PERMISSION_BIT_0) {
1696             read_security_level |= 1;
1697         }
1698         if (flags & (uint16_t)ATT_PROPERTY_READ_PERMISSION_BIT_1) {
1699             read_security_level |= 2;
1700         }
1701         if (read_security_level == ATT_SECURITY_AUTHORIZED) {
1702             permissions |= BTP_GATT_PERM_READ_AUTHZ;
1703         }
1704         if (read_security_level == ATT_SECURITY_AUTHENTICATED) {
1705             permissions |= BTP_GATT_PERM_READ_AUTHN;
1706         }
1707         if (read_security_level == ATT_SECURITY_ENCRYPTED) {
1708             permissions |= BTP_GATT_PERM_READ_ENC;
1709         }
1710         if (read_security_level == ATT_SECURITY_NONE) {
1711             permissions |= BTP_GATT_PERM_READ;
1712         }
1713     }
1714     if (flags & (ATT_PROPERTY_WRITE | ATT_PROPERTY_WRITE_WITHOUT_RESPONSE)){
1715         if (flags & (uint16_t)ATT_PROPERTY_WRITE_PERMISSION_BIT_0) {
1716             write_security_level |= 1;
1717         }
1718         if (flags & (uint16_t)ATT_PROPERTY_WRITE_PERMISSION_BIT_1) {
1719             write_security_level |= 2;
1720         }
1721         if (write_security_level == ATT_SECURITY_AUTHORIZED) {
1722             permissions |= BTP_GATT_PERM_WRITE_AUTHZ;
1723         }
1724         if (write_security_level == ATT_SECURITY_AUTHENTICATED) {
1725             permissions |= BTP_GATT_PERM_WRITE_AUTHN;
1726         }
1727         if (write_security_level == ATT_SECURITY_ENCRYPTED) {
1728             permissions |= BTP_GATT_PERM_WRITE_ENC;
1729         }
1730         if (write_security_level == ATT_SECURITY_NONE) {
1731             permissions |= BTP_GATT_PERM_WRITE;
1732         }
1733     }
1734     return permissions;
1735 }
1736 
1737 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){
1738     log_info("btp_att_get_attributes_by_uuid16 %04x from 0x%04x to 0x%04x, db %p", uuid16, start_handle, end_handle, att_database);
1739     att_dump_attributes();
1740 
1741     uint8_t num_attributes = 0;
1742     uint16_t pos = 1;
1743 
1744     att_iterator_t  it;
1745     att_iterator_init(&it);
1746     while (att_iterator_has_next(&it) && ((pos + 6) < response_buffer_size)){
1747         att_iterator_fetch_next(&it);
1748         log_info("handle %04x", it.handle);
1749         if (it.handle == 0){
1750             break;
1751         }
1752         if (it.handle < start_handle){
1753             continue;
1754         }
1755         if (it.handle > end_handle){
1756             break;
1757         }
1758         if ((uuid16 == 0) || att_iterator_match_uuid16(&it, uuid16)){
1759             little_endian_store_16(response_buffer, pos, it.handle);
1760             pos += 2;
1761             response_buffer[pos++] = btp_permissions_for_flags(it.flags);
1762             response_buffer[pos++] = 2;
1763             little_endian_store_16(response_buffer, pos, uuid16);
1764             pos += 2;
1765             num_attributes++;
1766         }
1767     }
1768     response_buffer[0] = num_attributes;
1769     return pos;
1770 }
1771 
1772 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){
1773     uint8_t num_attributes = 0;
1774     uint16_t pos = 1;
1775     att_iterator_t  it;
1776     att_iterator_init(&it);
1777     while (att_iterator_has_next(&it) && ((pos + 20) < response_buffer_size)){
1778         att_iterator_fetch_next(&it);
1779         if (it.handle == 0){
1780             break;
1781         }
1782         if (it.handle < start_handle){
1783             continue;
1784         }
1785         if (it.handle > end_handle){
1786             break;
1787         }
1788         if (att_iterator_match_uuid(&it, (uint8_t*) uuid128, 16)){
1789             little_endian_store_16(response_buffer, pos, it.handle);
1790             pos += 2;
1791             response_buffer[pos++] = btp_permissions_for_flags(it.flags);
1792             response_buffer[pos++] = 16;
1793             reverse_128(uuid128, &response_buffer[pos]);
1794             pos += 16;
1795             num_attributes++;
1796         }
1797     }
1798     response_buffer[0] = num_attributes;
1799     return pos;
1800 }
1801 
1802 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){
1803     att_iterator_t it;
1804     int ok = att_find_handle(&it, attribute_handle);
1805     if (!ok){
1806         return 0;
1807     }
1808 
1809     uint16_t pos = 0;
1810     // field: ATT_Response - simulate READ operation on given connection
1811     response_buffer[pos++] = att_validate_security(att_connection, ATT_READ, &it);
1812     // fetch len
1813     // assume: con handle not relevant here, else, it needs to get passed in
1814     // att_update_value_len(&it, HCI_CON_HANDLE_INVALID);
1815     uint16_t bytes_to_copy = btstack_min( response_buffer_size - 3, it.value_len);
1816     little_endian_store_16(response_buffer, pos, bytes_to_copy);
1817     pos += 2;
1818     // get value - only works for non-dynamic data
1819     if (it.value){
1820         memcpy(&response_buffer[pos], it.value, bytes_to_copy);
1821         pos += bytes_to_copy;
1822     }
1823     return pos;
1824 }
1825 // LCOV_EXCL_STOP
1826 #endif
1827