xref: /btstack/src/ble/att_db.c (revision 630ffdd469bbec3276322f46b93e6cfdfcb21c27)
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 MATTHIAS
24  * RINGWALD 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 
41 #include <stdio.h>
42 #include <string.h>
43 
44 #include "ble/att_db.h"
45 #include "ble/core.h"
46 #include "bluetooth.h"
47 #include "btstack_debug.h"
48 #include "btstack_util.h"
49 
50 // check for ENABLE_ATT_DELAYED_READ_RESPONSE -> ENABLE_ATT_DELAYED_RESPONSE,
51 #ifdef ENABLE_ATT_DELAYED_READ_RESPONSE
52     #error "ENABLE_ATT_DELAYED_READ_RESPONSE was replaced by ENABLE_ATT_DELAYED_RESPONSE. Please update btstack_config.h"
53 #endif
54 
55 typedef enum {
56     ATT_READ,
57     ATT_WRITE,
58 } att_operation_t;
59 
60 // Buetooth 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 
64 static int is_Bluetooth_Base_UUID(uint8_t const *uuid){
65     if (memcmp(&uuid[0],  &bluetooth_base_uuid[0], 12)) return 0;
66     if (memcmp(&uuid[14], &bluetooth_base_uuid[14], 2)) return 0;
67     return 1;
68 
69 }
70 
71 static uint16_t uuid16_from_uuid(uint16_t uuid_len, uint8_t * uuid){
72     if (uuid_len == 2) return little_endian_read_16(uuid, 0);
73     if (!is_Bluetooth_Base_UUID(uuid)) return 0;
74     return little_endian_read_16(uuid, 12);
75 }
76 
77 // ATT Database
78 
79 // new java-style iterator
80 typedef struct att_iterator {
81     // private
82     uint8_t const * att_ptr;
83     // public
84     uint16_t size;
85     uint16_t flags;
86     uint16_t handle;
87     uint8_t  const * uuid;
88     uint16_t value_len;
89     uint8_t  const * value;
90 } att_iterator_t;
91 
92 static void att_persistent_ccc_cache(att_iterator_t * it);
93 
94 static uint8_t const * att_db = NULL;
95 static att_read_callback_t  att_read_callback  = NULL;
96 static att_write_callback_t att_write_callback = NULL;
97 static int      att_prepare_write_error_code   = 0;
98 static uint16_t att_prepare_write_error_handle = 0x0000;
99 
100 // single cache for att_is_persistent_ccc - stores flags before write callback
101 static uint16_t att_persistent_ccc_handle;
102 static uint16_t att_persistent_ccc_uuid16;
103 
104 static void att_iterator_init(att_iterator_t *it){
105     it->att_ptr = att_db;
106 }
107 
108 static int att_iterator_has_next(att_iterator_t *it){
109     return it->att_ptr != NULL;
110 }
111 
112 static void att_iterator_fetch_next(att_iterator_t *it){
113     it->size   = little_endian_read_16(it->att_ptr, 0);
114     if (it->size == 0){
115         it->flags = 0;
116         it->handle = 0;
117         it->uuid = NULL;
118         it->value_len = 0;
119         it->value = NULL;
120         it->att_ptr = NULL;
121         return;
122     }
123     it->flags  = little_endian_read_16(it->att_ptr, 2);
124     it->handle = little_endian_read_16(it->att_ptr, 4);
125     it->uuid   = &it->att_ptr[6];
126     // handle 128 bit UUIDs
127     if (it->flags & ATT_PROPERTY_UUID128){
128         it->value_len = it->size - 22;
129         it->value  = &it->att_ptr[22];
130     } else {
131         it->value_len = it->size - 8;
132         it->value  = &it->att_ptr[8];
133     }
134     // advance AFTER setting values
135     it->att_ptr += it->size;
136 }
137 
138 static int att_iterator_match_uuid16(att_iterator_t *it, uint16_t uuid){
139     if (it->handle == 0) return 0;
140     if (it->flags & ATT_PROPERTY_UUID128){
141         if (!is_Bluetooth_Base_UUID(it->uuid)) return 0;
142         return little_endian_read_16(it->uuid, 12) == uuid;
143     }
144     return little_endian_read_16(it->uuid, 0)  == uuid;
145 }
146 
147 static int att_iterator_match_uuid(att_iterator_t *it, uint8_t *uuid, uint16_t uuid_len){
148     if (it->handle == 0) return 0;
149     // input: UUID16
150     if (uuid_len == 2) {
151         return att_iterator_match_uuid16(it, little_endian_read_16(uuid, 0));
152     }
153     // input and db: UUID128
154     if (it->flags & ATT_PROPERTY_UUID128){
155         return memcmp(it->uuid, uuid, 16) == 0;
156     }
157     // input: UUID128, db: UUID16
158     if (!is_Bluetooth_Base_UUID(uuid)) return 0;
159     return little_endian_read_16(uuid, 12) == little_endian_read_16(it->uuid, 0);
160 }
161 
162 
163 static int att_find_handle(att_iterator_t *it, uint16_t handle){
164     if (handle == 0) return 0;
165     att_iterator_init(it);
166     while (att_iterator_has_next(it)){
167         att_iterator_fetch_next(it);
168         if (it->handle != handle) continue;
169         return 1;
170     }
171     return 0;
172 }
173 
174 // experimental client API
175 uint16_t att_uuid_for_handle(uint16_t attribute_handle){
176     att_iterator_t it;
177     int ok = att_find_handle(&it, attribute_handle);
178     if (!ok) return 0;
179     if (it.flags & ATT_PROPERTY_UUID128) return 0;
180     return little_endian_read_16(it.uuid, 0);
181 }
182 // end of client API
183 
184 static void att_update_value_len(att_iterator_t *it, hci_con_handle_t con_handle){
185     if ((it->flags & ATT_PROPERTY_DYNAMIC) == 0) return;
186     it->value_len = (*att_read_callback)(con_handle, it->handle, 0, NULL, 0);
187     return;
188 }
189 
190 // copy attribute value from offset into buffer with given size
191 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){
192 
193     // DYNAMIC
194     if (it->flags & ATT_PROPERTY_DYNAMIC){
195         return (*att_read_callback)(con_handle, it->handle, offset, buffer, buffer_size);
196     }
197 
198     // STATIC
199     uint16_t bytes_to_copy = it->value_len - offset;
200     if (bytes_to_copy > buffer_size){
201         bytes_to_copy = buffer_size;
202     }
203     memcpy(buffer, it->value, bytes_to_copy);
204     return bytes_to_copy;
205 }
206 
207 void att_set_db(uint8_t const * db){
208     // validate db version
209     if (db == NULL) return;
210     if (*db++ != ATT_DB_VERSION){
211         log_error("ATT DB version differs, please regenerate .h from .gatt file or update att_db_util.c");
212         return;
213     }
214     att_db = db;
215 }
216 
217 void att_set_read_callback(att_read_callback_t callback){
218     att_read_callback = callback;
219 }
220 
221 void att_set_write_callback(att_write_callback_t callback){
222     att_write_callback = callback;
223 }
224 
225 void att_dump_attributes(void){
226     att_iterator_t it;
227     att_iterator_init(&it);
228     uint8_t uuid128[16];
229     while (att_iterator_has_next(&it)){
230         att_iterator_fetch_next(&it);
231         if (it.handle == 0) {
232             log_info("Handle: END");
233             return;
234         }
235         log_info("Handle: 0x%04x, flags: 0x%04x, uuid: ", it.handle, it.flags);
236         if (it.flags & ATT_PROPERTY_UUID128){
237             reverse_128(it.uuid, uuid128);
238             log_info("%s", uuid128_to_str(uuid128));
239         } else {
240             log_info("%04x", little_endian_read_16(it.uuid, 0));
241         }
242         log_info(", value_len: %u, value: ", it.value_len);
243         log_info_hexdump(it.value, it.value_len);
244     }
245 }
246 
247 static void att_prepare_write_reset(void){
248     att_prepare_write_error_code = 0;
249     att_prepare_write_error_handle = 0x0000;
250 }
251 
252 static void att_prepare_write_update_errors(uint8_t error_code, uint16_t handle){
253     // first ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH has highest priority
254     if (error_code == ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH && error_code != att_prepare_write_error_code){
255         att_prepare_write_error_code = error_code;
256         att_prepare_write_error_handle = handle;
257         return;
258     }
259     // first ATT_ERROR_INVALID_OFFSET is next
260     if (error_code == ATT_ERROR_INVALID_OFFSET && att_prepare_write_error_code == 0){
261         att_prepare_write_error_code = error_code;
262         att_prepare_write_error_handle = handle;
263         return;
264     }
265 }
266 
267 static uint16_t setup_error(uint8_t * response_buffer, uint16_t request, uint16_t handle, uint8_t error_code){
268     response_buffer[0] = ATT_ERROR_RESPONSE;
269     response_buffer[1] = request;
270     little_endian_store_16(response_buffer, 2, handle);
271     response_buffer[4] = error_code;
272     return 5;
273 }
274 
275 static inline uint16_t setup_error_read_not_permitted(uint8_t * response_buffer, uint16_t request, uint16_t start_handle){
276     return setup_error(response_buffer, request, start_handle, ATT_ERROR_READ_NOT_PERMITTED);
277 }
278 
279 static inline uint16_t setup_error_write_not_permitted(uint8_t * response_buffer, uint16_t request, uint16_t start_handle){
280     return setup_error(response_buffer, request, start_handle, ATT_ERROR_WRITE_NOT_PERMITTED);
281 }
282 
283 static inline uint16_t setup_error_atribute_not_found(uint8_t * response_buffer, uint16_t request, uint16_t start_handle){
284     return setup_error(response_buffer, request, start_handle, ATT_ERROR_ATTRIBUTE_NOT_FOUND);
285 }
286 
287 static inline uint16_t setup_error_invalid_handle(uint8_t * response_buffer, uint16_t request, uint16_t handle){
288     return setup_error(response_buffer, request, handle, ATT_ERROR_INVALID_HANDLE);
289 }
290 
291 static inline uint16_t setup_error_invalid_offset(uint8_t * response_buffer, uint16_t request, uint16_t handle){
292     return setup_error(response_buffer, request, handle, ATT_ERROR_INVALID_OFFSET);
293 }
294 
295 static uint8_t att_validate_security(att_connection_t * att_connection, att_operation_t operation, att_iterator_t * it){
296     int required_security_level = 0;
297     switch (operation){
298         case ATT_READ:
299             if (it->flags & ATT_PROPERTY_READ_PERMISSION_BIT_0) {
300                 required_security_level |= 1;
301             }
302             if (it->flags & ATT_PROPERTY_READ_PERMISSION_BIT_1) {
303                 required_security_level |= 2;
304             }
305             break;
306         case ATT_WRITE:
307             if (it->flags & ATT_PROPERTY_WRITE_PERMISSION_BIT_0) {
308                 required_security_level |= 1;
309             }
310             if (it->flags & ATT_PROPERTY_WRITE_PERMISSION_BIT_1) {
311                 required_security_level |= 2;
312             }
313             break;
314     }
315 
316     int required_encryption_size = it->flags >> 12;
317     if (required_encryption_size) required_encryption_size++;   // store -1 to fit into 4 bit
318 
319     log_debug("att_validate_security. flags 0x%04x (=> security level %u, key size %u) authorized %u, authenticated %u, encryption_key_size %u",
320         it->flags, required_security_level, required_encryption_size, att_connection->authorized, att_connection->authenticated, att_connection->encryption_key_size);
321 
322     if ((required_security_level >= ATT_SECURITY_AUTHORIZED) && (att_connection->authorized == 0)) {
323         return ATT_ERROR_INSUFFICIENT_AUTHORIZATION;
324     }
325     if ((required_security_level >= ATT_SECURITY_AUTHENTICATED) && (att_connection->authenticated == 0)) {
326         return ATT_ERROR_INSUFFICIENT_AUTHENTICATION;
327     }
328     if (required_security_level >= ATT_SECURITY_ENCRYPTED) {
329         if ((required_encryption_size > 0) && (att_connection->encryption_key_size == 0)){
330             return ATT_ERROR_INSUFFICIENT_ENCRYPTION;
331         }
332         if (required_encryption_size > att_connection->encryption_key_size){
333             return ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE;
334         }
335     }
336     return 0;
337 }
338 
339 //
340 // MARK: ATT_EXCHANGE_MTU_REQUEST
341 //
342 static uint16_t handle_exchange_mtu_request(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len,
343                                          uint8_t * response_buffer){
344 
345     UNUSED(request_len);
346 
347     uint16_t client_rx_mtu = little_endian_read_16(request_buffer, 1);
348 
349     // find min(local max mtu, remote mtu) and use as mtu for this connection
350     if (client_rx_mtu < att_connection->max_mtu){
351         att_connection->mtu = client_rx_mtu;
352     } else {
353         att_connection->mtu = att_connection->max_mtu;
354     }
355 
356     response_buffer[0] = ATT_EXCHANGE_MTU_RESPONSE;
357     little_endian_store_16(response_buffer, 1, att_connection->mtu);
358     return 3;
359 }
360 
361 
362 //
363 // MARK: ATT_FIND_INFORMATION_REQUEST
364 //
365 // TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID
366 //
367 static uint16_t handle_find_information_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size,
368                                            uint16_t start_handle, uint16_t end_handle){
369 
370     UNUSED(att_connection);
371 
372     log_info("ATT_FIND_INFORMATION_REQUEST: from %04X to %04X", start_handle, end_handle);
373     uint8_t request_type = ATT_FIND_INFORMATION_REQUEST;
374 
375     if (start_handle > end_handle || start_handle == 0){
376         return setup_error_invalid_handle(response_buffer, request_type, start_handle);
377     }
378 
379     uint16_t offset   = 1;
380     uint16_t uuid_len = 0;
381 
382     att_iterator_t it;
383     att_iterator_init(&it);
384     while (att_iterator_has_next(&it)){
385         att_iterator_fetch_next(&it);
386         if (!it.handle) break;
387         if (it.handle > end_handle) break;
388         if (it.handle < start_handle) continue;
389 
390         // log_info("Handle 0x%04x", it.handle);
391 
392         uint16_t this_uuid_len = (it.flags & ATT_PROPERTY_UUID128) ? 16 : 2;
393 
394         // check if value has same len as last one if not first result
395         if (offset > 1){
396             if (this_uuid_len != uuid_len) {
397                 break;
398             }
399         }
400 
401         // first
402         if (offset == 1) {
403             uuid_len = this_uuid_len;
404             // set format field
405             response_buffer[offset] = (it.flags & ATT_PROPERTY_UUID128) ? 0x02 : 0x01;
406             offset++;
407         }
408 
409         // space?
410         if (offset + 2 + uuid_len > response_buffer_size) break;
411 
412         // store
413         little_endian_store_16(response_buffer, offset, it.handle);
414         offset += 2;
415 
416         memcpy(response_buffer + offset, it.uuid, uuid_len);
417         offset += uuid_len;
418     }
419 
420     if (offset == 1){
421         return setup_error_atribute_not_found(response_buffer, request_type, start_handle);
422     }
423 
424     response_buffer[0] = ATT_FIND_INFORMATION_REPLY;
425     return offset;
426 }
427 
428 static uint16_t handle_find_information_request(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len,
429                                          uint8_t * response_buffer, uint16_t response_buffer_size){
430     UNUSED(request_len);
431     return handle_find_information_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), little_endian_read_16(request_buffer, 3));
432 }
433 
434 //
435 // MARK: ATT_FIND_BY_TYPE_VALUE
436 //
437 // "Only attributes with attribute handles between and including the Starting Handle parameter
438 // and the Ending Handle parameter that match the requested attri- bute type and the attribute
439 // value that have sufficient permissions to allow reading will be returned" -> (1)
440 //
441 // TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID
442 //
443 // NOTE: doesn't handle DYNAMIC values
444 // NOTE: only supports 16 bit UUIDs
445 //
446 static uint16_t handle_find_by_type_value_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size,
447                                            uint16_t start_handle, uint16_t end_handle,
448                                            uint16_t attribute_type, uint16_t attribute_len, uint8_t* attribute_value){
449 
450     UNUSED(att_connection);
451 
452     log_info("ATT_FIND_BY_TYPE_VALUE_REQUEST: from %04X to %04X, type %04X, value: ", start_handle, end_handle, attribute_type);
453     log_info_hexdump(attribute_value, attribute_len);
454     uint8_t request_type = ATT_FIND_BY_TYPE_VALUE_REQUEST;
455 
456     if (start_handle > end_handle || start_handle == 0){
457         return setup_error_invalid_handle(response_buffer, request_type, start_handle);
458     }
459 
460     uint16_t offset      = 1;
461     uint16_t in_group    = 0;
462     uint16_t prev_handle = 0;
463 
464     att_iterator_t it;
465     att_iterator_init(&it);
466     while (att_iterator_has_next(&it)){
467         att_iterator_fetch_next(&it);
468 
469         if (it.handle && it.handle < start_handle) continue;
470         if (it.handle > end_handle) break;  // (1)
471 
472         // close current tag, if within a group and a new service definition starts or we reach end of att db
473         if (in_group &&
474             (it.handle == 0 || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){
475 
476             log_info("End of group, handle 0x%04x", prev_handle);
477             little_endian_store_16(response_buffer, offset, prev_handle);
478             offset += 2;
479             in_group = 0;
480 
481             // check if space for another handle pair available
482             if (offset + 4 > response_buffer_size){
483                 break;
484             }
485         }
486 
487         // keep track of previous handle
488         prev_handle = it.handle;
489 
490         // does current attribute match
491         if (it.handle && att_iterator_match_uuid16(&it, attribute_type) && attribute_len == it.value_len && memcmp(attribute_value, it.value, it.value_len) == 0){
492             log_info("Begin of group, handle 0x%04x", it.handle);
493             little_endian_store_16(response_buffer, offset, it.handle);
494             offset += 2;
495             in_group = 1;
496         }
497     }
498 
499     if (offset == 1){
500         return setup_error_atribute_not_found(response_buffer, request_type, start_handle);
501     }
502 
503     response_buffer[0] = ATT_FIND_BY_TYPE_VALUE_RESPONSE;
504     return offset;
505 }
506 
507 static uint16_t handle_find_by_type_value_request(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len,
508                                            uint8_t * response_buffer, uint16_t response_buffer_size){
509     int attribute_len = request_len - 7;
510     return handle_find_by_type_value_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1),
511                                               little_endian_read_16(request_buffer, 3), little_endian_read_16(request_buffer, 5), attribute_len, &request_buffer[7]);
512 }
513 
514 //
515 // MARK: ATT_READ_BY_TYPE_REQUEST
516 //
517 static uint16_t handle_read_by_type_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size,
518                                       uint16_t start_handle, uint16_t end_handle,
519                                       uint16_t attribute_type_len, uint8_t * attribute_type){
520 
521     log_info("ATT_READ_BY_TYPE_REQUEST: from %04X to %04X, type: ", start_handle, end_handle);
522     log_info_hexdump(attribute_type, attribute_type_len);
523     uint8_t request_type = ATT_READ_BY_TYPE_REQUEST;
524 
525     if (start_handle > end_handle || start_handle == 0){
526         return setup_error_invalid_handle(response_buffer, request_type, start_handle);
527     }
528 
529     uint16_t offset   = 1;
530     uint16_t pair_len = 0;
531 
532     att_iterator_t it;
533     att_iterator_init(&it);
534     uint8_t error_code = 0;
535     uint16_t first_matching_but_unreadable_handle = 0;
536 
537 #ifdef ENABLE_ATT_DELAYED_RESPONSE
538     int read_request_pending = 0;
539 #endif
540 
541     while (att_iterator_has_next(&it)){
542         att_iterator_fetch_next(&it);
543 
544         if (!it.handle) break;
545         if (it.handle < start_handle) continue;
546         if (it.handle > end_handle) break;  // (1)
547 
548         // does current attribute match
549         if (!att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) continue;
550 
551         // skip handles that cannot be read but rembember that there has been at least one
552         if ((it.flags & ATT_PROPERTY_READ) == 0) {
553             if (first_matching_but_unreadable_handle == 0) {
554                 first_matching_but_unreadable_handle = it.handle;
555             }
556             continue;
557         }
558 
559         // check security requirements
560         error_code = att_validate_security(att_connection, ATT_READ, &it);
561         if (error_code) break;
562 
563         att_update_value_len(&it, att_connection->con_handle);
564 
565 #ifdef ENABLE_ATT_DELAYED_RESPONSE
566         if (it.value_len == ATT_READ_RESPONSE_PENDING){
567             read_request_pending = 1;
568         }
569         if (read_request_pending) continue;
570 #endif
571 
572         // check if value has same len as last one
573         uint16_t this_pair_len = 2 + it.value_len;
574         if (offset > 1){
575             if (pair_len != this_pair_len) {
576                 break;
577             }
578         }
579 
580         // first
581         if (offset == 1) {
582             pair_len = this_pair_len;
583             response_buffer[offset] = pair_len;
584             offset++;
585         }
586 
587         // space?
588         if (offset + pair_len > response_buffer_size) {
589             if (offset > 2) break;
590             it.value_len = response_buffer_size - 4;
591             response_buffer[1] = 2 + it.value_len;
592         }
593 
594         // store
595         little_endian_store_16(response_buffer, offset, it.handle);
596         offset += 2;
597         uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len, att_connection->con_handle);
598         offset += bytes_copied;
599     }
600 
601 #ifdef ENABLE_ATT_DELAYED_RESPONSE
602     if (read_request_pending) return ATT_READ_RESPONSE_PENDING;
603 #endif
604 
605     // at least one attribute could be read
606     if (offset > 1){
607         response_buffer[0] = ATT_READ_BY_TYPE_RESPONSE;
608         return offset;
609     }
610 
611     // first attribute had an error
612     if (error_code){
613         return setup_error(response_buffer, request_type, start_handle, error_code);
614     }
615 
616     // no other errors, but all found attributes had been non-readable
617     if (first_matching_but_unreadable_handle){
618         return setup_error_read_not_permitted(response_buffer, request_type, first_matching_but_unreadable_handle);
619     }
620 
621     // attribute not found
622     return setup_error_atribute_not_found(response_buffer, request_type, start_handle);
623 }
624 
625 static uint16_t handle_read_by_type_request(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len,
626                                      uint8_t * response_buffer, uint16_t response_buffer_size){
627     int attribute_type_len;
628     if (request_len <= 7){
629         attribute_type_len = 2;
630     } else {
631         attribute_type_len = 16;
632     }
633     return handle_read_by_type_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), little_endian_read_16(request_buffer, 3), attribute_type_len, &request_buffer[5]);
634 }
635 
636 //
637 // MARK: ATT_READ_BY_TYPE_REQUEST
638 //
639 static uint16_t handle_read_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle){
640 
641     log_info("ATT_READ_REQUEST: handle %04x", handle);
642     uint8_t request_type = ATT_READ_REQUEST;
643 
644     att_iterator_t it;
645     int ok = att_find_handle(&it, handle);
646     if (!ok){
647         return setup_error_invalid_handle(response_buffer, request_type, handle);
648     }
649 
650     // check if handle can be read
651     if ((it.flags & ATT_PROPERTY_READ) == 0) {
652         return setup_error_read_not_permitted(response_buffer, request_type, handle);
653     }
654 
655     // check security requirements
656     uint8_t error_code = att_validate_security(att_connection, ATT_READ, &it);
657     if (error_code) {
658         return setup_error(response_buffer, request_type, handle, error_code);
659     }
660 
661     att_update_value_len(&it, att_connection->con_handle);
662 
663 #ifdef ENABLE_ATT_DELAYED_RESPONSE
664     if (it.value_len == ATT_READ_RESPONSE_PENDING) return ATT_READ_RESPONSE_PENDING;
665 #endif
666 
667     uint16_t offset   = 1;
668     // limit data
669     if (offset + it.value_len > response_buffer_size) {
670         it.value_len = response_buffer_size - 1;
671     }
672 
673     // store
674     uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len, att_connection->con_handle);
675     offset += bytes_copied;
676 
677     response_buffer[0] = ATT_READ_RESPONSE;
678     return offset;
679 }
680 
681 static uint16_t handle_read_request(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len,
682                              uint8_t * response_buffer, uint16_t response_buffer_size){
683     UNUSED(request_len);
684     return handle_read_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1));
685 }
686 
687 //
688 // MARK: ATT_READ_BLOB_REQUEST 0x0c
689 //
690 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){
691     log_info("ATT_READ_BLOB_REQUEST: handle %04x, offset %u", handle, value_offset);
692     uint8_t request_type = ATT_READ_BLOB_REQUEST;
693 
694     att_iterator_t it;
695     int ok = att_find_handle(&it, handle);
696     if (!ok){
697         return setup_error_invalid_handle(response_buffer, request_type, handle);
698     }
699 
700     // check if handle can be read
701     if ((it.flags & ATT_PROPERTY_READ) == 0) {
702         return setup_error_read_not_permitted(response_buffer, request_type, handle);
703     }
704 
705     // check security requirements
706     uint8_t error_code = att_validate_security(att_connection, ATT_READ, &it);
707     if (error_code) {
708         return setup_error(response_buffer, request_type, handle, error_code);
709     }
710 
711     att_update_value_len(&it, att_connection->con_handle);
712 
713 #ifdef ENABLE_ATT_DELAYED_RESPONSE
714     if (it.value_len == ATT_READ_RESPONSE_PENDING) return ATT_READ_RESPONSE_PENDING;
715 #endif
716 
717     if (value_offset > it.value_len){
718         return setup_error_invalid_offset(response_buffer, request_type, handle);
719     }
720 
721     // limit data
722     uint16_t offset   = 1;
723     if (offset + it.value_len - value_offset > response_buffer_size) {
724         it.value_len = response_buffer_size - 1 + value_offset;
725     }
726 
727     // store
728     uint16_t bytes_copied = att_copy_value(&it, value_offset, response_buffer + offset, it.value_len - value_offset, att_connection->con_handle);
729     offset += bytes_copied;
730 
731     response_buffer[0] = ATT_READ_BLOB_RESPONSE;
732     return offset;
733 }
734 
735 static uint16_t handle_read_blob_request(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len,
736                                   uint8_t * response_buffer, uint16_t response_buffer_size){
737     UNUSED(request_len);
738     return handle_read_blob_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), little_endian_read_16(request_buffer, 3));
739 }
740 
741 //
742 // MARK: ATT_READ_MULTIPLE_REQUEST 0x0e
743 //
744 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){
745     log_info("ATT_READ_MULTIPLE_REQUEST: num handles %u", num_handles);
746     uint8_t request_type = ATT_READ_MULTIPLE_REQUEST;
747 
748     // TODO: figure out which error to respond with
749     // if (num_handles < 2){
750     //     return setup_error(response_buffer, ATT_READ_MULTIPLE_REQUEST, handle, ???);
751     // }
752 
753     uint16_t offset   = 1;
754 
755     int i;
756     uint8_t error_code = 0;
757     uint16_t handle = 0;
758 
759 #ifdef ENABLE_ATT_DELAYED_RESPONSE
760     int read_request_pending = 0;
761 #endif
762 
763     for (i=0;i<num_handles;i++){
764         handle = little_endian_read_16(handles, i << 1);
765 
766         if (handle == 0){
767             return setup_error_invalid_handle(response_buffer, request_type, handle);
768         }
769 
770         att_iterator_t it;
771 
772         int ok = att_find_handle(&it, handle);
773         if (!ok){
774             return setup_error_invalid_handle(response_buffer, request_type, handle);
775         }
776 
777         // check if handle can be read
778         if ((it.flags & ATT_PROPERTY_READ) == 0) {
779             error_code = ATT_ERROR_READ_NOT_PERMITTED;
780             break;
781         }
782 
783         // check security requirements
784         error_code = att_validate_security(att_connection, ATT_READ, &it);
785         if (error_code) break;
786 
787         att_update_value_len(&it, att_connection->con_handle);
788 
789 #ifdef ENABLE_ATT_DELAYED_RESPONSE
790         if (it.value_len == ATT_READ_RESPONSE_PENDING) {
791             read_request_pending = 1;
792         }
793         if (read_request_pending) continue;
794 #endif
795 
796         // limit data
797         if (offset + it.value_len > response_buffer_size) {
798             it.value_len = response_buffer_size - 1;
799         }
800 
801         // store
802         uint16_t bytes_copied = att_copy_value(&it, 0, response_buffer + offset, it.value_len, att_connection->con_handle);
803         offset += bytes_copied;
804     }
805 
806     if (error_code){
807         return setup_error(response_buffer, request_type, handle, error_code);
808     }
809 
810     response_buffer[0] = ATT_READ_MULTIPLE_RESPONSE;
811     return offset;
812 }
813 static uint16_t handle_read_multiple_request(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len,
814                                       uint8_t * response_buffer, uint16_t response_buffer_size){
815     int num_handles = (request_len - 1) >> 1;
816     return handle_read_multiple_request2(att_connection, response_buffer, response_buffer_size, num_handles, &request_buffer[1]);
817 }
818 
819 //
820 // MARK: ATT_READ_BY_GROUP_TYPE_REQUEST 0x10
821 //
822 // Only handles GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID
823 // Core v4.0, vol 3, part g, 2.5.3
824 // "The «Primary Service» and «Secondary Service» grouping types may be used in the Read By Group Type Request.
825 //  The «Characteristic» grouping type shall not be used in the ATT Read By Group Type Request."
826 //
827 // NOTE: doesn't handle DYNAMIC values
828 //
829 // NOTE: we don't check for security as PRIMARY and SECONDAY SERVICE definition shouldn't be protected
830 // Core 4.0, vol 3, part g, 8.1
831 // "The list of services and characteristics that a device supports is not considered private or
832 //  confidential information, and therefore the Service and Characteristic Discovery procedures
833 //  shall always be permitted. "
834 //
835 static uint16_t handle_read_by_group_type_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size,
836                                             uint16_t start_handle, uint16_t end_handle,
837                                             uint16_t attribute_type_len, uint8_t * attribute_type){
838 
839     UNUSED(att_connection);
840 
841     log_info("ATT_READ_BY_GROUP_TYPE_REQUEST: from %04X to %04X, buffer size %u, type: ", start_handle, end_handle, response_buffer_size);
842     log_info_hexdump(attribute_type, attribute_type_len);
843     uint8_t request_type = ATT_READ_BY_GROUP_TYPE_REQUEST;
844 
845     if (start_handle > end_handle || start_handle == 0){
846         return setup_error_invalid_handle(response_buffer, request_type, start_handle);
847     }
848 
849     // assert UUID is primary or secondary service uuid
850     uint16_t uuid16 = uuid16_from_uuid(attribute_type_len, attribute_type);
851     if (uuid16 != GATT_PRIMARY_SERVICE_UUID && uuid16 != GATT_SECONDARY_SERVICE_UUID){
852         return setup_error(response_buffer, request_type, start_handle, ATT_ERROR_UNSUPPORTED_GROUP_TYPE);
853     }
854 
855     uint16_t offset   = 1;
856     uint16_t pair_len = 0;
857     uint16_t in_group = 0;
858     uint16_t group_start_handle = 0;
859     uint8_t const * group_start_value = NULL;
860     uint16_t prev_handle = 0;
861 
862     att_iterator_t it;
863     att_iterator_init(&it);
864     while (att_iterator_has_next(&it)){
865         att_iterator_fetch_next(&it);
866 
867         if (it.handle && it.handle < start_handle) continue;
868         if (it.handle > end_handle) break;  // (1)
869 
870         // log_info("Handle 0x%04x", it.handle);
871 
872         // close current tag, if within a group and a new service definition starts or we reach end of att db
873         if (in_group &&
874             (it.handle == 0 || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){
875             // log_info("End of group, handle 0x%04x, val_len: %u", prev_handle, pair_len - 4);
876 
877             little_endian_store_16(response_buffer, offset, group_start_handle);
878             offset += 2;
879             little_endian_store_16(response_buffer, offset, prev_handle);
880             offset += 2;
881             memcpy(response_buffer + offset, group_start_value, pair_len - 4);
882             offset += pair_len - 4;
883             in_group = 0;
884 
885             // check if space for another handle pair available
886             if (offset + pair_len > response_buffer_size){
887                 break;
888             }
889         }
890 
891         // keep track of previous handle
892         prev_handle = it.handle;
893 
894         // does current attribute match
895         // log_info("compare: %04x == %04x", *(uint16_t*) context->attribute_type, *(uint16_t*) uuid);
896         if (it.handle && att_iterator_match_uuid(&it, attribute_type, attribute_type_len)) {
897 
898             // check if value has same len as last one
899             uint16_t this_pair_len = 4 + it.value_len;
900             if (offset > 1){
901                 if (this_pair_len != pair_len) {
902                     break;
903                 }
904             }
905 
906             // log_info("Begin of group, handle 0x%04x", it.handle);
907 
908             // first
909             if (offset == 1) {
910                 pair_len = this_pair_len;
911                 response_buffer[offset] = this_pair_len;
912                 offset++;
913             }
914 
915             group_start_handle = it.handle;
916             group_start_value  = it.value;
917             in_group = 1;
918         }
919     }
920 
921     if (offset == 1){
922         return setup_error_atribute_not_found(response_buffer, request_type, start_handle);
923     }
924 
925     response_buffer[0] = ATT_READ_BY_GROUP_TYPE_RESPONSE;
926     return offset;
927 }
928 static uint16_t handle_read_by_group_type_request(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len,
929                                            uint8_t * response_buffer, uint16_t response_buffer_size){
930     int attribute_type_len;
931     if (request_len <= 7){
932         attribute_type_len = 2;
933     } else {
934         attribute_type_len = 16;
935     }
936     return handle_read_by_group_type_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), little_endian_read_16(request_buffer, 3), attribute_type_len, &request_buffer[5]);
937 }
938 
939 //
940 // MARK: ATT_WRITE_REQUEST 0x12
941 static uint16_t handle_write_request(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len,
942                               uint8_t * response_buffer, uint16_t response_buffer_size){
943 
944     UNUSED(response_buffer_size);
945 
946     uint8_t request_type = ATT_WRITE_REQUEST;
947 
948     uint16_t handle = little_endian_read_16(request_buffer, 1);
949     att_iterator_t it;
950     int ok = att_find_handle(&it, handle);
951     if (!ok) {
952         return setup_error_invalid_handle(response_buffer, request_type, handle);
953     }
954     if (!att_write_callback) {
955         return setup_error_write_not_permitted(response_buffer, request_type, handle);
956     }
957     if ((it.flags & ATT_PROPERTY_WRITE) == 0) {
958         return setup_error_write_not_permitted(response_buffer, request_type, handle);
959     }
960     if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) {
961         return setup_error_write_not_permitted(response_buffer, request_type, handle);
962     }
963     // check security requirements
964     int error_code = att_validate_security(att_connection, ATT_WRITE, &it);
965     if (error_code) {
966         return setup_error(response_buffer, request_type, handle, error_code);
967     }
968     att_persistent_ccc_cache(&it);
969     error_code = (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3);
970 
971 #ifdef ENABLE_ATT_DELAYED_RESPONSE
972     if (error_code == ATT_ERROR_WRITE_RESPONSE_PENDING) return ATT_INTERNAL_WRITE_RESPONSE_PENDING;
973 #endif
974 
975     if (error_code) {
976         return setup_error(response_buffer, request_type, handle, error_code);
977     }
978     response_buffer[0] = ATT_WRITE_RESPONSE;
979     return 1;
980 }
981 
982 //
983 // MARK: ATT_PREPARE_WRITE_REQUEST 0x16
984 static uint16_t handle_prepare_write_request(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len,
985                                       uint8_t * response_buffer, uint16_t response_buffer_size){
986 
987     UNUSED(response_buffer_size);
988 
989     uint8_t request_type = ATT_PREPARE_WRITE_REQUEST;
990 
991     uint16_t handle = little_endian_read_16(request_buffer, 1);
992     uint16_t offset = little_endian_read_16(request_buffer, 3);
993     if (!att_write_callback) {
994         return setup_error_write_not_permitted(response_buffer, request_type, handle);
995     }
996     att_iterator_t it;
997     int ok = att_find_handle(&it, handle);
998     if (!ok) {
999         return setup_error_invalid_handle(response_buffer, request_type, handle);
1000     }
1001     if ((it.flags & ATT_PROPERTY_WRITE) == 0) {
1002         return setup_error_write_not_permitted(response_buffer, request_type, handle);
1003     }
1004     if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) {
1005         return setup_error_write_not_permitted(response_buffer, request_type, handle);
1006     }
1007     // check security requirements
1008     int error_code = att_validate_security(att_connection, ATT_WRITE, &it);
1009     if (error_code) {
1010         return setup_error(response_buffer, request_type, handle, error_code);
1011     }
1012 
1013     error_code = (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_ACTIVE, offset, request_buffer + 5, request_len - 5);
1014     switch (error_code){
1015         case 0:
1016             break;
1017         case ATT_ERROR_INVALID_OFFSET:
1018         case ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH:
1019             // postpone to execute write request
1020             att_prepare_write_update_errors(error_code, handle);
1021             break;
1022 #ifdef ENABLE_ATT_DELAYED_RESPONSE
1023         case ATT_ERROR_WRITE_RESPONSE_PENDING:
1024             return ATT_INTERNAL_WRITE_RESPONSE_PENDING;
1025 #endif
1026         default:
1027             return setup_error(response_buffer, request_type, handle, error_code);
1028     }
1029 
1030     // response: echo request
1031     memcpy(response_buffer, request_buffer, request_len);
1032     response_buffer[0] = ATT_PREPARE_WRITE_RESPONSE;
1033     return request_len;
1034 }
1035 
1036 /*
1037  * @brief transcation queue of prepared writes, e.g., after disconnect
1038  */
1039 void att_clear_transaction_queue(att_connection_t * att_connection){
1040     (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_CANCEL, 0, NULL, 0);
1041 }
1042 
1043 // MARK: ATT_EXECUTE_WRITE_REQUEST 0x18
1044 // NOTE: security has been verified by handle_prepare_write_request
1045 static uint16_t handle_execute_write_request(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len,
1046                                       uint8_t * response_buffer, uint16_t response_buffer_size){
1047 
1048     UNUSED(request_len);
1049     UNUSED(response_buffer_size);
1050 
1051     uint8_t request_type = ATT_EXECUTE_WRITE_REQUEST;
1052     if (request_buffer[1]) {
1053         // validate queued write
1054         if (att_prepare_write_error_code == 0){
1055             att_prepare_write_error_code = (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_VALIDATE, 0, NULL, 0);
1056         }
1057 #ifdef ENABLE_ATT_DELAYED_RESPONSE
1058         if (att_prepare_write_error_code == ATT_ERROR_WRITE_RESPONSE_PENDING) return ATT_INTERNAL_WRITE_RESPONSE_PENDING;
1059 #endif
1060         // deliver queued errors
1061         if (att_prepare_write_error_code){
1062             att_clear_transaction_queue(att_connection);
1063             uint8_t  error_code = att_prepare_write_error_code;
1064             uint16_t handle     = att_prepare_write_error_handle;
1065             att_prepare_write_reset();
1066             return setup_error(response_buffer, request_type, handle, error_code);
1067         }
1068         att_write_callback(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_EXECUTE, 0, NULL, 0);
1069     } else {
1070         att_clear_transaction_queue(att_connection);
1071     }
1072     response_buffer[0] = ATT_EXECUTE_WRITE_RESPONSE;
1073     return 1;
1074 }
1075 
1076 // MARK: ATT_WRITE_COMMAND 0x52
1077 // Core 4.0, vol 3, part F, 3.4.5.3
1078 // "No Error Response or Write Response shall be sent in response to this command"
1079 static void handle_write_command(att_connection_t * att_connection, uint8_t * request_buffer,  uint16_t request_len,
1080                                            uint8_t * response_buffer, uint16_t response_buffer_size){
1081 
1082     UNUSED(response_buffer);
1083     UNUSED(response_buffer_size);
1084 
1085     uint16_t handle = little_endian_read_16(request_buffer, 1);
1086     if (!att_write_callback) return;
1087 
1088     att_iterator_t it;
1089     int ok = att_find_handle(&it, handle);
1090     if (!ok) return;
1091     if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) return;
1092     if ((it.flags & ATT_PROPERTY_WRITE_WITHOUT_RESPONSE) == 0) return;
1093     if (att_validate_security(att_connection, ATT_WRITE, &it)) return;
1094     att_persistent_ccc_cache(&it);
1095     (*att_write_callback)(att_connection->con_handle, handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3);
1096 }
1097 
1098 // MARK: helper for ATT_HANDLE_VALUE_NOTIFICATION and ATT_HANDLE_VALUE_INDICATION
1099 static uint16_t prepare_handle_value(att_connection_t * att_connection,
1100                                      uint16_t handle,
1101                                      uint8_t *value,
1102                                      uint16_t value_len,
1103                                      uint8_t * response_buffer){
1104     little_endian_store_16(response_buffer, 1, handle);
1105     if (value_len > att_connection->mtu - 3){
1106         value_len = att_connection->mtu - 3;
1107     }
1108     memcpy(&response_buffer[3], value, value_len);
1109     return value_len + 3;
1110 }
1111 
1112 // MARK: ATT_HANDLE_VALUE_NOTIFICATION 0x1b
1113 uint16_t att_prepare_handle_value_notification(att_connection_t * att_connection,
1114                                                uint16_t handle,
1115                                                uint8_t *value,
1116                                                uint16_t value_len,
1117                                                uint8_t * response_buffer){
1118 
1119     response_buffer[0] = ATT_HANDLE_VALUE_NOTIFICATION;
1120     return prepare_handle_value(att_connection, handle, value, value_len, response_buffer);
1121 }
1122 
1123 // MARK: ATT_HANDLE_VALUE_INDICATION 0x1d
1124 uint16_t att_prepare_handle_value_indication(att_connection_t * att_connection,
1125                                              uint16_t handle,
1126                                              uint8_t *value,
1127                                              uint16_t value_len,
1128                                              uint8_t * response_buffer){
1129 
1130     response_buffer[0] = ATT_HANDLE_VALUE_INDICATION;
1131     return prepare_handle_value(att_connection, handle, value, value_len, response_buffer);
1132 }
1133 
1134 // MARK: Dispatcher
1135 uint16_t att_handle_request(att_connection_t * att_connection,
1136                             uint8_t * request_buffer,
1137                             uint16_t request_len,
1138                             uint8_t * response_buffer){
1139     uint16_t response_len = 0;
1140     uint16_t response_buffer_size = att_connection->mtu;
1141 
1142     switch (request_buffer[0]){
1143         case ATT_EXCHANGE_MTU_REQUEST:
1144             response_len = handle_exchange_mtu_request(att_connection, request_buffer, request_len, response_buffer);
1145             break;
1146         case ATT_FIND_INFORMATION_REQUEST:
1147             response_len = handle_find_information_request(att_connection, request_buffer, request_len,response_buffer, response_buffer_size);
1148             break;
1149         case ATT_FIND_BY_TYPE_VALUE_REQUEST:
1150             response_len = handle_find_by_type_value_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1151             break;
1152         case ATT_READ_BY_TYPE_REQUEST:
1153             response_len = handle_read_by_type_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1154             break;
1155         case ATT_READ_REQUEST:
1156             response_len = handle_read_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1157             break;
1158         case ATT_READ_BLOB_REQUEST:
1159             response_len = handle_read_blob_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1160             break;
1161         case ATT_READ_MULTIPLE_REQUEST:
1162             response_len = handle_read_multiple_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1163             break;
1164         case ATT_READ_BY_GROUP_TYPE_REQUEST:
1165             response_len = handle_read_by_group_type_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1166             break;
1167         case ATT_WRITE_REQUEST:
1168             response_len = handle_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1169             break;
1170         case ATT_PREPARE_WRITE_REQUEST:
1171             response_len = handle_prepare_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1172             break;
1173         case ATT_EXECUTE_WRITE_REQUEST:
1174             response_len = handle_execute_write_request(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1175             break;
1176         case ATT_WRITE_COMMAND:
1177             handle_write_command(att_connection, request_buffer, request_len, response_buffer, response_buffer_size);
1178             break;
1179 #ifdef ENABLE_LE_SIGNED_WRITE
1180         case ATT_SIGNED_WRITE_COMMAND:
1181             log_info("handle_signed_write_command preprocessed by att_server.c");
1182             break;
1183 #endif
1184         default:
1185             log_info("Unhandled ATT Command: %02X, DATA: ", request_buffer[0]);
1186             log_info_hexdump(&request_buffer[9], request_len-9);
1187             break;
1188     }
1189     return response_len;
1190 }
1191 
1192 // returns 1 if service found. only primary service.
1193 int gatt_server_get_get_handle_range_for_service_with_uuid16(uint16_t uuid16, uint16_t * start_handle, uint16_t * end_handle){
1194     uint16_t in_group    = 0;
1195     uint16_t prev_handle = 0;
1196 
1197     uint8_t attribute_value[2];
1198     int attribute_len = sizeof(attribute_value);
1199     little_endian_store_16(attribute_value, 0, uuid16);
1200 
1201     att_iterator_t it;
1202     att_iterator_init(&it);
1203     while (att_iterator_has_next(&it)){
1204         att_iterator_fetch_next(&it);
1205         int new_service_started = att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID);
1206 
1207         // close current tag, if within a group and a new service definition starts or we reach end of att db
1208         if (in_group &&
1209             (it.handle == 0 || new_service_started)){
1210             *end_handle = prev_handle;
1211             return 1;
1212         }
1213 
1214         // keep track of previous handle
1215         prev_handle = it.handle;
1216 
1217         // check if found
1218         if (it.handle && new_service_started && attribute_len == it.value_len && memcmp(attribute_value, it.value, it.value_len) == 0){
1219             *start_handle = it.handle;
1220             in_group = 1;
1221         }
1222     }
1223     return 0;
1224 }
1225 
1226 // returns 0 if not found
1227 uint16_t gatt_server_get_value_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){
1228     att_iterator_t it;
1229     att_iterator_init(&it);
1230     while (att_iterator_has_next(&it)){
1231         att_iterator_fetch_next(&it);
1232         if (it.handle && it.handle < start_handle) continue;
1233         if (it.handle > end_handle) break;  // (1)
1234         if (it.handle == 0) break;
1235         if (att_iterator_match_uuid16(&it, uuid16)) return it.handle;
1236     }
1237     return 0;
1238 }
1239 
1240 // returns 0 if not found
1241 uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uuid16(uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){
1242     att_iterator_t it;
1243     att_iterator_init(&it);
1244     int characteristic_found = 0;
1245     while (att_iterator_has_next(&it)){
1246         att_iterator_fetch_next(&it);
1247         if (it.handle && it.handle < start_handle) continue;
1248         if (it.handle > end_handle) break;  // (1)
1249         if (it.handle == 0) break;
1250         if (att_iterator_match_uuid16(&it, uuid16)){
1251             characteristic_found = 1;
1252             continue;
1253         }
1254         if (att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID)
1255          || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID)
1256          || att_iterator_match_uuid16(&it, GATT_CHARACTERISTICS_UUID)){
1257             if (characteristic_found) break;
1258             continue;
1259         }
1260         if (characteristic_found && att_iterator_match_uuid16(&it, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION)){
1261             return it.handle;
1262         }
1263     }
1264     return 0;
1265 }
1266 
1267 // returns 1 if service found. only primary service.
1268 int gatt_server_get_get_handle_range_for_service_with_uuid128(const uint8_t * uuid128, uint16_t * start_handle, uint16_t * end_handle){
1269     uint16_t in_group    = 0;
1270     uint16_t prev_handle = 0;
1271 
1272     uint8_t attribute_value[16];
1273     int attribute_len = sizeof(attribute_value);
1274     reverse_128(uuid128, attribute_value);
1275 
1276     att_iterator_t it;
1277     att_iterator_init(&it);
1278     while (att_iterator_has_next(&it)){
1279         att_iterator_fetch_next(&it);
1280         int new_service_started = att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID);
1281 
1282         // close current tag, if within a group and a new service definition starts or we reach end of att db
1283         if (in_group &&
1284             (it.handle == 0 || new_service_started)){
1285             *end_handle = prev_handle;
1286             return 1;
1287         }
1288 
1289         // keep track of previous handle
1290         prev_handle = it.handle;
1291 
1292         // check if found
1293         if (it.handle && new_service_started && attribute_len == it.value_len && memcmp(attribute_value, it.value, it.value_len) == 0){
1294             *start_handle = it.handle;
1295             in_group = 1;
1296         }
1297     }
1298     return 0;
1299 }
1300 
1301 // returns 0 if not found
1302 uint16_t gatt_server_get_value_handle_for_characteristic_with_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128){
1303     uint8_t attribute_value[16];
1304     reverse_128(uuid128, attribute_value);
1305     att_iterator_t it;
1306     att_iterator_init(&it);
1307     while (att_iterator_has_next(&it)){
1308         att_iterator_fetch_next(&it);
1309         if (it.handle && it.handle < start_handle) continue;
1310         if (it.handle > end_handle) break;  // (1)
1311         if (it.handle == 0) break;
1312         if (att_iterator_match_uuid(&it, attribute_value, 16)) return it.handle;
1313     }
1314     return 0;
1315 }
1316 
1317 // returns 0 if not found
1318 uint16_t gatt_server_get_client_configuration_handle_for_characteristic_with_uuid128(uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128){
1319     uint8_t attribute_value[16];
1320     reverse_128(uuid128, attribute_value);
1321     att_iterator_t it;
1322     att_iterator_init(&it);
1323     int characteristic_found = 0;
1324     while (att_iterator_has_next(&it)){
1325         att_iterator_fetch_next(&it);
1326         if (it.handle && it.handle < start_handle) continue;
1327         if (it.handle > end_handle) break;  // (1)
1328         if (it.handle == 0) break;
1329         if (att_iterator_match_uuid(&it, attribute_value, 16)){
1330             characteristic_found = 1;
1331             continue;
1332         }
1333         if (att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID)
1334          || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID)
1335          || att_iterator_match_uuid16(&it, GATT_CHARACTERISTICS_UUID)){
1336             if (characteristic_found) break;
1337             continue;
1338         }
1339         if (characteristic_found && att_iterator_match_uuid16(&it, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION)){
1340             return it.handle;
1341         }
1342     }
1343     return 0;
1344 }
1345 
1346 
1347 // 1-item cache to optimize query during write_callback
1348 static void att_persistent_ccc_cache(att_iterator_t * it){
1349     att_persistent_ccc_handle = it->handle;
1350     if (it->flags & ATT_PROPERTY_UUID128){
1351         att_persistent_ccc_uuid16 = 0;
1352     } else {
1353         att_persistent_ccc_uuid16 = little_endian_read_16(it->uuid, 0);
1354     }
1355 }
1356 
1357 int att_is_persistent_ccc(uint16_t handle){
1358     if (handle != att_persistent_ccc_handle){
1359         att_iterator_t it;
1360         int ok = att_find_handle(&it, handle);
1361         if (!ok) return 0;
1362         att_persistent_ccc_cache(&it);
1363     }
1364     return att_persistent_ccc_uuid16 == GATT_CLIENT_CHARACTERISTICS_CONFIGURATION;
1365 }
1366 
1367 // att_read_callback helpers
1368 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){
1369     if (buffer){
1370         uint16_t bytes_to_copy = btstack_min(blob_size - offset, buffer_size);
1371         memcpy(buffer, &blob[offset], bytes_to_copy);
1372         return bytes_to_copy;
1373     } else {
1374         return blob_size;
1375     }
1376 }
1377 
1378 uint16_t att_read_callback_handle_little_endian_32(uint32_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
1379     uint8_t value_buffer[4];
1380     little_endian_store_32(value_buffer, 0, value);
1381     return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size);
1382 }
1383 
1384 uint16_t att_read_callback_handle_little_endian_16(uint16_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
1385     uint8_t value_buffer[2];
1386     little_endian_store_16(value_buffer, 0, value);
1387     return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size);
1388 }
1389 
1390 uint16_t att_read_callback_handle_byte(uint8_t value, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
1391     uint8_t value_buffer[1];
1392     value_buffer[0] = value;
1393     return att_read_callback_handle_blob(value_buffer, sizeof(value_buffer), offset, buffer, buffer_size);
1394 }
1395