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