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