xref: /btstack/src/ble/att_db.c (revision ced70f9bfeafe291ec597a3a9cc862e39e0da3ce)
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_MULTIPLE_HANDLE_VALUE_NTF 0x23u
1318 uint16_t att_prepare_handle_value_multiple_notification(att_connection_t * att_connection,
1319                                                uint8_t num_attributes,
1320                                                const uint16_t * attribute_handles,
1321                                                const uint8_t ** values_data,
1322                                                const uint16_t * values_len,
1323                                                uint8_t * response_buffer){
1324 
1325     response_buffer[0] = ATT_MULTIPLE_HANDLE_VALUE_NTF;
1326     uint8_t i;
1327     uint16_t offset = 1;
1328     uint16_t response_buffer_size = att_connection->mtu - 3u;
1329     for (i = 0; i < num_attributes; i++) {
1330         uint16_t value_len = values_len[i];
1331         if ((offset + 4 + value_len) > response_buffer_size){
1332             break;
1333         }
1334         little_endian_store_16(response_buffer, offset, attribute_handles[i]);
1335         offset += 2;
1336         little_endian_store_16(response_buffer, offset, value_len);
1337         offset += 2;
1338         (void) memcpy(&response_buffer[offset], values_data[i], value_len);
1339         offset += value_len;
1340     }
1341     return offset;
1342 }
1343 
1344 // MARK: ATT_HANDLE_VALUE_INDICATION 0x1d
1345 uint16_t att_prepare_handle_value_indication(att_connection_t * att_connection,
1346                                              uint16_t attribute_handle,
1347                                              const uint8_t *value,
1348                                              uint16_t value_len,
1349                                              uint8_t * response_buffer){
1350 
1351     response_buffer[0] = ATT_HANDLE_VALUE_INDICATION;
1352     return prepare_handle_value(att_connection, attribute_handle, value, value_len, response_buffer);
1353 }
1354 
1355 // MARK: Dispatcher
1356 uint16_t att_handle_request(att_connection_t * att_connection,
1357                             uint8_t * request_buffer,
1358                             uint16_t request_len,
1359                             uint8_t * response_buffer){
1360     uint16_t response_len = 0;
1361     const uint16_t response_buffer_size = att_connection->mtu;
1362     const uint8_t  request_opcode = request_buffer[0];
1363 
1364     switch (request_opcode){
1365         case ATT_EXCHANGE_MTU_REQUEST:
1366             response_len = handle_exchange_mtu_request(att_connection, request_buffer, request_len, response_buffer);
1367             break;
1368         case ATT_FIND_INFORMATION_REQUEST:
1369             response_len = handle_find_information_request(att_connection, request_buffer, request_len,response_buffer, response_buffer_size);
1370             break;
1371         case ATT_FIND_BY_TYPE_VALUE_REQUEST:
1372             response_len = handle_find_by_type_value_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1373             break;
1374         case ATT_READ_BY_TYPE_REQUEST:
1375             response_len = handle_read_by_type_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1376             break;
1377         case ATT_READ_REQUEST:
1378             response_len = handle_read_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1379             break;
1380         case ATT_READ_BLOB_REQUEST:
1381             response_len = handle_read_blob_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1382             break;
1383         case ATT_READ_MULTIPLE_REQUEST:
1384             response_len = handle_read_multiple_request(att_connection, request_buffer, request_len, response_buffer,
1385                                                         response_buffer_size, false);
1386             break;
1387         case ATT_READ_MULTIPLE_VARIABLE_REQ:
1388             response_len = handle_read_multiple_request(att_connection, request_buffer, request_len, response_buffer,
1389                                                         response_buffer_size, true);
1390             break;
1391         case ATT_READ_BY_GROUP_TYPE_REQUEST:
1392             response_len = handle_read_by_group_type_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1393             break;
1394         case ATT_WRITE_REQUEST:
1395             response_len = handle_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1396             break;
1397         case ATT_PREPARE_WRITE_REQUEST:
1398             response_len = handle_prepare_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1399             break;
1400         case ATT_EXECUTE_WRITE_REQUEST:
1401             response_len = handle_execute_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1402             break;
1403         case ATT_WRITE_COMMAND:
1404             handle_write_command(att_connection, request_buffer, request_len, ATT_PROPERTY_WRITE_WITHOUT_RESPONSE);
1405             break;
1406 #ifdef ENABLE_LE_SIGNED_WRITE
1407         case ATT_SIGNED_WRITE_COMMAND:
1408             handle_write_command(att_connection, request_buffer, request_len, ATT_PROPERTY_AUTHENTICATED_SIGNED_WRITE);
1409             break;
1410 #endif
1411         default:
1412             response_len = setup_error(response_buffer, request_opcode, 0, ATT_ERROR_REQUEST_NOT_SUPPORTED);
1413             break;
1414     }
1415     return response_len;
1416 }
1417 
1418 // returns 1 if service found. only primary service.
1419 bool gatt_server_get_handle_range_for_service_with_uuid16(uint16_t uuid16, uint16_t * start_handle, uint16_t * end_handle){
1420     bool in_group    = false;
1421     uint16_t prev_handle = 0;
1422     uint16_t service_start = 0;
1423 
1424     uint8_t attribute_value[2];
1425     int attribute_len = sizeof(attribute_value);
1426     little_endian_store_16(attribute_value, 0, uuid16);
1427 
1428     att_iterator_t it;
1429     att_iterator_init(&it);
1430     while (att_iterator_has_next(&it)){
1431         att_iterator_fetch_next(&it);
1432         int new_service_started = att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID);
1433 
1434         // close current tag, if within a group and a new service definition starts or we reach end of att db
1435         if (in_group &&
1436             ((it.handle == 0u) || new_service_started)){
1437             in_group = false;
1438             // check range
1439             if ((service_start >= *start_handle) && (prev_handle <= *end_handle)){
1440                 *start_handle = service_start;
1441                 *end_handle = prev_handle;
1442                 return true;
1443             }
1444         }
1445 
1446         // keep track of previous handle
1447         prev_handle = it.handle;
1448 
1449         // check if found
1450         if ( (it.handle != 0u) && new_service_started && (attribute_len == it.value_len) && (memcmp(attribute_value, it.value, it.value_len) == 0)){
1451             service_start = it.handle;
1452             in_group = true;
1453         }
1454     }
1455     return false;
1456 }
1457 
1458 // returns false if not found
1459 uint16_t gatt_server_get_value_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){
1460     att_iterator_t it;
1461     att_iterator_init(&it);
1462     while (att_iterator_has_next(&it)){
1463         att_iterator_fetch_next(&it);
1464         if ((it.handle != 0u) && (it.handle < start_handle)){
1465             continue;
1466         }
1467         if (it.handle > end_handle){
1468             break;  // (1)
1469         }
1470         if (it.handle == 0u){
1471             break;
1472         }
1473         if (att_iterator_match_uuid16(&it, uuid16)){
1474             return it.handle;
1475         }
1476     }
1477     return 0;
1478 }
1479 
1480 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){
1481     att_iterator_t it;
1482     att_iterator_init(&it);
1483     bool characteristic_found = false;
1484     while (att_iterator_has_next(&it)){
1485         att_iterator_fetch_next(&it);
1486         if ((it.handle != 0u) && (it.handle < start_handle)){
1487             continue;
1488         }
1489         if (it.handle > end_handle){
1490             break;  // (1)
1491         }
1492         if (it.handle == 0u){
1493             break;
1494         }
1495         if (att_iterator_match_uuid16(&it, characteristic_uuid16)){
1496             characteristic_found = true;
1497             continue;
1498         }
1499         if (att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID)
1500          || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID)
1501          || att_iterator_match_uuid16(&it, GATT_CHARACTERISTICS_UUID)){
1502             if (characteristic_found){
1503                 break;
1504             }
1505             continue;
1506         }
1507         if (characteristic_found && att_iterator_match_uuid16(&it, descriptor_uuid16)){
1508             return it.handle;
1509         }
1510     }
1511     return 0;
1512 }
1513 
1514 // returns 0 if not found
1515 uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t characteristic_uuid16){
1516     return gatt_server_get_descriptor_handle_for_characteristic_with_uuid16(start_handle, end_handle, characteristic_uuid16, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION);
1517 }
1518 // returns 0 if not found
1519 
1520 uint16_t gatt_server_get_server_configuration_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t characteristic_uuid16){
1521     return gatt_server_get_descriptor_handle_for_characteristic_with_uuid16(start_handle, end_handle, characteristic_uuid16, GATT_SERVER_CHARACTERISTICS_CONFIGURATION);
1522 }
1523 
1524 // returns true if service found. only primary service.
1525 bool gatt_server_get_handle_range_for_service_with_uuid128(const uint8_t * uuid128, uint16_t * start_handle, uint16_t * end_handle){
1526     bool in_group    = false;
1527     uint16_t prev_handle = 0;
1528 
1529     uint8_t attribute_value[16];
1530     uint16_t attribute_len = (uint16_t)sizeof(attribute_value);
1531     reverse_128(uuid128, attribute_value);
1532 
1533     att_iterator_t it;
1534     att_iterator_init(&it);
1535     while (att_iterator_has_next(&it)){
1536         att_iterator_fetch_next(&it);
1537         int new_service_started = att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID);
1538 
1539         // close current tag, if within a group and a new service definition starts or we reach end of att db
1540         if (in_group &&
1541             ((it.handle == 0u) || new_service_started)){
1542             *end_handle = prev_handle;
1543             return true;
1544         }
1545 
1546         // keep track of previous handle
1547         prev_handle = it.handle;
1548 
1549         // check if found
1550         if ( (it.handle != 0u) && new_service_started && (attribute_len == it.value_len) && (memcmp(attribute_value, it.value, it.value_len) == 0)){
1551             *start_handle = it.handle;
1552             in_group = true;
1553         }
1554     }
1555     return false;
1556 }
1557 
1558 // returns 0 if not found
1559 uint16_t gatt_server_get_value_handle_for_characteristic_with_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128){
1560     uint8_t attribute_value[16];
1561     reverse_128(uuid128, attribute_value);
1562     att_iterator_t it;
1563     att_iterator_init(&it);
1564     while (att_iterator_has_next(&it)){
1565         att_iterator_fetch_next(&it);
1566         if ((it.handle != 0u) && (it.handle < start_handle)){
1567             continue;
1568         }
1569         if (it.handle > end_handle){
1570             break;  // (1)
1571         }
1572         if (it.handle == 0u){
1573             break;
1574         }
1575         if (att_iterator_match_uuid(&it, attribute_value, 16)){
1576             return it.handle;
1577         }
1578     }
1579     return 0;
1580 }
1581 
1582 // returns 0 if not found
1583 uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128){
1584     uint8_t attribute_value[16];
1585     reverse_128(uuid128, attribute_value);
1586     att_iterator_t it;
1587     att_iterator_init(&it);
1588     int characteristic_found = 0;
1589     while (att_iterator_has_next(&it)){
1590         att_iterator_fetch_next(&it);
1591         if ((it.handle != 0u) && (it.handle < start_handle)){
1592             continue;
1593         }
1594         if (it.handle > end_handle){
1595             break;  // (1)
1596         }
1597         if (it.handle == 0u){
1598             break;
1599         }
1600         if (att_iterator_match_uuid(&it, attribute_value, 16)){
1601             characteristic_found = 1;
1602             continue;
1603         }
1604         if (att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID)
1605          || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID)
1606          || att_iterator_match_uuid16(&it, GATT_CHARACTERISTICS_UUID)){
1607             if (characteristic_found){
1608                 break;
1609             }
1610             continue;
1611         }
1612         if (characteristic_found && att_iterator_match_uuid16(&it, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION)){
1613             return it.handle;
1614         }
1615     }
1616     return 0;
1617 }
1618 
1619 
1620 bool gatt_server_get_included_service_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16,
1621     uint16_t * out_included_service_handle, uint16_t * out_included_service_start_handle, uint16_t * out_included_service_end_handle){
1622 
1623     att_iterator_t it;
1624     att_iterator_init(&it);
1625     while (att_iterator_has_next(&it)){
1626         att_iterator_fetch_next(&it);
1627         if ((it.handle != 0u) && (it.handle < start_handle)){
1628             continue;
1629         }
1630         if (it.handle > end_handle){
1631             break;  // (1)
1632         }
1633         if (it.handle == 0u){
1634             break;
1635         }
1636         if ((it.value_len == 6) && (att_iterator_match_uuid16(&it, GATT_INCLUDE_SERVICE_UUID))){
1637             if (little_endian_read_16(it.value, 4) == uuid16){
1638                 *out_included_service_handle = it.handle;
1639                 *out_included_service_start_handle = little_endian_read_16(it.value, 0);
1640                 *out_included_service_end_handle = little_endian_read_16(it.value, 2);
1641                 return true;
1642             }
1643         }
1644     }
1645     return false;
1646 }
1647 
1648 // 1-item cache to optimize query during write_callback
1649 static void att_persistent_ccc_cache(att_iterator_t * it){
1650     att_persistent_ccc_handle = it->handle;
1651     if (it->flags & (uint16_t)ATT_PROPERTY_UUID128){
1652         att_persistent_ccc_uuid16 = 0u;
1653     } else {
1654         att_persistent_ccc_uuid16 = little_endian_read_16(it->uuid, 0);
1655     }
1656 }
1657 
1658 bool att_is_persistent_ccc(uint16_t handle){
1659     if (handle != att_persistent_ccc_handle){
1660         att_iterator_t it;
1661         int ok = att_find_handle(&it, handle);
1662         if (!ok){
1663             return false;
1664         }
1665         att_persistent_ccc_cache(&it);
1666     }
1667     switch (att_persistent_ccc_uuid16){
1668         case GATT_CLIENT_CHARACTERISTICS_CONFIGURATION:
1669         case GATT_CLIENT_SUPPORTED_FEATURES:
1670             return true;
1671         default:
1672             return false;
1673     }
1674 }
1675 
1676 // att_read_callback helpers
1677 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){
1678     btstack_assert(blob != NULL);
1679 
1680     if (buffer != NULL){
1681         uint16_t bytes_to_copy = 0;
1682         if (blob_size >= offset){
1683             bytes_to_copy = btstack_min(blob_size - offset, buffer_size);
1684             (void)memcpy(buffer, &blob[offset], bytes_to_copy);
1685         }
1686         return bytes_to_copy;
1687     } else {
1688         return blob_size;
1689     }
1690 }
1691 
1692 uint16_t att_read_callback_handle_little_endian_32(uint32_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
1693     uint8_t value_buffer[4];
1694     little_endian_store_32(value_buffer, 0, value);
1695     return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size);
1696 }
1697 
1698 uint16_t att_read_callback_handle_little_endian_16(uint16_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
1699     uint8_t value_buffer[2];
1700     little_endian_store_16(value_buffer, 0, value);
1701     return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size);
1702 }
1703 
1704 uint16_t att_read_callback_handle_byte(uint8_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
1705     uint8_t value_buffer[1];
1706     value_buffer[0] = value;
1707     return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size);
1708 }
1709 
1710 
1711 #ifdef ENABLE_BTP
1712 
1713 // start of auto-PTS testing code, not used in production
1714 // LCOV_EXCL_START
1715 #include "btp.h"
1716 
1717 static uint8_t btp_permissions_for_flags(uint16_t flags){
1718 
1719     // see BT_GATT_PERM_*
1720     // https://docs.zephyrproject.org/latest/reference/bluetooth/gatt.html
1721     // set bit indicates requirement, e.g. BTP_GATT_PERM_READ_AUTHN requires authenticated connection
1722 
1723     uint8_t permissions = 0;
1724 
1725     uint8_t read_security_level = 0;
1726     uint8_t write_security_level = 0;
1727     if (flags & (uint16_t)ATT_PROPERTY_READ){
1728         if (flags & (uint16_t)ATT_PROPERTY_READ_PERMISSION_BIT_0) {
1729             read_security_level |= 1;
1730         }
1731         if (flags & (uint16_t)ATT_PROPERTY_READ_PERMISSION_BIT_1) {
1732             read_security_level |= 2;
1733         }
1734         if (read_security_level == ATT_SECURITY_AUTHORIZED) {
1735             permissions |= BTP_GATT_PERM_READ_AUTHZ;
1736         }
1737         if (read_security_level == ATT_SECURITY_AUTHENTICATED) {
1738             permissions |= BTP_GATT_PERM_READ_AUTHN;
1739         }
1740         if (read_security_level == ATT_SECURITY_ENCRYPTED) {
1741             permissions |= BTP_GATT_PERM_READ_ENC;
1742         }
1743         if (read_security_level == ATT_SECURITY_NONE) {
1744             permissions |= BTP_GATT_PERM_READ;
1745         }
1746     }
1747     if (flags & (ATT_PROPERTY_WRITE | ATT_PROPERTY_WRITE_WITHOUT_RESPONSE)){
1748         if (flags & (uint16_t)ATT_PROPERTY_WRITE_PERMISSION_BIT_0) {
1749             write_security_level |= 1;
1750         }
1751         if (flags & (uint16_t)ATT_PROPERTY_WRITE_PERMISSION_BIT_1) {
1752             write_security_level |= 2;
1753         }
1754         if (write_security_level == ATT_SECURITY_AUTHORIZED) {
1755             permissions |= BTP_GATT_PERM_WRITE_AUTHZ;
1756         }
1757         if (write_security_level == ATT_SECURITY_AUTHENTICATED) {
1758             permissions |= BTP_GATT_PERM_WRITE_AUTHN;
1759         }
1760         if (write_security_level == ATT_SECURITY_ENCRYPTED) {
1761             permissions |= BTP_GATT_PERM_WRITE_ENC;
1762         }
1763         if (write_security_level == ATT_SECURITY_NONE) {
1764             permissions |= BTP_GATT_PERM_WRITE;
1765         }
1766     }
1767     return permissions;
1768 }
1769 
1770 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){
1771     log_info("btp_att_get_attributes_by_uuid16 %04x from 0x%04x to 0x%04x, db %p", uuid16, start_handle, end_handle, att_database);
1772     att_dump_attributes();
1773 
1774     uint8_t num_attributes = 0;
1775     uint16_t pos = 1;
1776 
1777     att_iterator_t  it;
1778     att_iterator_init(&it);
1779     while (att_iterator_has_next(&it) && ((pos + 6) < response_buffer_size)){
1780         att_iterator_fetch_next(&it);
1781         log_info("handle %04x", it.handle);
1782         if (it.handle == 0){
1783             break;
1784         }
1785         if (it.handle < start_handle){
1786             continue;
1787         }
1788         if (it.handle > end_handle){
1789             break;
1790         }
1791         if ((uuid16 == 0) || att_iterator_match_uuid16(&it, uuid16)){
1792             little_endian_store_16(response_buffer, pos, it.handle);
1793             pos += 2;
1794             response_buffer[pos++] = btp_permissions_for_flags(it.flags);
1795             response_buffer[pos++] = 2;
1796             little_endian_store_16(response_buffer, pos, uuid16);
1797             pos += 2;
1798             num_attributes++;
1799         }
1800     }
1801     response_buffer[0] = num_attributes;
1802     return pos;
1803 }
1804 
1805 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){
1806     uint8_t num_attributes = 0;
1807     uint16_t pos = 1;
1808     att_iterator_t  it;
1809     att_iterator_init(&it);
1810     while (att_iterator_has_next(&it) && ((pos + 20) < response_buffer_size)){
1811         att_iterator_fetch_next(&it);
1812         if (it.handle == 0){
1813             break;
1814         }
1815         if (it.handle < start_handle){
1816             continue;
1817         }
1818         if (it.handle > end_handle){
1819             break;
1820         }
1821         if (att_iterator_match_uuid(&it, (uint8_t*) uuid128, 16)){
1822             little_endian_store_16(response_buffer, pos, it.handle);
1823             pos += 2;
1824             response_buffer[pos++] = btp_permissions_for_flags(it.flags);
1825             response_buffer[pos++] = 16;
1826             reverse_128(uuid128, &response_buffer[pos]);
1827             pos += 16;
1828             num_attributes++;
1829         }
1830     }
1831     response_buffer[0] = num_attributes;
1832     return pos;
1833 }
1834 
1835 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){
1836     att_iterator_t it;
1837     int ok = att_find_handle(&it, attribute_handle);
1838     if (!ok){
1839         return 0;
1840     }
1841 
1842     uint16_t pos = 0;
1843     // field: ATT_Response - simulate READ operation on given connection
1844     response_buffer[pos++] = att_validate_security(att_connection, ATT_READ, &it);
1845     // fetch len
1846     // assume: con handle not relevant here, else, it needs to get passed in
1847     // att_update_value_len(&it, HCI_CON_HANDLE_INVALID);
1848     uint16_t bytes_to_copy = btstack_min( response_buffer_size - 3, it.value_len);
1849     little_endian_store_16(response_buffer, pos, bytes_to_copy);
1850     pos += 2;
1851     // get value - only works for non-dynamic data
1852     if (it.value){
1853         memcpy(&response_buffer[pos], it.value, bytes_to_copy);
1854         pos += bytes_to_copy;
1855     }
1856     return pos;
1857 }
1858 // LCOV_EXCL_STOP
1859 #endif
1860