xref: /btstack/src/ble/gatt_client.c (revision 4601294989d1426f390e414b6614470fb0aee9a6)
13deb3ec6SMatthias Ringwald /*
23deb3ec6SMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
33deb3ec6SMatthias Ringwald  *
43deb3ec6SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
53deb3ec6SMatthias Ringwald  * modification, are permitted provided that the following conditions
63deb3ec6SMatthias Ringwald  * are met:
73deb3ec6SMatthias Ringwald  *
83deb3ec6SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
93deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
103deb3ec6SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
113deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
123deb3ec6SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
133deb3ec6SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
143deb3ec6SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
153deb3ec6SMatthias Ringwald  *    from this software without specific prior written permission.
163deb3ec6SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
173deb3ec6SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
183deb3ec6SMatthias Ringwald  *    monetary gain.
193deb3ec6SMatthias Ringwald  *
203deb3ec6SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
213deb3ec6SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
223deb3ec6SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
232fca4dadSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
253deb3ec6SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
263deb3ec6SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
273deb3ec6SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
283deb3ec6SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
293deb3ec6SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
303deb3ec6SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
313deb3ec6SMatthias Ringwald  * SUCH DAMAGE.
323deb3ec6SMatthias Ringwald  *
333deb3ec6SMatthias Ringwald  * Please inquire about commercial licensing options at
343deb3ec6SMatthias Ringwald  * [email protected]
353deb3ec6SMatthias Ringwald  *
363deb3ec6SMatthias Ringwald  */
373deb3ec6SMatthias Ringwald 
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "gatt_client.c"
39ab2c6ae4SMatthias Ringwald 
403deb3ec6SMatthias Ringwald #include <stdint.h>
413deb3ec6SMatthias Ringwald #include <string.h>
42a95ca902SMatthias Ringwald #include <stddef.h>
433deb3ec6SMatthias Ringwald 
447907f069SMatthias Ringwald #include "btstack_config.h"
453deb3ec6SMatthias Ringwald 
46296289e3SMatthias Ringwald #include "ble/att_dispatch.h"
470e2df43fSMatthias Ringwald #include "ble/att_db.h"
480e2df43fSMatthias Ringwald #include "ble/gatt_client.h"
490e2df43fSMatthias Ringwald #include "ble/le_device_db.h"
500e2df43fSMatthias Ringwald #include "ble/sm.h"
5116ece135SMatthias Ringwald #include "btstack_debug.h"
520e2df43fSMatthias Ringwald #include "btstack_event.h"
533deb3ec6SMatthias Ringwald #include "btstack_memory.h"
540e2df43fSMatthias Ringwald #include "btstack_run_loop.h"
550e2df43fSMatthias Ringwald #include "btstack_util.h"
563deb3ec6SMatthias Ringwald #include "hci.h"
573deb3ec6SMatthias Ringwald #include "hci_dump.h"
583deb3ec6SMatthias Ringwald #include "l2cap.h"
591450cdc6SMatthias Ringwald #include "classic/sdp_client.h"
601450cdc6SMatthias Ringwald #include "bluetooth_gatt.h"
611450cdc6SMatthias Ringwald #include "bluetooth_sdp.h"
621450cdc6SMatthias Ringwald #include "classic/sdp_util.h"
633deb3ec6SMatthias Ringwald 
649c662c9bSMatthias Ringwald static btstack_linked_list_t gatt_client_connections;
659c662c9bSMatthias Ringwald static btstack_linked_list_t gatt_client_value_listeners;
66361b1363SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
67f4b33574SMatthias Ringwald static btstack_packet_callback_registration_t sm_event_callback_registration;
68f4b33574SMatthias Ringwald 
6911279da7SMatthias Ringwald // GATT Client Configuration
7011279da7SMatthias Ringwald static bool                 gatt_client_mtu_exchange_enabled;
7111279da7SMatthias Ringwald static gap_security_level_t gatt_client_required_security_level;
725cf6c434SJakob Krantz 
733deb3ec6SMatthias Ringwald static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size);
74f4b33574SMatthias Ringwald static void gatt_client_event_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
755cf1669fSMatthias Ringwald static void gatt_client_report_error_if_pending(gatt_client_t *gatt_client, uint8_t att_error_code);
767a766ebfSMatthias Ringwald 
777a766ebfSMatthias Ringwald #ifdef ENABLE_LE_SIGNED_WRITE
783deb3ec6SMatthias Ringwald static void att_signed_write_handle_cmac_result(uint8_t hash[8]);
797a766ebfSMatthias Ringwald #endif
803deb3ec6SMatthias Ringwald 
813deb3ec6SMatthias Ringwald void gatt_client_init(void){
823deb3ec6SMatthias Ringwald     gatt_client_connections = NULL;
83f4b33574SMatthias Ringwald 
8411279da7SMatthias Ringwald     // default configuration
8511279da7SMatthias Ringwald     gatt_client_mtu_exchange_enabled    = true;
8611279da7SMatthias Ringwald     gatt_client_required_security_level = LEVEL_0;
8711279da7SMatthias Ringwald 
8811279da7SMatthias Ringwald     // register for HCI Events
89f4b33574SMatthias Ringwald     hci_event_callback_registration.callback = &gatt_client_event_packet_handler;
90361b1363SMatthias Ringwald     hci_add_event_handler(&hci_event_callback_registration);
91361b1363SMatthias Ringwald 
92f4b33574SMatthias Ringwald     // register for SM Events
93f4b33574SMatthias Ringwald     sm_event_callback_registration.callback = &gatt_client_event_packet_handler;
94f4b33574SMatthias Ringwald     sm_add_event_handler(&sm_event_callback_registration);
95f4b33574SMatthias Ringwald 
96361b1363SMatthias Ringwald     // and ATT Client PDUs
973deb3ec6SMatthias Ringwald     att_dispatch_register_client(gatt_client_att_packet_handler);
983deb3ec6SMatthias Ringwald }
993deb3ec6SMatthias Ringwald 
10011279da7SMatthias Ringwald void gatt_client_set_required_security_level(gap_security_level_t level){
10111279da7SMatthias Ringwald     gatt_client_required_security_level = level;
10211279da7SMatthias Ringwald }
10311279da7SMatthias Ringwald 
104ec820d77SMatthias Ringwald static gatt_client_t * gatt_client_for_timer(btstack_timer_source_t * ts){
105665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
106665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &gatt_client_connections);
107665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
1085cf1669fSMatthias Ringwald         gatt_client_t * gatt_client = (gatt_client_t *) btstack_linked_list_iterator_next(&it);
1095cf1669fSMatthias Ringwald         if (&gatt_client->gc_timeout == ts) {
1105cf1669fSMatthias Ringwald             return gatt_client;
1113deb3ec6SMatthias Ringwald         }
1123deb3ec6SMatthias Ringwald     }
1133deb3ec6SMatthias Ringwald     return NULL;
1143deb3ec6SMatthias Ringwald }
1153deb3ec6SMatthias Ringwald 
116ec820d77SMatthias Ringwald static void gatt_client_timeout_handler(btstack_timer_source_t * timer){
1175cf1669fSMatthias Ringwald     gatt_client_t * gatt_client = gatt_client_for_timer(timer);
1185cf1669fSMatthias Ringwald     if (gatt_client == NULL) return;
1195cf1669fSMatthias Ringwald     log_info("GATT client timeout handle, handle 0x%02x", gatt_client->con_handle);
1205cf1669fSMatthias Ringwald     gatt_client_report_error_if_pending(gatt_client, ATT_ERROR_TIMEOUT);
1213deb3ec6SMatthias Ringwald }
1223deb3ec6SMatthias Ringwald 
1235cf1669fSMatthias Ringwald static void gatt_client_timeout_start(gatt_client_t * gatt_client){
1245cf1669fSMatthias Ringwald     log_info("GATT client timeout start, handle 0x%02x", gatt_client->con_handle);
1255cf1669fSMatthias Ringwald     btstack_run_loop_remove_timer(&gatt_client->gc_timeout);
1265cf1669fSMatthias Ringwald     btstack_run_loop_set_timer_handler(&gatt_client->gc_timeout, gatt_client_timeout_handler);
1275cf1669fSMatthias Ringwald     btstack_run_loop_set_timer(&gatt_client->gc_timeout, 30000); // 30 seconds sm timeout
1285cf1669fSMatthias Ringwald     btstack_run_loop_add_timer(&gatt_client->gc_timeout);
1293deb3ec6SMatthias Ringwald }
1303deb3ec6SMatthias Ringwald 
1315cf1669fSMatthias Ringwald static void gatt_client_timeout_stop(gatt_client_t * gatt_client){
1325cf1669fSMatthias Ringwald     log_info("GATT client timeout stop, handle 0x%02x", gatt_client->con_handle);
1335cf1669fSMatthias Ringwald     btstack_run_loop_remove_timer(&gatt_client->gc_timeout);
1343deb3ec6SMatthias Ringwald }
1353deb3ec6SMatthias Ringwald 
1361dfae9c7SMatthias Ringwald static gap_security_level_t gatt_client_le_security_level_for_connection(hci_con_handle_t con_handle){
1371dfae9c7SMatthias Ringwald     uint8_t encryption_key_size = gap_encryption_key_size(con_handle);
1381dfae9c7SMatthias Ringwald     if (encryption_key_size == 0) return LEVEL_0;
1391dfae9c7SMatthias Ringwald 
140ff3f1026SMatthias Ringwald     bool authenticated = gap_authenticated(con_handle);
1411dfae9c7SMatthias Ringwald     if (!authenticated) return LEVEL_2;
1421dfae9c7SMatthias Ringwald 
1431dfae9c7SMatthias Ringwald     return encryption_key_size == 16 ? LEVEL_4 : LEVEL_3;
1441dfae9c7SMatthias Ringwald }
1451dfae9c7SMatthias Ringwald 
1465cf1669fSMatthias Ringwald static gatt_client_t * gatt_client_get_context_for_handle(uint16_t handle){
147665d90f2SMatthias Ringwald     btstack_linked_item_t *it;
148a0da043fSMatthias Ringwald     for (it = (btstack_linked_item_t *) gatt_client_connections; it != NULL; it = it->next){
1495cf1669fSMatthias Ringwald         gatt_client_t * gatt_client = (gatt_client_t *) it;
1505cf1669fSMatthias Ringwald         if (gatt_client->con_handle == handle){
1515cf1669fSMatthias Ringwald             return gatt_client;
1523deb3ec6SMatthias Ringwald         }
1533deb3ec6SMatthias Ringwald     }
1543deb3ec6SMatthias Ringwald     return NULL;
1553deb3ec6SMatthias Ringwald }
1563deb3ec6SMatthias Ringwald 
1573deb3ec6SMatthias Ringwald 
1586b65794dSMilanka Ringwald // @return gatt_client context
1593deb3ec6SMatthias Ringwald // returns existing one, or tries to setup new one
16040faeb84SMilanka Ringwald static uint8_t gatt_client_provide_context_for_handle(hci_con_handle_t con_handle, gatt_client_t ** out_gatt_client){
1615cf1669fSMatthias Ringwald     gatt_client_t * gatt_client = gatt_client_get_context_for_handle(con_handle);
16240faeb84SMilanka Ringwald 
16340faeb84SMilanka Ringwald     if (gatt_client != NULL){
16440faeb84SMilanka Ringwald         *out_gatt_client = gatt_client;
16540faeb84SMilanka Ringwald         return ERROR_CODE_SUCCESS;
16640faeb84SMilanka Ringwald     }
1673deb3ec6SMatthias Ringwald 
168ae1d1237SMatthias Ringwald     // bail if no such hci connection
1690e0bba86SMatthias Ringwald     hci_connection_t * hci_connection = hci_connection_for_handle(con_handle);
1700e0bba86SMatthias Ringwald     if (hci_connection == NULL){
171ae1d1237SMatthias Ringwald         log_error("No connection for handle 0x%04x", con_handle);
17240faeb84SMilanka Ringwald         *out_gatt_client = NULL;
17340faeb84SMilanka Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
174ae1d1237SMatthias Ringwald     }
17540faeb84SMilanka Ringwald 
1765cf1669fSMatthias Ringwald     gatt_client = btstack_memory_gatt_client_get();
17740faeb84SMilanka Ringwald     if (gatt_client == NULL){
17840faeb84SMilanka Ringwald         *out_gatt_client = NULL;
17940faeb84SMilanka Ringwald         return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED;
18040faeb84SMilanka Ringwald     }
1813deb3ec6SMatthias Ringwald     // init state
182e9cdf30bSMatthias Ringwald     gatt_client->bearer_type = ATT_BEARER_UNENHANCED_LE;
1835cf1669fSMatthias Ringwald     gatt_client->con_handle = con_handle;
1845cf1669fSMatthias Ringwald     gatt_client->mtu = ATT_DEFAULT_MTU;
1851dfae9c7SMatthias Ringwald     gatt_client->security_level = gatt_client_le_security_level_for_connection(con_handle);
18611279da7SMatthias Ringwald     if (gatt_client_mtu_exchange_enabled){
1875cf1669fSMatthias Ringwald         gatt_client->mtu_state = SEND_MTU_EXCHANGE;
1885cf6c434SJakob Krantz     } else {
1895cf1669fSMatthias Ringwald         gatt_client->mtu_state = MTU_AUTO_EXCHANGE_DISABLED;
1905cf6c434SJakob Krantz     }
1915cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_READY;
1925cf1669fSMatthias Ringwald     btstack_linked_list_add(&gatt_client_connections, (btstack_linked_item_t*)gatt_client);
1930e0bba86SMatthias Ringwald 
1940e0bba86SMatthias Ringwald     // get unenhanced att bearer state
1950e0bba86SMatthias Ringwald     if (hci_connection->att_connection.mtu_exchanged){
1960e0bba86SMatthias Ringwald         gatt_client->mtu = hci_connection->att_connection.mtu;
1970e0bba86SMatthias Ringwald         gatt_client->mtu_state = MTU_EXCHANGED;
1980e0bba86SMatthias Ringwald     }
19940faeb84SMilanka Ringwald     *out_gatt_client = gatt_client;
20040faeb84SMilanka Ringwald     return ERROR_CODE_SUCCESS;
2013deb3ec6SMatthias Ringwald }
2023deb3ec6SMatthias Ringwald 
203de27733dSMatthias Ringwald static bool is_ready(gatt_client_t * gatt_client){
204de27733dSMatthias Ringwald     return gatt_client->gatt_client_state == P_READY;
205de27733dSMatthias Ringwald }
206de27733dSMatthias Ringwald 
207de27733dSMatthias Ringwald static uint8_t gatt_client_provide_context_for_request(hci_con_handle_t con_handle, gatt_client_t ** out_gatt_client){
208de27733dSMatthias Ringwald     gatt_client_t * gatt_client = NULL;
209de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client);
21040faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
21140faeb84SMilanka Ringwald         return status;
21240faeb84SMilanka Ringwald     }
213de27733dSMatthias Ringwald 
214de27733dSMatthias Ringwald     if (is_ready(gatt_client) == 0){
215de27733dSMatthias Ringwald         return GATT_CLIENT_IN_WRONG_STATE;
2163deb3ec6SMatthias Ringwald     }
2173deb3ec6SMatthias Ringwald 
218de27733dSMatthias Ringwald     gatt_client_timeout_start(gatt_client);
219de27733dSMatthias Ringwald 
220de27733dSMatthias Ringwald     *out_gatt_client = gatt_client;
221de27733dSMatthias Ringwald 
222de27733dSMatthias Ringwald     return status;
2233deb3ec6SMatthias Ringwald }
2243deb3ec6SMatthias Ringwald 
225fc64f94aSMatthias Ringwald int gatt_client_is_ready(hci_con_handle_t con_handle){
22640faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
22740faeb84SMilanka Ringwald     uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client);
22840faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
22940faeb84SMilanka Ringwald         return 0;
23040faeb84SMilanka Ringwald     }
231aacf1b1aSMilanka Ringwald     return is_ready(gatt_client) ? 1 : 0;
2323deb3ec6SMatthias Ringwald }
2333deb3ec6SMatthias Ringwald 
2345cf6c434SJakob Krantz void gatt_client_mtu_enable_auto_negotiation(uint8_t enabled){
23511279da7SMatthias Ringwald     gatt_client_mtu_exchange_enabled = enabled != 0;
2365cf6c434SJakob Krantz }
2375cf6c434SJakob Krantz 
238fc64f94aSMatthias Ringwald uint8_t gatt_client_get_mtu(hci_con_handle_t con_handle, uint16_t * mtu){
23940faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
24040faeb84SMilanka Ringwald     uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client);
24140faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
24240faeb84SMilanka Ringwald         return status;
24340faeb84SMilanka Ringwald     }
2447d2258b3SMilanka Ringwald 
2455cf1669fSMatthias Ringwald     if ((gatt_client->mtu_state == MTU_EXCHANGED) || (gatt_client->mtu_state == MTU_AUTO_EXCHANGE_DISABLED)){
2465cf1669fSMatthias Ringwald         *mtu = gatt_client->mtu;
2477d2258b3SMilanka Ringwald         return ERROR_CODE_SUCCESS;
2483deb3ec6SMatthias Ringwald     }
2493deb3ec6SMatthias Ringwald     *mtu = ATT_DEFAULT_MTU;
250616edd56SMatthias Ringwald     return GATT_CLIENT_IN_WRONG_STATE;
2513deb3ec6SMatthias Ringwald }
2523deb3ec6SMatthias Ringwald 
2539228fd32SMatthias Ringwald static uint8_t *gatt_client_reserve_request_buffer(gatt_client_t *gatt_client) {
2549228fd32SMatthias Ringwald     l2cap_reserve_packet_buffer();
2559228fd32SMatthias Ringwald     return l2cap_get_outgoing_buffer();
2569228fd32SMatthias Ringwald }
2579228fd32SMatthias Ringwald 
2583deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
2596e7b444cSMatthias Ringwald static uint8_t gatt_client_send(gatt_client_t * gatt_client, uint16_t len){
260*46012949SMatthias Ringwald     switch (gatt_client->bearer_type){
261*46012949SMatthias Ringwald         case ATT_BEARER_UNENHANCED_LE:
2626e7b444cSMatthias Ringwald             return l2cap_send_prepared_connectionless(gatt_client->con_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, len);
263*46012949SMatthias Ringwald #ifdef ENABLE_GATT_OVER_CLASSIC
264*46012949SMatthias Ringwald         case ATT_BEARER_UNENHANCED_CLASSIC:
265*46012949SMatthias Ringwald             return l2cap_send_prepared(gatt_client->l2cap_cid, len);
266*46012949SMatthias Ringwald #endif
267*46012949SMatthias Ringwald         default:
268*46012949SMatthias Ringwald             btstack_unreachable();
269*46012949SMatthias Ringwald             return ERROR_CODE_HARDWARE_FAILURE;
270*46012949SMatthias Ringwald     }
2713deb3ec6SMatthias Ringwald }
2723deb3ec6SMatthias Ringwald 
2733deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
2746e7b444cSMatthias Ringwald static uint8_t att_confirmation(gatt_client_t * gatt_client) {
2759228fd32SMatthias Ringwald     uint8_t *request = gatt_client_reserve_request_buffer(gatt_client);
2766e7b444cSMatthias Ringwald 
2776e7b444cSMatthias Ringwald     request[0] = ATT_HANDLE_VALUE_CONFIRMATION;
2786e7b444cSMatthias Ringwald 
2796e7b444cSMatthias Ringwald     return gatt_client_send(gatt_client, 1);
2806e7b444cSMatthias Ringwald }
2816e7b444cSMatthias Ringwald 
2826e7b444cSMatthias Ringwald // precondition: can_send_packet_now == TRUE
2836e7b444cSMatthias Ringwald static uint8_t att_find_information_request(gatt_client_t *gatt_client, uint8_t request_type, uint16_t start_handle,
2846e7b444cSMatthias Ringwald                                             uint16_t end_handle) {
2859228fd32SMatthias Ringwald     uint8_t *request = gatt_client_reserve_request_buffer(gatt_client);
2866e7b444cSMatthias Ringwald 
2873deb3ec6SMatthias Ringwald     request[0] = request_type;
288f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 1, start_handle);
289f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 3, end_handle);
2903deb3ec6SMatthias Ringwald 
2916e7b444cSMatthias Ringwald     return gatt_client_send(gatt_client, 5);
2923deb3ec6SMatthias Ringwald }
2933deb3ec6SMatthias Ringwald 
2943deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
2956e7b444cSMatthias Ringwald static uint8_t
2966e7b444cSMatthias Ringwald att_find_by_type_value_request(gatt_client_t *gatt_client, uint8_t request_type, uint16_t attribute_group_type,
2976e7b444cSMatthias Ringwald                                uint16_t start_handle, uint16_t end_handle, uint8_t *value, uint16_t value_size) {
2989228fd32SMatthias Ringwald     uint8_t *request = gatt_client_reserve_request_buffer(gatt_client);
2993deb3ec6SMatthias Ringwald     request[0] = request_type;
3009228fd32SMatthias Ringwald 
301f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 1, start_handle);
302f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 3, end_handle);
303f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 5, attribute_group_type);
3046535961aSMatthias Ringwald     (void)memcpy(&request[7], value, value_size);
3053deb3ec6SMatthias Ringwald 
3066e7b444cSMatthias Ringwald     return gatt_client_send(gatt_client, 7u + value_size);
3073deb3ec6SMatthias Ringwald }
3083deb3ec6SMatthias Ringwald 
3093deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
3106e7b444cSMatthias Ringwald static uint8_t
3116e7b444cSMatthias Ringwald att_read_by_type_or_group_request_for_uuid16(gatt_client_t *gatt_client, uint8_t request_type, uint16_t uuid16,
3126e7b444cSMatthias Ringwald                                              uint16_t start_handle, uint16_t end_handle) {
3139228fd32SMatthias Ringwald     uint8_t *request = gatt_client_reserve_request_buffer(gatt_client);
3146e7b444cSMatthias Ringwald 
3153deb3ec6SMatthias Ringwald     request[0] = request_type;
316f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 1, start_handle);
317f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 3, end_handle);
318f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 5, uuid16);
3193deb3ec6SMatthias Ringwald 
3206e7b444cSMatthias Ringwald     return gatt_client_send(gatt_client, 7);
3213deb3ec6SMatthias Ringwald }
3223deb3ec6SMatthias Ringwald 
3233deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
3246e7b444cSMatthias Ringwald static uint8_t
3256e7b444cSMatthias Ringwald att_read_by_type_or_group_request_for_uuid128(gatt_client_t *gatt_client, uint8_t request_type, const uint8_t *uuid128,
3266e7b444cSMatthias Ringwald                                               uint16_t start_handle, uint16_t end_handle) {
3279228fd32SMatthias Ringwald     uint8_t *request = gatt_client_reserve_request_buffer(gatt_client);
3286e7b444cSMatthias Ringwald 
3293deb3ec6SMatthias Ringwald     request[0] = request_type;
330f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 1, start_handle);
331f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 3, end_handle);
3329c80e4ccSMatthias Ringwald     reverse_128(uuid128, &request[5]);
3333deb3ec6SMatthias Ringwald 
3346e7b444cSMatthias Ringwald     return gatt_client_send(gatt_client, 21);
3353deb3ec6SMatthias Ringwald }
3363deb3ec6SMatthias Ringwald 
3373deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
3386e7b444cSMatthias Ringwald static uint8_t att_read_request(gatt_client_t *gatt_client, uint8_t request_type, uint16_t attribute_handle) {
3399228fd32SMatthias Ringwald     uint8_t *request = gatt_client_reserve_request_buffer(gatt_client);
3406e7b444cSMatthias Ringwald 
3413deb3ec6SMatthias Ringwald     request[0] = request_type;
342f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 1, attribute_handle);
3433deb3ec6SMatthias Ringwald 
3446e7b444cSMatthias Ringwald     return gatt_client_send(gatt_client, 3);
3453deb3ec6SMatthias Ringwald }
3463deb3ec6SMatthias Ringwald 
3473deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
3486e7b444cSMatthias Ringwald static uint8_t att_read_blob_request(gatt_client_t *gatt_client, uint8_t request_type, uint16_t attribute_handle,
3496e7b444cSMatthias Ringwald                                      uint16_t value_offset) {
3509228fd32SMatthias Ringwald     uint8_t *request = gatt_client_reserve_request_buffer(gatt_client);
3519228fd32SMatthias Ringwald 
3523deb3ec6SMatthias Ringwald     request[0] = request_type;
353f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 1, attribute_handle);
354f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 3, value_offset);
3553deb3ec6SMatthias Ringwald 
3566e7b444cSMatthias Ringwald     return gatt_client_send(gatt_client, 5);
3573deb3ec6SMatthias Ringwald }
3583deb3ec6SMatthias Ringwald 
3596e7b444cSMatthias Ringwald static uint8_t
3606e7b444cSMatthias Ringwald att_read_multiple_request(gatt_client_t *gatt_client, uint16_t num_value_handles, uint16_t *value_handles) {
3619228fd32SMatthias Ringwald     uint8_t *request = gatt_client_reserve_request_buffer(gatt_client);
3629228fd32SMatthias Ringwald 
3633deb3ec6SMatthias Ringwald     request[0] = ATT_READ_MULTIPLE_REQUEST;
3649228fd32SMatthias Ringwald     uint16_t i;
3659228fd32SMatthias Ringwald     uint16_t offset = 1;
3663deb3ec6SMatthias Ringwald     for (i=0;i<num_value_handles;i++){
367f8fbdce0SMatthias Ringwald         little_endian_store_16(request, offset, value_handles[i]);
3683deb3ec6SMatthias Ringwald         offset += 2;
3693deb3ec6SMatthias Ringwald     }
37025b7c058SMilanka Ringwald 
3716e7b444cSMatthias Ringwald     return gatt_client_send(gatt_client, offset);
3723deb3ec6SMatthias Ringwald }
3733deb3ec6SMatthias Ringwald 
3747a766ebfSMatthias Ringwald #ifdef ENABLE_LE_SIGNED_WRITE
3753deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
3766e7b444cSMatthias Ringwald static uint8_t att_signed_write_request(gatt_client_t *gatt_client, uint16_t request_type, uint16_t attribute_handle,
3776e7b444cSMatthias Ringwald                                         uint16_t value_length, uint8_t *value, uint32_t sign_counter, uint8_t sgn[8]) {
3789228fd32SMatthias Ringwald     uint8_t *request = gatt_client_reserve_request_buffer(gatt_client);
3799228fd32SMatthias Ringwald 
3803deb3ec6SMatthias Ringwald     request[0] = request_type;
381f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 1, attribute_handle);
3826535961aSMatthias Ringwald     (void)memcpy(&request[3], value, value_length);
383f8fbdce0SMatthias Ringwald     little_endian_store_32(request, 3 + value_length, sign_counter);
3849c80e4ccSMatthias Ringwald     reverse_64(sgn, &request[3 + value_length + 4]);
38525b7c058SMilanka Ringwald 
3866e7b444cSMatthias Ringwald     return gatt_client_send(gatt_client, 3 + value_length + 12);
3873deb3ec6SMatthias Ringwald }
3887a766ebfSMatthias Ringwald #endif
3893deb3ec6SMatthias Ringwald 
3903deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
3916e7b444cSMatthias Ringwald static uint8_t
3926e7b444cSMatthias Ringwald att_write_request(gatt_client_t *gatt_client, uint8_t request_type, uint16_t attribute_handle, uint16_t value_length,
3936e7b444cSMatthias Ringwald                   uint8_t *value) {
3949228fd32SMatthias Ringwald     uint8_t *request = gatt_client_reserve_request_buffer(gatt_client);
3959228fd32SMatthias Ringwald 
3963deb3ec6SMatthias Ringwald     request[0] = request_type;
397f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 1, attribute_handle);
3986535961aSMatthias Ringwald     (void)memcpy(&request[3], value, value_length);
3993deb3ec6SMatthias Ringwald 
4006e7b444cSMatthias Ringwald     return gatt_client_send(gatt_client, 3u + value_length);
4013deb3ec6SMatthias Ringwald }
4023deb3ec6SMatthias Ringwald 
4033deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
4046e7b444cSMatthias Ringwald static uint8_t att_execute_write_request(gatt_client_t *gatt_client, uint8_t request_type, uint8_t execute_write) {
4059228fd32SMatthias Ringwald     uint8_t *request = gatt_client_reserve_request_buffer(gatt_client);
4069228fd32SMatthias Ringwald 
4073deb3ec6SMatthias Ringwald     request[0] = request_type;
4083deb3ec6SMatthias Ringwald     request[1] = execute_write;
40925b7c058SMilanka Ringwald 
4106e7b444cSMatthias Ringwald     return gatt_client_send(gatt_client, 2);
4113deb3ec6SMatthias Ringwald }
4123deb3ec6SMatthias Ringwald 
4133deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
4146e7b444cSMatthias Ringwald static uint8_t att_prepare_write_request(gatt_client_t *gatt_client, uint8_t request_type, uint16_t attribute_handle,
4156e7b444cSMatthias Ringwald                                          uint16_t value_offset, uint16_t blob_length, uint8_t *value) {
4169228fd32SMatthias Ringwald     uint8_t *request = gatt_client_reserve_request_buffer(gatt_client);
4179228fd32SMatthias Ringwald 
4183deb3ec6SMatthias Ringwald     request[0] = request_type;
419f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 1, attribute_handle);
420f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 3, value_offset);
4216535961aSMatthias Ringwald     (void)memcpy(&request[5], &value[value_offset], blob_length);
4223deb3ec6SMatthias Ringwald 
4236e7b444cSMatthias Ringwald     return gatt_client_send(gatt_client,  5u + blob_length);
4243deb3ec6SMatthias Ringwald }
4253deb3ec6SMatthias Ringwald 
4266e7b444cSMatthias Ringwald static uint8_t att_exchange_mtu_request(gatt_client_t *gatt_client) {
4279228fd32SMatthias Ringwald     uint8_t *request = gatt_client_reserve_request_buffer(gatt_client);
4289228fd32SMatthias Ringwald 
4293deb3ec6SMatthias Ringwald     request[0] = ATT_EXCHANGE_MTU_REQUEST;
4309228fd32SMatthias Ringwald     uint16_t mtu = l2cap_max_le_mtu();
431f8fbdce0SMatthias Ringwald     little_endian_store_16(request, 1, mtu);
43225b7c058SMilanka Ringwald 
4336e7b444cSMatthias Ringwald     return gatt_client_send(gatt_client, 3);
4343deb3ec6SMatthias Ringwald }
4353deb3ec6SMatthias Ringwald 
4365cf1669fSMatthias Ringwald static uint16_t write_blob_length(gatt_client_t * gatt_client){
437dda77937SMatthias Ringwald     uint16_t max_blob_length = gatt_client->mtu - 5u;
4385cf1669fSMatthias Ringwald     if (gatt_client->attribute_offset >= gatt_client->attribute_length) {
4393deb3ec6SMatthias Ringwald         return 0;
4403deb3ec6SMatthias Ringwald     }
4415cf1669fSMatthias Ringwald     uint16_t rest_length = gatt_client->attribute_length - gatt_client->attribute_offset;
4423deb3ec6SMatthias Ringwald     if (max_blob_length > rest_length){
4433deb3ec6SMatthias Ringwald         return rest_length;
4443deb3ec6SMatthias Ringwald     }
4453deb3ec6SMatthias Ringwald     return max_blob_length;
4463deb3ec6SMatthias Ringwald }
4473deb3ec6SMatthias Ringwald 
4485cf1669fSMatthias Ringwald static void send_gatt_services_request(gatt_client_t *gatt_client){
4496e7b444cSMatthias Ringwald     att_read_by_type_or_group_request_for_uuid16(gatt_client, ATT_READ_BY_GROUP_TYPE_REQUEST,
4506e7b444cSMatthias Ringwald                                                  gatt_client->uuid16, gatt_client->start_group_handle,
4516e7b444cSMatthias Ringwald                                                  gatt_client->end_group_handle);
4523deb3ec6SMatthias Ringwald }
4533deb3ec6SMatthias Ringwald 
4545cf1669fSMatthias Ringwald static void send_gatt_by_uuid_request(gatt_client_t *gatt_client, uint16_t attribute_group_type){
4555cf1669fSMatthias Ringwald     if (gatt_client->uuid16){
4563deb3ec6SMatthias Ringwald         uint8_t uuid16[2];
4575cf1669fSMatthias Ringwald         little_endian_store_16(uuid16, 0, gatt_client->uuid16);
4586e7b444cSMatthias Ringwald         att_find_by_type_value_request(gatt_client, ATT_FIND_BY_TYPE_VALUE_REQUEST, attribute_group_type,
4596e7b444cSMatthias Ringwald                                        gatt_client->start_group_handle, gatt_client->end_group_handle, uuid16, 2);
4603deb3ec6SMatthias Ringwald         return;
4613deb3ec6SMatthias Ringwald     }
4623deb3ec6SMatthias Ringwald     uint8_t uuid128[16];
4635cf1669fSMatthias Ringwald     reverse_128(gatt_client->uuid128, uuid128);
4646e7b444cSMatthias Ringwald     att_find_by_type_value_request(gatt_client, ATT_FIND_BY_TYPE_VALUE_REQUEST, attribute_group_type,
4656e7b444cSMatthias Ringwald                                    gatt_client->start_group_handle, gatt_client->end_group_handle, uuid128, 16);
4663deb3ec6SMatthias Ringwald }
4673deb3ec6SMatthias Ringwald 
4685cf1669fSMatthias Ringwald static void send_gatt_services_by_uuid_request(gatt_client_t *gatt_client){
4695cf1669fSMatthias Ringwald     send_gatt_by_uuid_request(gatt_client, GATT_PRIMARY_SERVICE_UUID);
4703deb3ec6SMatthias Ringwald }
4713deb3ec6SMatthias Ringwald 
4725cf1669fSMatthias Ringwald static void send_gatt_included_service_uuid_request(gatt_client_t *gatt_client){
4736e7b444cSMatthias Ringwald     att_read_request(gatt_client, ATT_READ_REQUEST, gatt_client->query_start_handle);
4743deb3ec6SMatthias Ringwald }
4753deb3ec6SMatthias Ringwald 
4765cf1669fSMatthias Ringwald static void send_gatt_included_service_request(gatt_client_t *gatt_client){
4776e7b444cSMatthias Ringwald     att_read_by_type_or_group_request_for_uuid16(gatt_client, ATT_READ_BY_TYPE_REQUEST,
4786e7b444cSMatthias Ringwald                                                  GATT_INCLUDE_SERVICE_UUID, gatt_client->start_group_handle,
4796e7b444cSMatthias Ringwald                                                  gatt_client->end_group_handle);
4803deb3ec6SMatthias Ringwald }
4813deb3ec6SMatthias Ringwald 
4825cf1669fSMatthias Ringwald static void send_gatt_characteristic_request(gatt_client_t *gatt_client){
4836e7b444cSMatthias Ringwald     att_read_by_type_or_group_request_for_uuid16(gatt_client, ATT_READ_BY_TYPE_REQUEST,
4846e7b444cSMatthias Ringwald                                                  GATT_CHARACTERISTICS_UUID, gatt_client->start_group_handle,
4856e7b444cSMatthias Ringwald                                                  gatt_client->end_group_handle);
4863deb3ec6SMatthias Ringwald }
4873deb3ec6SMatthias Ringwald 
4885cf1669fSMatthias Ringwald static void send_gatt_characteristic_descriptor_request(gatt_client_t *gatt_client){
4896e7b444cSMatthias Ringwald     att_find_information_request(gatt_client, ATT_FIND_INFORMATION_REQUEST, gatt_client->start_group_handle,
4906e7b444cSMatthias Ringwald                                  gatt_client->end_group_handle);
4913deb3ec6SMatthias Ringwald }
4923deb3ec6SMatthias Ringwald 
4935cf1669fSMatthias Ringwald static void send_gatt_read_characteristic_value_request(gatt_client_t *gatt_client){
4946e7b444cSMatthias Ringwald     att_read_request(gatt_client, ATT_READ_REQUEST, gatt_client->attribute_handle);
4953deb3ec6SMatthias Ringwald }
4963deb3ec6SMatthias Ringwald 
4975cf1669fSMatthias Ringwald static void send_gatt_read_by_type_request(gatt_client_t * gatt_client){
4985cf1669fSMatthias Ringwald     if (gatt_client->uuid16){
4996e7b444cSMatthias Ringwald         att_read_by_type_or_group_request_for_uuid16(gatt_client, ATT_READ_BY_TYPE_REQUEST,
5006e7b444cSMatthias Ringwald                                                      gatt_client->uuid16, gatt_client->start_group_handle,
5016e7b444cSMatthias Ringwald                                                      gatt_client->end_group_handle);
5023deb3ec6SMatthias Ringwald     } else {
5036e7b444cSMatthias Ringwald         att_read_by_type_or_group_request_for_uuid128(gatt_client, ATT_READ_BY_TYPE_REQUEST,
5046e7b444cSMatthias Ringwald                                                       gatt_client->uuid128, gatt_client->start_group_handle,
5056e7b444cSMatthias Ringwald                                                       gatt_client->end_group_handle);
5063deb3ec6SMatthias Ringwald     }
5073deb3ec6SMatthias Ringwald }
5083deb3ec6SMatthias Ringwald 
5095cf1669fSMatthias Ringwald static void send_gatt_read_blob_request(gatt_client_t *gatt_client){
51030952227SMilanka Ringwald     if (gatt_client->attribute_offset == 0){
5116e7b444cSMatthias Ringwald         att_read_request(gatt_client, ATT_READ_REQUEST, gatt_client->attribute_handle);
51230952227SMilanka Ringwald     } else {
5136e7b444cSMatthias Ringwald         att_read_blob_request(gatt_client, ATT_READ_BLOB_REQUEST, gatt_client->attribute_handle,
5146e7b444cSMatthias Ringwald                               gatt_client->attribute_offset);
5153deb3ec6SMatthias Ringwald     }
51630952227SMilanka Ringwald }
5173deb3ec6SMatthias Ringwald 
5185cf1669fSMatthias Ringwald static void send_gatt_read_multiple_request(gatt_client_t * gatt_client){
5196e7b444cSMatthias Ringwald     att_read_multiple_request(gatt_client, gatt_client->read_multiple_handle_count, gatt_client->read_multiple_handles);
5203deb3ec6SMatthias Ringwald }
5213deb3ec6SMatthias Ringwald 
5225cf1669fSMatthias Ringwald static void send_gatt_write_attribute_value_request(gatt_client_t * gatt_client){
5236e7b444cSMatthias Ringwald     att_write_request(gatt_client, ATT_WRITE_REQUEST, gatt_client->attribute_handle, gatt_client->attribute_length,
5246e7b444cSMatthias Ringwald                       gatt_client->attribute_value);
5253deb3ec6SMatthias Ringwald }
5263deb3ec6SMatthias Ringwald 
5275cf1669fSMatthias Ringwald static void send_gatt_write_client_characteristic_configuration_request(gatt_client_t * gatt_client){
5286e7b444cSMatthias Ringwald     att_write_request(gatt_client, ATT_WRITE_REQUEST, gatt_client->client_characteristic_configuration_handle, 2,
5296e7b444cSMatthias Ringwald                       gatt_client->client_characteristic_configuration_value);
5303deb3ec6SMatthias Ringwald }
5313deb3ec6SMatthias Ringwald 
5325cf1669fSMatthias Ringwald static void send_gatt_prepare_write_request(gatt_client_t * gatt_client){
5336e7b444cSMatthias Ringwald     att_prepare_write_request(gatt_client, ATT_PREPARE_WRITE_REQUEST, gatt_client->attribute_handle,
5346e7b444cSMatthias Ringwald                               gatt_client->attribute_offset, write_blob_length(gatt_client),
5356e7b444cSMatthias Ringwald                               gatt_client->attribute_value);
5363deb3ec6SMatthias Ringwald }
5373deb3ec6SMatthias Ringwald 
5385cf1669fSMatthias Ringwald static void send_gatt_execute_write_request(gatt_client_t * gatt_client){
5396e7b444cSMatthias Ringwald     att_execute_write_request(gatt_client, ATT_EXECUTE_WRITE_REQUEST, 1);
5403deb3ec6SMatthias Ringwald }
5413deb3ec6SMatthias Ringwald 
5425cf1669fSMatthias Ringwald static void send_gatt_cancel_prepared_write_request(gatt_client_t * gatt_client){
5436e7b444cSMatthias Ringwald     att_execute_write_request(gatt_client, ATT_EXECUTE_WRITE_REQUEST, 0);
5443deb3ec6SMatthias Ringwald }
5453deb3ec6SMatthias Ringwald 
546abdc9fb5SMatthias Ringwald #ifndef ENABLE_GATT_FIND_INFORMATION_FOR_CCC_DISCOVERY
5475cf1669fSMatthias Ringwald static void send_gatt_read_client_characteristic_configuration_request(gatt_client_t * gatt_client){
5486e7b444cSMatthias Ringwald     att_read_by_type_or_group_request_for_uuid16(gatt_client, ATT_READ_BY_TYPE_REQUEST,
5496e7b444cSMatthias Ringwald                                                  GATT_CLIENT_CHARACTERISTICS_CONFIGURATION,
5506e7b444cSMatthias Ringwald                                                  gatt_client->start_group_handle, gatt_client->end_group_handle);
5513deb3ec6SMatthias Ringwald }
552abdc9fb5SMatthias Ringwald #endif
5533deb3ec6SMatthias Ringwald 
5545cf1669fSMatthias Ringwald static void send_gatt_read_characteristic_descriptor_request(gatt_client_t * gatt_client){
5556e7b444cSMatthias Ringwald     att_read_request(gatt_client, ATT_READ_REQUEST, gatt_client->attribute_handle);
5563deb3ec6SMatthias Ringwald }
5573deb3ec6SMatthias Ringwald 
5587a766ebfSMatthias Ringwald #ifdef ENABLE_LE_SIGNED_WRITE
5595cf1669fSMatthias Ringwald static void send_gatt_signed_write_request(gatt_client_t * gatt_client, uint32_t sign_counter){
5606e7b444cSMatthias Ringwald     att_signed_write_request(gatt_client, ATT_SIGNED_WRITE_COMMAND, gatt_client->attribute_handle,
5616e7b444cSMatthias Ringwald                              gatt_client->attribute_length, gatt_client->attribute_value, sign_counter,
5626e7b444cSMatthias Ringwald                              gatt_client->cmac);
5633deb3ec6SMatthias Ringwald }
5647a766ebfSMatthias Ringwald #endif
5653deb3ec6SMatthias Ringwald 
5663deb3ec6SMatthias Ringwald static uint16_t get_last_result_handle_from_service_list(uint8_t * packet, uint16_t size){
56739ac9711SMatthias Ringwald     if (size < 2) return 0xffff;
5683deb3ec6SMatthias Ringwald     uint8_t attr_length = packet[1];
56939ac9711SMatthias Ringwald     if ((2 + attr_length) > size) return 0xffff;
5704ea43905SMatthias Ringwald     return little_endian_read_16(packet, size - attr_length + 2u);
5713deb3ec6SMatthias Ringwald }
5723deb3ec6SMatthias Ringwald 
5733deb3ec6SMatthias Ringwald static uint16_t get_last_result_handle_from_characteristics_list(uint8_t * packet, uint16_t size){
57439ac9711SMatthias Ringwald     if (size < 2) return 0xffff;
5753deb3ec6SMatthias Ringwald     uint8_t attr_length = packet[1];
57639ac9711SMatthias Ringwald     if ((2 + attr_length) > size) return 0xffff;
5774ea43905SMatthias Ringwald     return little_endian_read_16(packet, size - attr_length + 3u);
5783deb3ec6SMatthias Ringwald }
5793deb3ec6SMatthias Ringwald 
5803deb3ec6SMatthias Ringwald static uint16_t get_last_result_handle_from_included_services_list(uint8_t * packet, uint16_t size){
58139ac9711SMatthias Ringwald     if (size < 2) return 0xffff;
5823deb3ec6SMatthias Ringwald     uint8_t attr_length = packet[1];
58339ac9711SMatthias Ringwald     if ((2 + attr_length) > size) return 0xffff;
584f8fbdce0SMatthias Ringwald     return little_endian_read_16(packet, size - attr_length);
5853deb3ec6SMatthias Ringwald }
5863deb3ec6SMatthias Ringwald 
58753e9c18fSMatthias Ringwald static void gatt_client_notify_can_send_query(gatt_client_t * gatt_client){
58853e9c18fSMatthias Ringwald     while (gatt_client->gatt_client_state == P_READY){
58953e9c18fSMatthias Ringwald         btstack_context_callback_registration_t * callback = (btstack_context_callback_registration_t *) btstack_linked_list_pop(&gatt_client->query_requests);
59009834412SMatthias Ringwald         if (callback == NULL) {
59109834412SMatthias Ringwald             return;
59253e9c18fSMatthias Ringwald         }
59309834412SMatthias Ringwald         (*callback->callback)(callback->context);
59453e9c18fSMatthias Ringwald     }
59553e9c18fSMatthias Ringwald }
59653e9c18fSMatthias Ringwald 
5975cf1669fSMatthias Ringwald static void gatt_client_handle_transaction_complete(gatt_client_t * gatt_client){
5985cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_READY;
5995cf1669fSMatthias Ringwald     gatt_client_timeout_stop(gatt_client);
60053e9c18fSMatthias Ringwald     gatt_client_notify_can_send_query(gatt_client);
6013deb3ec6SMatthias Ringwald }
6023deb3ec6SMatthias Ringwald 
6039c662c9bSMatthias Ringwald static void emit_event_new(btstack_packet_handler_t callback, uint8_t * packet, uint16_t size){
6049c662c9bSMatthias Ringwald     if (!callback) return;
60592da54c4SMatthias Ringwald     hci_dump_packet(HCI_EVENT_PACKET, 1, packet, size);
6069c662c9bSMatthias Ringwald     (*callback)(HCI_EVENT_PACKET, 0, packet, size);
6073deb3ec6SMatthias Ringwald }
6083deb3ec6SMatthias Ringwald 
60948cdff9cSMilanka Ringwald void gatt_client_listen_for_characteristic_value_updates(gatt_client_notification_t * notification, btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){
61048cdff9cSMilanka Ringwald     notification->callback = callback;
6119c662c9bSMatthias Ringwald     notification->con_handle = con_handle;
612b3f03c84SMatthias Ringwald     if (characteristic == NULL){
613b3f03c84SMatthias Ringwald         notification->attribute_handle = GATT_CLIENT_ANY_VALUE_HANDLE;
614b3f03c84SMatthias Ringwald     } else {
6159c662c9bSMatthias Ringwald         notification->attribute_handle = characteristic->value_handle;
616b3f03c84SMatthias Ringwald     }
6179c662c9bSMatthias Ringwald     btstack_linked_list_add(&gatt_client_value_listeners, (btstack_linked_item_t*) notification);
6189c662c9bSMatthias Ringwald }
6199c662c9bSMatthias Ringwald 
6201f734b5fSMatthias Ringwald void gatt_client_stop_listening_for_characteristic_value_updates(gatt_client_notification_t * notification){
6211f734b5fSMatthias Ringwald     btstack_linked_list_remove(&gatt_client_value_listeners, (btstack_linked_item_t*) notification);
6221f734b5fSMatthias Ringwald }
6231f734b5fSMatthias Ringwald 
624711e6c80SMatthias Ringwald static void emit_event_to_registered_listeners(hci_con_handle_t con_handle, uint16_t attribute_handle, uint8_t * packet, uint16_t size){
625665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
6269c662c9bSMatthias Ringwald     btstack_linked_list_iterator_init(&it, &gatt_client_value_listeners);
627665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
62886c38559SMatthias Ringwald         gatt_client_notification_t * notification = (gatt_client_notification_t*) btstack_linked_list_iterator_next(&it);
629b3f03c84SMatthias Ringwald         if ((notification->con_handle       != GATT_CLIENT_ANY_CONNECTION)   && (notification->con_handle       != con_handle)) continue;
630b3f03c84SMatthias Ringwald         if ((notification->attribute_handle != GATT_CLIENT_ANY_VALUE_HANDLE) && (notification->attribute_handle != attribute_handle)) continue;
63186c38559SMatthias Ringwald         (*notification->callback)(HCI_EVENT_PACKET, 0, packet, size);
6323deb3ec6SMatthias Ringwald     }
6333deb3ec6SMatthias Ringwald }
6343deb3ec6SMatthias Ringwald 
6355cf1669fSMatthias Ringwald static void emit_gatt_complete_event(gatt_client_t * gatt_client, uint8_t att_status){
6363deb3ec6SMatthias Ringwald     // @format H1
6373deb3ec6SMatthias Ringwald     uint8_t packet[5];
6385611a760SMatthias Ringwald     packet[0] = GATT_EVENT_QUERY_COMPLETE;
6393deb3ec6SMatthias Ringwald     packet[1] = 3;
6405cf1669fSMatthias Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
6417d2258b3SMilanka Ringwald     packet[4] = att_status;
6425cf1669fSMatthias Ringwald     emit_event_new(gatt_client->callback, packet, sizeof(packet));
6433deb3ec6SMatthias Ringwald }
6443deb3ec6SMatthias Ringwald 
645045d700dSDavid Lechner static void emit_gatt_service_query_result_event(gatt_client_t * gatt_client, uint16_t start_group_handle, uint16_t end_group_handle, const uint8_t * uuid128){
6463deb3ec6SMatthias Ringwald     // @format HX
6473deb3ec6SMatthias Ringwald     uint8_t packet[24];
6485611a760SMatthias Ringwald     packet[0] = GATT_EVENT_SERVICE_QUERY_RESULT;
6494ea43905SMatthias Ringwald     packet[1] = sizeof(packet) - 2u;
6505cf1669fSMatthias Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
6513deb3ec6SMatthias Ringwald     ///
652f8fbdce0SMatthias Ringwald     little_endian_store_16(packet, 4, start_group_handle);
653f8fbdce0SMatthias Ringwald     little_endian_store_16(packet, 6, end_group_handle);
6549c80e4ccSMatthias Ringwald     reverse_128(uuid128, &packet[8]);
6555cf1669fSMatthias Ringwald     emit_event_new(gatt_client->callback, packet, sizeof(packet));
6563deb3ec6SMatthias Ringwald }
6573deb3ec6SMatthias Ringwald 
658045d700dSDavid Lechner static void emit_gatt_included_service_query_result_event(gatt_client_t * gatt_client, uint16_t include_handle, uint16_t start_group_handle, uint16_t end_group_handle, const uint8_t * uuid128){
6593deb3ec6SMatthias Ringwald     // @format HX
6603deb3ec6SMatthias Ringwald     uint8_t packet[26];
6615611a760SMatthias Ringwald     packet[0] = GATT_EVENT_INCLUDED_SERVICE_QUERY_RESULT;
6624ea43905SMatthias Ringwald     packet[1] = sizeof(packet) - 2u;
6635cf1669fSMatthias Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
6643deb3ec6SMatthias Ringwald     ///
665f8fbdce0SMatthias Ringwald     little_endian_store_16(packet, 4, include_handle);
6663deb3ec6SMatthias Ringwald     //
667f8fbdce0SMatthias Ringwald     little_endian_store_16(packet, 6, start_group_handle);
668f8fbdce0SMatthias Ringwald     little_endian_store_16(packet, 8, end_group_handle);
6699c80e4ccSMatthias Ringwald     reverse_128(uuid128, &packet[10]);
6705cf1669fSMatthias Ringwald     emit_event_new(gatt_client->callback, packet, sizeof(packet));
6713deb3ec6SMatthias Ringwald }
6723deb3ec6SMatthias Ringwald 
6735cf1669fSMatthias Ringwald static void emit_gatt_characteristic_query_result_event(gatt_client_t * gatt_client, uint16_t start_handle, uint16_t value_handle, uint16_t end_handle,
674045d700dSDavid Lechner                                                         uint16_t properties, const uint8_t * uuid128){
6753deb3ec6SMatthias Ringwald     // @format HY
6763deb3ec6SMatthias Ringwald     uint8_t packet[28];
6775611a760SMatthias Ringwald     packet[0] = GATT_EVENT_CHARACTERISTIC_QUERY_RESULT;
6784ea43905SMatthias Ringwald     packet[1] = sizeof(packet) - 2u;
6795cf1669fSMatthias Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
6803deb3ec6SMatthias Ringwald     ///
681f8fbdce0SMatthias Ringwald     little_endian_store_16(packet, 4,  start_handle);
682f8fbdce0SMatthias Ringwald     little_endian_store_16(packet, 6,  value_handle);
683f8fbdce0SMatthias Ringwald     little_endian_store_16(packet, 8,  end_handle);
684f8fbdce0SMatthias Ringwald     little_endian_store_16(packet, 10, properties);
6859c80e4ccSMatthias Ringwald     reverse_128(uuid128, &packet[12]);
6865cf1669fSMatthias Ringwald     emit_event_new(gatt_client->callback, packet, sizeof(packet));
6873deb3ec6SMatthias Ringwald }
6883deb3ec6SMatthias Ringwald 
6893deb3ec6SMatthias Ringwald static void emit_gatt_all_characteristic_descriptors_result_event(
690045d700dSDavid Lechner         gatt_client_t * gatt_client, uint16_t descriptor_handle, const uint8_t * uuid128){
6913deb3ec6SMatthias Ringwald     // @format HZ
6923deb3ec6SMatthias Ringwald     uint8_t packet[22];
6935611a760SMatthias Ringwald     packet[0] = GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT;
6944ea43905SMatthias Ringwald     packet[1] = sizeof(packet) - 2u;
6955cf1669fSMatthias Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
6963deb3ec6SMatthias Ringwald     ///
697f8fbdce0SMatthias Ringwald     little_endian_store_16(packet, 4,  descriptor_handle);
6989c80e4ccSMatthias Ringwald     reverse_128(uuid128, &packet[6]);
6995cf1669fSMatthias Ringwald     emit_event_new(gatt_client->callback, packet, sizeof(packet));
7003deb3ec6SMatthias Ringwald }
7013deb3ec6SMatthias Ringwald 
7025cf1669fSMatthias Ringwald static void emit_gatt_mtu_exchanged_result_event(gatt_client_t * gatt_client, uint16_t new_mtu){
7038f37572aSJakob Krantz     // @format H2
7048f37572aSJakob Krantz     uint8_t packet[6];
7058f37572aSJakob Krantz     packet[0] = GATT_EVENT_MTU;
7064ea43905SMatthias Ringwald     packet[1] = sizeof(packet) - 2u;
7075cf1669fSMatthias Ringwald     little_endian_store_16(packet, 2, gatt_client->con_handle);
7088f37572aSJakob Krantz     little_endian_store_16(packet, 4, new_mtu);
7095cf1669fSMatthias Ringwald     att_dispatch_client_mtu_exchanged(gatt_client->con_handle, new_mtu);
7105cf1669fSMatthias Ringwald     emit_event_new(gatt_client->callback, packet, sizeof(packet));
7118f37572aSJakob Krantz }
7128f37572aSJakob Krantz ///
7135cf1669fSMatthias Ringwald static void report_gatt_services(gatt_client_t * gatt_client, uint8_t * packet, uint16_t size){
71439ac9711SMatthias Ringwald     if (size < 2) return;
7153deb3ec6SMatthias Ringwald     uint8_t attr_length = packet[1];
7164ea43905SMatthias Ringwald     uint8_t uuid_length = attr_length - 4u;
7173deb3ec6SMatthias Ringwald 
7183deb3ec6SMatthias Ringwald     int i;
71939ac9711SMatthias Ringwald     for (i = 2; (i+attr_length) <= size; i += attr_length){
720f8fbdce0SMatthias Ringwald         uint16_t start_group_handle = little_endian_read_16(packet,i);
721f8fbdce0SMatthias Ringwald         uint16_t end_group_handle   = little_endian_read_16(packet,i+2);
7223deb3ec6SMatthias Ringwald         uint8_t  uuid128[16];
7233deb3ec6SMatthias Ringwald         uint16_t uuid16 = 0;
7243deb3ec6SMatthias Ringwald 
7254ea43905SMatthias Ringwald         if (uuid_length == 2u){
726f8fbdce0SMatthias Ringwald             uuid16 = little_endian_read_16(packet, i+4);
727e1a125dfSMatthias Ringwald             uuid_add_bluetooth_prefix((uint8_t*) &uuid128, uuid16);
72839ac9711SMatthias Ringwald         } else if (uuid_length == 16u) {
7299c80e4ccSMatthias Ringwald             reverse_128(&packet[i+4], uuid128);
73039ac9711SMatthias Ringwald         } else {
73139ac9711SMatthias Ringwald             return;
7323deb3ec6SMatthias Ringwald         }
7335cf1669fSMatthias Ringwald         emit_gatt_service_query_result_event(gatt_client, start_group_handle, end_group_handle, uuid128);
7343deb3ec6SMatthias Ringwald     }
7353deb3ec6SMatthias Ringwald }
7363deb3ec6SMatthias Ringwald 
7373deb3ec6SMatthias Ringwald // helper
7385cf1669fSMatthias Ringwald static void characteristic_start_found(gatt_client_t * gatt_client, uint16_t start_handle, uint8_t properties, uint16_t value_handle, uint8_t * uuid, uint16_t uuid_length){
7393deb3ec6SMatthias Ringwald     uint8_t uuid128[16];
7403deb3ec6SMatthias Ringwald     uint16_t uuid16 = 0;
7414ea43905SMatthias Ringwald     if (uuid_length == 2u){
742f8fbdce0SMatthias Ringwald         uuid16 = little_endian_read_16(uuid, 0);
743e1a125dfSMatthias Ringwald         uuid_add_bluetooth_prefix((uint8_t*) uuid128, uuid16);
7444ea43905SMatthias Ringwald     } else if (uuid_length == 16u){
7459c80e4ccSMatthias Ringwald         reverse_128(uuid, uuid128);
746d73c9dbeSMilanka Ringwald     } else {
747d73c9dbeSMilanka Ringwald         return;
7483deb3ec6SMatthias Ringwald     }
7493deb3ec6SMatthias Ringwald 
7505cf1669fSMatthias Ringwald     if (gatt_client->filter_with_uuid && (memcmp(gatt_client->uuid128, uuid128, 16) != 0)) return;
7513deb3ec6SMatthias Ringwald 
7525cf1669fSMatthias Ringwald     gatt_client->characteristic_properties = properties;
7535cf1669fSMatthias Ringwald     gatt_client->characteristic_start_handle = start_handle;
7545cf1669fSMatthias Ringwald     gatt_client->attribute_handle = value_handle;
7553deb3ec6SMatthias Ringwald 
7565cf1669fSMatthias Ringwald     if (gatt_client->filter_with_uuid) return;
7573deb3ec6SMatthias Ringwald 
7585cf1669fSMatthias Ringwald     gatt_client->uuid16 = uuid16;
7595cf1669fSMatthias Ringwald     (void)memcpy(gatt_client->uuid128, uuid128, 16);
7603deb3ec6SMatthias Ringwald }
7613deb3ec6SMatthias Ringwald 
7625cf1669fSMatthias Ringwald static void characteristic_end_found(gatt_client_t * gatt_client, uint16_t end_handle){
7633deb3ec6SMatthias Ringwald     // TODO: stop searching if filter and uuid found
7643deb3ec6SMatthias Ringwald 
7655cf1669fSMatthias Ringwald     if (!gatt_client->characteristic_start_handle) return;
7663deb3ec6SMatthias Ringwald 
7675cf1669fSMatthias Ringwald     emit_gatt_characteristic_query_result_event(gatt_client, gatt_client->characteristic_start_handle, gatt_client->attribute_handle,
7685cf1669fSMatthias Ringwald                                                 end_handle, gatt_client->characteristic_properties, gatt_client->uuid128);
7693deb3ec6SMatthias Ringwald 
7705cf1669fSMatthias Ringwald     gatt_client->characteristic_start_handle = 0;
7713deb3ec6SMatthias Ringwald }
7723deb3ec6SMatthias Ringwald 
7735cf1669fSMatthias Ringwald static void report_gatt_characteristics(gatt_client_t * gatt_client, uint8_t * packet, uint16_t size){
7744ea43905SMatthias Ringwald     if (size < 2u) return;
7753deb3ec6SMatthias Ringwald     uint8_t attr_length = packet[1];
7764ea43905SMatthias Ringwald     if ((attr_length != 7u) && (attr_length != 21u)) return;
7774ea43905SMatthias Ringwald     uint8_t uuid_length = attr_length - 5u;
7783deb3ec6SMatthias Ringwald     int i;
7794ea43905SMatthias Ringwald     for (i = 2u; (i + attr_length) <= size; i += attr_length){
780f8fbdce0SMatthias Ringwald         uint16_t start_handle = little_endian_read_16(packet, i);
7813deb3ec6SMatthias Ringwald         uint8_t  properties = packet[i+2];
782f8fbdce0SMatthias Ringwald         uint16_t value_handle = little_endian_read_16(packet, i+3);
7835cf1669fSMatthias Ringwald         characteristic_end_found(gatt_client, start_handle - 1u);
7845cf1669fSMatthias Ringwald         characteristic_start_found(gatt_client, start_handle, properties, value_handle, &packet[i + 5], uuid_length);
7853deb3ec6SMatthias Ringwald     }
7863deb3ec6SMatthias Ringwald }
7873deb3ec6SMatthias Ringwald 
7885cf1669fSMatthias Ringwald static void report_gatt_included_service_uuid16(gatt_client_t * gatt_client, uint16_t include_handle, uint16_t uuid16){
7893deb3ec6SMatthias Ringwald     uint8_t normalized_uuid128[16];
790e1a125dfSMatthias Ringwald     uuid_add_bluetooth_prefix(normalized_uuid128, uuid16);
7915cf1669fSMatthias Ringwald     emit_gatt_included_service_query_result_event(gatt_client, include_handle, gatt_client->query_start_handle,
7925cf1669fSMatthias Ringwald                                                   gatt_client->query_end_handle, normalized_uuid128);
7933deb3ec6SMatthias Ringwald }
7943deb3ec6SMatthias Ringwald 
795045d700dSDavid Lechner static void report_gatt_included_service_uuid128(gatt_client_t * gatt_client, uint16_t include_handle, const uint8_t * uuid128){
7965cf1669fSMatthias Ringwald     emit_gatt_included_service_query_result_event(gatt_client, include_handle, gatt_client->query_start_handle,
7975cf1669fSMatthias Ringwald                                                   gatt_client->query_end_handle, uuid128);
7983deb3ec6SMatthias Ringwald }
7993deb3ec6SMatthias Ringwald 
8006b65794dSMilanka Ringwald // @return packet pointer
8013deb3ec6SMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite HCI + L2CAP packet headers
8023deb3ec6SMatthias Ringwald static const int characteristic_value_event_header_size = 8;
803711e6c80SMatthias Ringwald static uint8_t * setup_characteristic_value_packet(uint8_t type, hci_con_handle_t con_handle, uint16_t attribute_handle, uint8_t * value, uint16_t length){
804a6121b51SMilanka Ringwald #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
805ae1ee62dSMilanka Ringwald     // copy value into test packet for testing
806ae1ee62dSMilanka Ringwald     static uint8_t packet[1000];
807ae1ee62dSMilanka Ringwald     memcpy(&packet[8], value, length);
808ae1ee62dSMilanka Ringwald #else
8093deb3ec6SMatthias Ringwald     // before the value inside the ATT PDU
8103deb3ec6SMatthias Ringwald     uint8_t * packet = value - characteristic_value_event_header_size;
811ae1ee62dSMilanka Ringwald #endif
8123deb3ec6SMatthias Ringwald     packet[0] = type;
8133deb3ec6SMatthias Ringwald     packet[1] = characteristic_value_event_header_size - 2 + length;
814f8fbdce0SMatthias Ringwald     little_endian_store_16(packet, 2, con_handle);
815f8fbdce0SMatthias Ringwald     little_endian_store_16(packet, 4, attribute_handle);
816f8fbdce0SMatthias Ringwald     little_endian_store_16(packet, 6, length);
8173deb3ec6SMatthias Ringwald     return packet;
8183deb3ec6SMatthias Ringwald }
8193deb3ec6SMatthias Ringwald 
8206b65794dSMilanka Ringwald // @return packet pointer
8213deb3ec6SMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes
8223deb3ec6SMatthias Ringwald static const int long_characteristic_value_event_header_size = 10;
823711e6c80SMatthias Ringwald static uint8_t * setup_long_characteristic_value_packet(uint8_t type, hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * value, uint16_t length){
824a6121b51SMilanka Ringwald #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
825a6121b51SMilanka Ringwald     // avoid using pre ATT headers.
826a6121b51SMilanka Ringwald     return NULL;
827a6121b51SMilanka Ringwald #endif
8283deb3ec6SMatthias Ringwald #if defined(HCI_INCOMING_PRE_BUFFER_SIZE) && (HCI_INCOMING_PRE_BUFFER_SIZE >= 10 - 8) // L2CAP Header (4) - ACL Header (4)
8293deb3ec6SMatthias Ringwald     // before the value inside the ATT PDU
8303deb3ec6SMatthias Ringwald     uint8_t * packet = value - long_characteristic_value_event_header_size;
8313deb3ec6SMatthias Ringwald     packet[0] = type;
8323deb3ec6SMatthias Ringwald     packet[1] = long_characteristic_value_event_header_size - 2 + length;
833f8fbdce0SMatthias Ringwald     little_endian_store_16(packet, 2, con_handle);
834f8fbdce0SMatthias Ringwald     little_endian_store_16(packet, 4, attribute_handle);
835f8fbdce0SMatthias Ringwald     little_endian_store_16(packet, 6, offset);
836f8fbdce0SMatthias Ringwald     little_endian_store_16(packet, 8, length);
8373deb3ec6SMatthias Ringwald     return packet;
8383deb3ec6SMatthias Ringwald #else
8393deb3ec6SMatthias Ringwald     log_error("HCI_INCOMING_PRE_BUFFER_SIZE >= 2 required for long characteristic reads");
8403deb3ec6SMatthias Ringwald     return NULL;
8413deb3ec6SMatthias Ringwald #endif
8423deb3ec6SMatthias Ringwald }
8433deb3ec6SMatthias Ringwald 
844c90e270fSMatthias Ringwald // test if notification/indication should be delivered to application (BLESA)
8450fde3c5eSMatthias Ringwald static bool gatt_client_accept_server_message(gatt_client_t *gatt_client) {
846b15d5ceaSMatthias Ringwald #ifdef ENABLE_LE_PROACTIVE_AUTHENTICATION
847b15d5ceaSMatthias Ringwald 	// ignore messages until re-encryption is complete
8480fde3c5eSMatthias Ringwald     if (gap_reconnect_security_setup_active(gatt_client->con_handle)) return false;
849c90e270fSMatthias Ringwald 
850c90e270fSMatthias Ringwald 	// after that ignore if bonded but not encrypted
8510fde3c5eSMatthias Ringwald 	return !gap_bonded(gatt_client->con_handle) || (gap_encryption_key_size(gatt_client->con_handle) > 0);
852c90e270fSMatthias Ringwald #else
8530fde3c5eSMatthias Ringwald     UNUSED(gatt_client);
854c90e270fSMatthias Ringwald 	return true;
855c90e270fSMatthias Ringwald #endif
856c90e270fSMatthias Ringwald }
857c90e270fSMatthias Ringwald 
8583deb3ec6SMatthias Ringwald 
8593deb3ec6SMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes
8600fde3c5eSMatthias Ringwald static void report_gatt_notification(gatt_client_t *gatt_client, uint16_t value_handle, uint8_t *value, int length) {
8610fde3c5eSMatthias Ringwald 	if (!gatt_client_accept_server_message(gatt_client)) return;
8620fde3c5eSMatthias Ringwald     uint8_t * packet = setup_characteristic_value_packet(GATT_EVENT_NOTIFICATION, gatt_client->con_handle, value_handle, value, length);
8630fde3c5eSMatthias Ringwald     emit_event_to_registered_listeners(gatt_client->con_handle, value_handle, packet, characteristic_value_event_header_size + length);
8643deb3ec6SMatthias Ringwald }
8653deb3ec6SMatthias Ringwald 
8663deb3ec6SMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes
8670fde3c5eSMatthias Ringwald static void report_gatt_indication(gatt_client_t *gatt_client, uint16_t value_handle, uint8_t *value, int length) {
8680fde3c5eSMatthias Ringwald 	if (!gatt_client_accept_server_message(gatt_client)) return;
8690fde3c5eSMatthias Ringwald     uint8_t * packet = setup_characteristic_value_packet(GATT_EVENT_INDICATION, gatt_client->con_handle, value_handle, value, length);
8700fde3c5eSMatthias Ringwald     emit_event_to_registered_listeners(gatt_client->con_handle, value_handle, packet, characteristic_value_event_header_size + length);
8713deb3ec6SMatthias Ringwald }
8723deb3ec6SMatthias Ringwald 
8733deb3ec6SMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes
8745cf1669fSMatthias Ringwald static void report_gatt_characteristic_value(gatt_client_t * gatt_client, uint16_t attribute_handle, uint8_t * value, uint16_t length){
8755cf1669fSMatthias Ringwald     uint8_t * packet = setup_characteristic_value_packet(GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT, gatt_client->con_handle, attribute_handle, value, length);
8765cf1669fSMatthias Ringwald     emit_event_new(gatt_client->callback, packet, characteristic_value_event_header_size + length);
8773deb3ec6SMatthias Ringwald }
8783deb3ec6SMatthias Ringwald 
8793deb3ec6SMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes
8805cf1669fSMatthias Ringwald static void report_gatt_long_characteristic_value_blob(gatt_client_t * gatt_client, uint16_t attribute_handle, uint8_t * blob, uint16_t blob_length, int value_offset){
8815cf1669fSMatthias Ringwald     uint8_t * packet = setup_long_characteristic_value_packet(GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT, gatt_client->con_handle, attribute_handle, value_offset, blob, blob_length);
8823deb3ec6SMatthias Ringwald     if (!packet) return;
8835cf1669fSMatthias Ringwald     emit_event_new(gatt_client->callback, packet, blob_length + long_characteristic_value_event_header_size);
8843deb3ec6SMatthias Ringwald }
8853deb3ec6SMatthias Ringwald 
8865cf1669fSMatthias Ringwald static void report_gatt_characteristic_descriptor(gatt_client_t * gatt_client, uint16_t descriptor_handle, uint8_t *value, uint16_t value_length, uint16_t value_offset){
8879ec2630cSMatthias Ringwald     UNUSED(value_offset);
8885cf1669fSMatthias Ringwald     uint8_t * packet = setup_characteristic_value_packet(GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT, gatt_client->con_handle, descriptor_handle, value, value_length);
8895cf1669fSMatthias Ringwald     emit_event_new(gatt_client->callback, packet, value_length + 8u);
8903deb3ec6SMatthias Ringwald }
8913deb3ec6SMatthias Ringwald 
8925cf1669fSMatthias Ringwald static void report_gatt_long_characteristic_descriptor(gatt_client_t * gatt_client, uint16_t descriptor_handle, uint8_t *blob, uint16_t blob_length, uint16_t value_offset){
8935cf1669fSMatthias Ringwald     uint8_t * packet = setup_long_characteristic_value_packet(GATT_EVENT_LONG_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT, gatt_client->con_handle, descriptor_handle, value_offset, blob, blob_length);
8943deb3ec6SMatthias Ringwald     if (!packet) return;
8955cf1669fSMatthias Ringwald     emit_event_new(gatt_client->callback, packet, blob_length + long_characteristic_value_event_header_size);
8963deb3ec6SMatthias Ringwald }
8973deb3ec6SMatthias Ringwald 
8985cf1669fSMatthias Ringwald static void report_gatt_all_characteristic_descriptors(gatt_client_t * gatt_client, uint8_t * packet, uint16_t size, uint16_t pair_size){
8993deb3ec6SMatthias Ringwald     int i;
9004ea43905SMatthias Ringwald     for (i = 0u; (i + pair_size) <= size; i += pair_size){
901f8fbdce0SMatthias Ringwald         uint16_t descriptor_handle = little_endian_read_16(packet,i);
9023deb3ec6SMatthias Ringwald         uint8_t uuid128[16];
9033deb3ec6SMatthias Ringwald         uint16_t uuid16 = 0;
9044ea43905SMatthias Ringwald         if (pair_size == 4u){
905f8fbdce0SMatthias Ringwald             uuid16 = little_endian_read_16(packet,i+2);
906e1a125dfSMatthias Ringwald             uuid_add_bluetooth_prefix(uuid128, uuid16);
9073deb3ec6SMatthias Ringwald         } else {
9089c80e4ccSMatthias Ringwald             reverse_128(&packet[i+2], uuid128);
9093deb3ec6SMatthias Ringwald         }
9105cf1669fSMatthias Ringwald         emit_gatt_all_characteristic_descriptors_result_event(gatt_client, descriptor_handle, uuid128);
9113deb3ec6SMatthias Ringwald     }
9123deb3ec6SMatthias Ringwald 
9133deb3ec6SMatthias Ringwald }
9143deb3ec6SMatthias Ringwald 
9155cf1669fSMatthias Ringwald static int is_query_done(gatt_client_t * gatt_client, uint16_t last_result_handle){
9165cf1669fSMatthias Ringwald     return last_result_handle >= gatt_client->end_group_handle;
9173deb3ec6SMatthias Ringwald }
9183deb3ec6SMatthias Ringwald 
9195cf1669fSMatthias Ringwald static void trigger_next_query(gatt_client_t * gatt_client, uint16_t last_result_handle, gatt_client_state_t next_query_state){
9205cf1669fSMatthias Ringwald     if (is_query_done(gatt_client, last_result_handle)){
9215cf1669fSMatthias Ringwald         gatt_client_handle_transaction_complete(gatt_client);
9225cf1669fSMatthias Ringwald         emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
9233deb3ec6SMatthias Ringwald         return;
9243deb3ec6SMatthias Ringwald     }
9253deb3ec6SMatthias Ringwald     // next
9265cf1669fSMatthias Ringwald     gatt_client->start_group_handle = last_result_handle + 1u;
9275cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = next_query_state;
9283deb3ec6SMatthias Ringwald }
9293deb3ec6SMatthias Ringwald 
9305cf1669fSMatthias Ringwald static void trigger_next_included_service_query(gatt_client_t * gatt_client, uint16_t last_result_handle){
9315cf1669fSMatthias Ringwald     trigger_next_query(gatt_client, last_result_handle, P_W2_SEND_INCLUDED_SERVICE_QUERY);
9323deb3ec6SMatthias Ringwald }
9333deb3ec6SMatthias Ringwald 
9345cf1669fSMatthias Ringwald static void trigger_next_service_query(gatt_client_t * gatt_client, uint16_t last_result_handle){
9355cf1669fSMatthias Ringwald     trigger_next_query(gatt_client, last_result_handle, P_W2_SEND_SERVICE_QUERY);
9363deb3ec6SMatthias Ringwald }
9373deb3ec6SMatthias Ringwald 
9385cf1669fSMatthias Ringwald static void trigger_next_service_by_uuid_query(gatt_client_t * gatt_client, uint16_t last_result_handle){
9395cf1669fSMatthias Ringwald     trigger_next_query(gatt_client, last_result_handle, P_W2_SEND_SERVICE_WITH_UUID_QUERY);
9403deb3ec6SMatthias Ringwald }
9413deb3ec6SMatthias Ringwald 
9425cf1669fSMatthias Ringwald static void trigger_next_characteristic_query(gatt_client_t * gatt_client, uint16_t last_result_handle){
9435cf1669fSMatthias Ringwald     if (is_query_done(gatt_client, last_result_handle)){
9443deb3ec6SMatthias Ringwald         // report last characteristic
9455cf1669fSMatthias Ringwald         characteristic_end_found(gatt_client, gatt_client->end_group_handle);
9463deb3ec6SMatthias Ringwald     }
9475cf1669fSMatthias Ringwald     trigger_next_query(gatt_client, last_result_handle, P_W2_SEND_ALL_CHARACTERISTICS_OF_SERVICE_QUERY);
9483deb3ec6SMatthias Ringwald }
9493deb3ec6SMatthias Ringwald 
9505cf1669fSMatthias Ringwald static void trigger_next_characteristic_descriptor_query(gatt_client_t * gatt_client, uint16_t last_result_handle){
9515cf1669fSMatthias Ringwald     trigger_next_query(gatt_client, last_result_handle, P_W2_SEND_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY);
9523deb3ec6SMatthias Ringwald }
9533deb3ec6SMatthias Ringwald 
9545cf1669fSMatthias Ringwald static void trigger_next_read_by_type_query(gatt_client_t * gatt_client, uint16_t last_result_handle){
9555cf1669fSMatthias Ringwald     trigger_next_query(gatt_client, last_result_handle, P_W2_SEND_READ_BY_TYPE_REQUEST);
9563deb3ec6SMatthias Ringwald }
9573deb3ec6SMatthias Ringwald 
9585cf1669fSMatthias Ringwald static void trigger_next_prepare_write_query(gatt_client_t * gatt_client, gatt_client_state_t next_query_state, gatt_client_state_t done_state){
9595cf1669fSMatthias Ringwald     gatt_client->attribute_offset += write_blob_length(gatt_client);
9605cf1669fSMatthias Ringwald     uint16_t next_blob_length =  write_blob_length(gatt_client);
9613deb3ec6SMatthias Ringwald 
9624ea43905SMatthias Ringwald     if (next_blob_length == 0u){
9635cf1669fSMatthias Ringwald         gatt_client->gatt_client_state = done_state;
9643deb3ec6SMatthias Ringwald         return;
9653deb3ec6SMatthias Ringwald     }
9665cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = next_query_state;
9673deb3ec6SMatthias Ringwald }
9683deb3ec6SMatthias Ringwald 
9695cf1669fSMatthias Ringwald static void trigger_next_blob_query(gatt_client_t * gatt_client, gatt_client_state_t next_query_state, uint16_t received_blob_length){
9703deb3ec6SMatthias Ringwald 
971dda77937SMatthias Ringwald     uint16_t max_blob_length = gatt_client->mtu - 1u;
9723deb3ec6SMatthias Ringwald     if (received_blob_length < max_blob_length){
9735cf1669fSMatthias Ringwald         gatt_client_handle_transaction_complete(gatt_client);
9745cf1669fSMatthias Ringwald         emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
9753deb3ec6SMatthias Ringwald         return;
9763deb3ec6SMatthias Ringwald     }
9773deb3ec6SMatthias Ringwald 
9785cf1669fSMatthias Ringwald     gatt_client->attribute_offset += received_blob_length;
9795cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = next_query_state;
9803deb3ec6SMatthias Ringwald }
9813deb3ec6SMatthias Ringwald 
9823deb3ec6SMatthias Ringwald 
9835cf1669fSMatthias Ringwald static int is_value_valid(gatt_client_t *gatt_client, uint8_t *packet, uint16_t size){
984f8fbdce0SMatthias Ringwald     uint16_t attribute_handle = little_endian_read_16(packet, 1);
985f8fbdce0SMatthias Ringwald     uint16_t value_offset = little_endian_read_16(packet, 3);
9863deb3ec6SMatthias Ringwald 
9875cf1669fSMatthias Ringwald     if (gatt_client->attribute_handle != attribute_handle) return 0;
9885cf1669fSMatthias Ringwald     if (gatt_client->attribute_offset != value_offset) return 0;
9895cf1669fSMatthias Ringwald     return memcmp(&gatt_client->attribute_value[gatt_client->attribute_offset], &packet[5], size - 5u) == 0u;
9903deb3ec6SMatthias Ringwald }
9913deb3ec6SMatthias Ringwald 
9920038504eSMatthias Ringwald #ifdef ENABLE_LE_SIGNED_WRITE
99392a7335eSMatthias Ringwald static void gatt_client_run_for_client_start_signed_write(gatt_client_t *gatt_client) {
99492a7335eSMatthias Ringwald     sm_key_t csrk;
99592a7335eSMatthias Ringwald     le_device_db_local_csrk_get(gatt_client->le_device_index, csrk);
99692a7335eSMatthias Ringwald     uint32_t sign_counter = le_device_db_local_counter_get(gatt_client->le_device_index);
99792a7335eSMatthias Ringwald     gatt_client->gatt_client_state = P_W4_CMAC_RESULT;
99892a7335eSMatthias Ringwald     sm_cmac_signed_write_start(csrk, ATT_SIGNED_WRITE_COMMAND, gatt_client->attribute_handle, gatt_client->attribute_length, gatt_client->attribute_value, sign_counter, att_signed_write_handle_cmac_result);
99992a7335eSMatthias Ringwald }
10000038504eSMatthias Ringwald #endif
100192a7335eSMatthias Ringwald 
100292a7335eSMatthias Ringwald // returns true if packet was sent
10031979f09cSMatthias Ringwald static bool gatt_client_run_for_gatt_client(gatt_client_t * gatt_client){
10043deb3ec6SMatthias Ringwald 
1005e4d159baSMatthias Ringwald     // wait until re-encryption is complete
10061979f09cSMatthias Ringwald     if (gap_reconnect_security_setup_active(gatt_client->con_handle)) return false;
1007d1e1a57fSMatthias Ringwald 
1008e4d159baSMatthias Ringwald     // wait until re-encryption is complete
10091979f09cSMatthias Ringwald     if (gatt_client->reencryption_active) return false;
10106c124bc2SMatthias Ringwald 
101111279da7SMatthias Ringwald     // wait until pairing complete (either reactive authentication or due to required security level)
10121979f09cSMatthias Ringwald     if (gatt_client->wait_for_authentication_complete) return false;
101311279da7SMatthias Ringwald 
1014fd14b205SMatthias Ringwald     bool client_request_pending = gatt_client->gatt_client_state != P_READY;
1015fd14b205SMatthias Ringwald 
10161aa9e3e8SMatthias Ringwald     // verify security level for Mandatory Authentication over LE
1017*46012949SMatthias Ringwald     bool check_security;
1018*46012949SMatthias Ringwald     switch (gatt_client->bearer_type){
1019*46012949SMatthias Ringwald         case ATT_BEARER_UNENHANCED_LE:
1020*46012949SMatthias Ringwald             check_security = true;
1021*46012949SMatthias Ringwald             break;
1022*46012949SMatthias Ringwald         default:
10239ced96e1SMatthias Ringwald             check_security = false;
1024*46012949SMatthias Ringwald             break;
10259ced96e1SMatthias Ringwald     }
10269ced96e1SMatthias Ringwald     if (client_request_pending && (gatt_client_required_security_level > gatt_client->security_level) && check_security){
10271dfae9c7SMatthias Ringwald         log_info("Trigger pairing, current security level %u, required %u\n", gatt_client->security_level, gatt_client_required_security_level);
10283503dc74SMatthias Ringwald         gatt_client->wait_for_authentication_complete = 1;
102911279da7SMatthias Ringwald         // set att error code for pairing failure based on required level
103011279da7SMatthias Ringwald         switch (gatt_client_required_security_level){
103111279da7SMatthias Ringwald             case LEVEL_4:
103211279da7SMatthias Ringwald             case LEVEL_3:
103311279da7SMatthias Ringwald                 gatt_client->pending_error_code = ATT_ERROR_INSUFFICIENT_AUTHENTICATION;
103411279da7SMatthias Ringwald                 break;
103511279da7SMatthias Ringwald             default:
103611279da7SMatthias Ringwald                 gatt_client->pending_error_code = ATT_ERROR_INSUFFICIENT_ENCRYPTION;
103711279da7SMatthias Ringwald                 break;
103811279da7SMatthias Ringwald         }
103911279da7SMatthias Ringwald         sm_request_pairing(gatt_client->con_handle);
104011279da7SMatthias Ringwald         // sm probably just sent a pdu
10411979f09cSMatthias Ringwald         return true;
104211279da7SMatthias Ringwald     }
1043f4b33574SMatthias Ringwald 
10445cf1669fSMatthias Ringwald     switch (gatt_client->mtu_state) {
1045544128c3SMatthias Ringwald         case SEND_MTU_EXCHANGE:
10465cf1669fSMatthias Ringwald             gatt_client->mtu_state = SENT_MTU_EXCHANGE;
10476e7b444cSMatthias Ringwald             att_exchange_mtu_request(gatt_client);
10481979f09cSMatthias Ringwald             return true;
10493deb3ec6SMatthias Ringwald         case SENT_MTU_EXCHANGE:
10501979f09cSMatthias Ringwald             return false;
10513deb3ec6SMatthias Ringwald         default:
10523deb3ec6SMatthias Ringwald             break;
10533deb3ec6SMatthias Ringwald     }
10543deb3ec6SMatthias Ringwald 
10555cf1669fSMatthias Ringwald     if (gatt_client->send_confirmation){
10565cf1669fSMatthias Ringwald         gatt_client->send_confirmation = 0;
10576e7b444cSMatthias Ringwald         att_confirmation(gatt_client);
10581979f09cSMatthias Ringwald         return true;
10593deb3ec6SMatthias Ringwald     }
10603deb3ec6SMatthias Ringwald 
10613deb3ec6SMatthias Ringwald     // check MTU for writes
10625cf1669fSMatthias Ringwald     switch (gatt_client->gatt_client_state){
10633deb3ec6SMatthias Ringwald         case P_W2_SEND_WRITE_CHARACTERISTIC_VALUE:
10643deb3ec6SMatthias Ringwald         case P_W2_SEND_WRITE_CHARACTERISTIC_DESCRIPTOR:
1065dda77937SMatthias Ringwald             if (gatt_client->attribute_length <= (gatt_client->mtu - 3u)) break;
1066dda77937SMatthias Ringwald             log_error("gatt_client_run: value len %u > MTU %u - 3\n", gatt_client->attribute_length,gatt_client->mtu);
10675cf1669fSMatthias Ringwald             gatt_client_handle_transaction_complete(gatt_client);
10685cf1669fSMatthias Ringwald             emit_gatt_complete_event(gatt_client, ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH);
10691979f09cSMatthias Ringwald             return false;
10703deb3ec6SMatthias Ringwald         default:
10713deb3ec6SMatthias Ringwald             break;
10723deb3ec6SMatthias Ringwald     }
10733deb3ec6SMatthias Ringwald 
10740038504eSMatthias Ringwald     bool packet_sent = true;
10750038504eSMatthias Ringwald     bool done = true;
10765cf1669fSMatthias Ringwald     switch (gatt_client->gatt_client_state){
10773deb3ec6SMatthias Ringwald         case P_W2_SEND_SERVICE_QUERY:
10785cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_SERVICE_QUERY_RESULT;
10795cf1669fSMatthias Ringwald             send_gatt_services_request(gatt_client);
10800038504eSMatthias Ringwald             break;
10813deb3ec6SMatthias Ringwald 
10823deb3ec6SMatthias Ringwald         case P_W2_SEND_SERVICE_WITH_UUID_QUERY:
10835cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_SERVICE_WITH_UUID_RESULT;
10845cf1669fSMatthias Ringwald             send_gatt_services_by_uuid_request(gatt_client);
10850038504eSMatthias Ringwald             break;
10863deb3ec6SMatthias Ringwald 
10873deb3ec6SMatthias Ringwald         case P_W2_SEND_ALL_CHARACTERISTICS_OF_SERVICE_QUERY:
10885cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT;
10895cf1669fSMatthias Ringwald             send_gatt_characteristic_request(gatt_client);
10900038504eSMatthias Ringwald             break;
10913deb3ec6SMatthias Ringwald 
10923deb3ec6SMatthias Ringwald         case P_W2_SEND_CHARACTERISTIC_WITH_UUID_QUERY:
10935cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT;
10945cf1669fSMatthias Ringwald             send_gatt_characteristic_request(gatt_client);
10950038504eSMatthias Ringwald             break;
10963deb3ec6SMatthias Ringwald 
10973deb3ec6SMatthias Ringwald         case P_W2_SEND_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY:
10985cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT;
10995cf1669fSMatthias Ringwald             send_gatt_characteristic_descriptor_request(gatt_client);
11000038504eSMatthias Ringwald             break;
11013deb3ec6SMatthias Ringwald 
11023deb3ec6SMatthias Ringwald         case P_W2_SEND_INCLUDED_SERVICE_QUERY:
11035cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_INCLUDED_SERVICE_QUERY_RESULT;
11045cf1669fSMatthias Ringwald             send_gatt_included_service_request(gatt_client);
11050038504eSMatthias Ringwald             break;
11063deb3ec6SMatthias Ringwald 
11073deb3ec6SMatthias Ringwald         case P_W2_SEND_INCLUDED_SERVICE_WITH_UUID_QUERY:
11085cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_INCLUDED_SERVICE_UUID_WITH_QUERY_RESULT;
11095cf1669fSMatthias Ringwald             send_gatt_included_service_uuid_request(gatt_client);
11100038504eSMatthias Ringwald             break;
11113deb3ec6SMatthias Ringwald 
11123deb3ec6SMatthias Ringwald         case P_W2_SEND_READ_CHARACTERISTIC_VALUE_QUERY:
11135cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_READ_CHARACTERISTIC_VALUE_RESULT;
11145cf1669fSMatthias Ringwald             send_gatt_read_characteristic_value_request(gatt_client);
11150038504eSMatthias Ringwald             break;
11163deb3ec6SMatthias Ringwald 
11173deb3ec6SMatthias Ringwald         case P_W2_SEND_READ_BLOB_QUERY:
11185cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_READ_BLOB_RESULT;
11195cf1669fSMatthias Ringwald             send_gatt_read_blob_request(gatt_client);
11200038504eSMatthias Ringwald             break;
11213deb3ec6SMatthias Ringwald 
11223deb3ec6SMatthias Ringwald         case P_W2_SEND_READ_BY_TYPE_REQUEST:
11235cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_READ_BY_TYPE_RESPONSE;
11245cf1669fSMatthias Ringwald             send_gatt_read_by_type_request(gatt_client);
11250038504eSMatthias Ringwald             break;
11263deb3ec6SMatthias Ringwald 
11273deb3ec6SMatthias Ringwald         case P_W2_SEND_READ_MULTIPLE_REQUEST:
11285cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_READ_MULTIPLE_RESPONSE;
11295cf1669fSMatthias Ringwald             send_gatt_read_multiple_request(gatt_client);
11300038504eSMatthias Ringwald             break;
11313deb3ec6SMatthias Ringwald 
11323deb3ec6SMatthias Ringwald         case P_W2_SEND_WRITE_CHARACTERISTIC_VALUE:
11335cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_WRITE_CHARACTERISTIC_VALUE_RESULT;
11345cf1669fSMatthias Ringwald             send_gatt_write_attribute_value_request(gatt_client);
11350038504eSMatthias Ringwald             break;
11363deb3ec6SMatthias Ringwald 
11373deb3ec6SMatthias Ringwald         case P_W2_PREPARE_WRITE:
11385cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_PREPARE_WRITE_RESULT;
11395cf1669fSMatthias Ringwald             send_gatt_prepare_write_request(gatt_client);
11400038504eSMatthias Ringwald             break;
11413deb3ec6SMatthias Ringwald 
11423deb3ec6SMatthias Ringwald         case P_W2_PREPARE_WRITE_SINGLE:
11435cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_PREPARE_WRITE_SINGLE_RESULT;
11445cf1669fSMatthias Ringwald             send_gatt_prepare_write_request(gatt_client);
11450038504eSMatthias Ringwald             break;
11463deb3ec6SMatthias Ringwald 
11473deb3ec6SMatthias Ringwald         case P_W2_PREPARE_RELIABLE_WRITE:
11485cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_PREPARE_RELIABLE_WRITE_RESULT;
11495cf1669fSMatthias Ringwald             send_gatt_prepare_write_request(gatt_client);
11500038504eSMatthias Ringwald             break;
11513deb3ec6SMatthias Ringwald 
11523deb3ec6SMatthias Ringwald         case P_W2_EXECUTE_PREPARED_WRITE:
11535cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_EXECUTE_PREPARED_WRITE_RESULT;
11545cf1669fSMatthias Ringwald             send_gatt_execute_write_request(gatt_client);
11550038504eSMatthias Ringwald             break;
11563deb3ec6SMatthias Ringwald 
11573deb3ec6SMatthias Ringwald         case P_W2_CANCEL_PREPARED_WRITE:
11585cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_CANCEL_PREPARED_WRITE_RESULT;
11595cf1669fSMatthias Ringwald             send_gatt_cancel_prepared_write_request(gatt_client);
11600038504eSMatthias Ringwald             break;
11613deb3ec6SMatthias Ringwald 
11623deb3ec6SMatthias Ringwald         case P_W2_CANCEL_PREPARED_WRITE_DATA_MISMATCH:
11635cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_CANCEL_PREPARED_WRITE_DATA_MISMATCH_RESULT;
11645cf1669fSMatthias Ringwald             send_gatt_cancel_prepared_write_request(gatt_client);
11650038504eSMatthias Ringwald             break;
11663deb3ec6SMatthias Ringwald 
1167abdc9fb5SMatthias Ringwald #ifdef ENABLE_GATT_FIND_INFORMATION_FOR_CCC_DISCOVERY
1168abdc9fb5SMatthias Ringwald         case P_W2_SEND_FIND_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY:
1169abdc9fb5SMatthias Ringwald             // use Find Information
11705cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_FIND_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY_RESULT;
11715cf1669fSMatthias Ringwald             send_gatt_characteristic_descriptor_request(gatt_client);
1172abdc9fb5SMatthias Ringwald #else
11733deb3ec6SMatthias Ringwald         case P_W2_SEND_READ_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY:
1174abdc9fb5SMatthias Ringwald             // Use Read By Type
11755cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_READ_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY_RESULT;
11765cf1669fSMatthias Ringwald             send_gatt_read_client_characteristic_configuration_request(gatt_client);
1177abdc9fb5SMatthias Ringwald #endif
11780038504eSMatthias Ringwald             break;
11793deb3ec6SMatthias Ringwald 
11803deb3ec6SMatthias Ringwald         case P_W2_SEND_READ_CHARACTERISTIC_DESCRIPTOR_QUERY:
11815cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_READ_CHARACTERISTIC_DESCRIPTOR_RESULT;
11825cf1669fSMatthias Ringwald             send_gatt_read_characteristic_descriptor_request(gatt_client);
11830038504eSMatthias Ringwald             break;
11843deb3ec6SMatthias Ringwald 
11853deb3ec6SMatthias Ringwald         case P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY:
11865cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_RESULT;
11875cf1669fSMatthias Ringwald             send_gatt_read_blob_request(gatt_client);
11880038504eSMatthias Ringwald             break;
11893deb3ec6SMatthias Ringwald 
11903deb3ec6SMatthias Ringwald         case P_W2_SEND_WRITE_CHARACTERISTIC_DESCRIPTOR:
11915cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT;
11925cf1669fSMatthias Ringwald             send_gatt_write_attribute_value_request(gatt_client);
11930038504eSMatthias Ringwald             break;
11943deb3ec6SMatthias Ringwald 
11953deb3ec6SMatthias Ringwald         case P_W2_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION:
11965cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_CLIENT_CHARACTERISTIC_CONFIGURATION_RESULT;
11975cf1669fSMatthias Ringwald             send_gatt_write_client_characteristic_configuration_request(gatt_client);
11980038504eSMatthias Ringwald             break;
11993deb3ec6SMatthias Ringwald 
12003deb3ec6SMatthias Ringwald         case P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR:
12015cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT;
12025cf1669fSMatthias Ringwald             send_gatt_prepare_write_request(gatt_client);
12030038504eSMatthias Ringwald             break;
12043deb3ec6SMatthias Ringwald 
12053deb3ec6SMatthias Ringwald         case P_W2_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR:
12065cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT;
12075cf1669fSMatthias Ringwald             send_gatt_execute_write_request(gatt_client);
12080038504eSMatthias Ringwald             break;
12093deb3ec6SMatthias Ringwald 
12107a766ebfSMatthias Ringwald #ifdef ENABLE_LE_SIGNED_WRITE
1211793cf6ceSMatthias Ringwald         case P_W4_IDENTITY_RESOLVING:
12125cf1669fSMatthias Ringwald             log_info("P_W4_IDENTITY_RESOLVING - state %x", sm_identity_resolving_state(gatt_client->con_handle));
12135cf1669fSMatthias Ringwald             switch (sm_identity_resolving_state(gatt_client->con_handle)){
1214793cf6ceSMatthias Ringwald                 case IRK_LOOKUP_SUCCEEDED:
12155cf1669fSMatthias Ringwald                     gatt_client->le_device_index = sm_le_device_index(gatt_client->con_handle);
12165cf1669fSMatthias Ringwald                     gatt_client->gatt_client_state = P_W4_CMAC_READY;
121792a7335eSMatthias Ringwald                     if (sm_cmac_ready()){
121892a7335eSMatthias Ringwald                         gatt_client_run_for_client_start_signed_write(gatt_client);
121992a7335eSMatthias Ringwald                     }
1220793cf6ceSMatthias Ringwald                     break;
1221793cf6ceSMatthias Ringwald                 case IRK_LOOKUP_FAILED:
12225cf1669fSMatthias Ringwald                     gatt_client_handle_transaction_complete(gatt_client);
12235cf1669fSMatthias Ringwald                     emit_gatt_complete_event(gatt_client, ATT_ERROR_BONDING_INFORMATION_MISSING);
122492a7335eSMatthias Ringwald                     break;
1225793cf6ceSMatthias Ringwald                 default:
122692a7335eSMatthias Ringwald                     break;
1227793cf6ceSMatthias Ringwald             }
12280038504eSMatthias Ringwald             packet_sent = false;
12290038504eSMatthias Ringwald             break;
1230793cf6ceSMatthias Ringwald 
12313deb3ec6SMatthias Ringwald         case P_W4_CMAC_READY:
12323deb3ec6SMatthias Ringwald             if (sm_cmac_ready()){
123392a7335eSMatthias Ringwald                 gatt_client_run_for_client_start_signed_write(gatt_client);
12343deb3ec6SMatthias Ringwald             }
12350038504eSMatthias Ringwald             packet_sent = false;
12360038504eSMatthias Ringwald             break;
12373deb3ec6SMatthias Ringwald 
12383deb3ec6SMatthias Ringwald         case P_W2_SEND_SIGNED_WRITE: {
12395cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W4_SEND_SINGED_WRITE_DONE;
12403deb3ec6SMatthias Ringwald             // bump local signing counter
12415cf1669fSMatthias Ringwald             uint32_t sign_counter = le_device_db_local_counter_get(gatt_client->le_device_index);
12425cf1669fSMatthias Ringwald             le_device_db_local_counter_set(gatt_client->le_device_index, sign_counter + 1);
124364b12680SMatthias Ringwald             // send signed write command
12445cf1669fSMatthias Ringwald             send_gatt_signed_write_request(gatt_client, sign_counter);
12453deb3ec6SMatthias Ringwald             // finally, notifiy client that write is complete
12465cf1669fSMatthias Ringwald             gatt_client_handle_transaction_complete(gatt_client);
12475cf1669fSMatthias Ringwald             emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
1248b68ac7a5SMatthias Ringwald             break;
12493deb3ec6SMatthias Ringwald         }
12507a766ebfSMatthias Ringwald #endif
12513deb3ec6SMatthias Ringwald         default:
1252b68ac7a5SMatthias Ringwald             done = false;
12533deb3ec6SMatthias Ringwald             break;
12543deb3ec6SMatthias Ringwald     }
125547181045SMatthias Ringwald 
12560038504eSMatthias Ringwald     if (done){
12570038504eSMatthias Ringwald         return packet_sent;
12580038504eSMatthias Ringwald     }
12590038504eSMatthias Ringwald 
126059d34cd2SMatthias Ringwald     // write without response callback
126159d34cd2SMatthias Ringwald     btstack_context_callback_registration_t * callback =
126259d34cd2SMatthias Ringwald             (btstack_context_callback_registration_t *) btstack_linked_list_pop(&gatt_client->write_without_response_requests);
126359d34cd2SMatthias Ringwald     if (callback != NULL){
126459d34cd2SMatthias Ringwald         (*callback->callback)(callback->context);
126559d34cd2SMatthias Ringwald         return true;
126659d34cd2SMatthias Ringwald     }
126759d34cd2SMatthias Ringwald 
126859d34cd2SMatthias Ringwald     // requested can send now old
12695cf1669fSMatthias Ringwald     if (gatt_client->write_without_response_callback){
12705cf1669fSMatthias Ringwald         btstack_packet_handler_t packet_handler = gatt_client->write_without_response_callback;
12715cf1669fSMatthias Ringwald         gatt_client->write_without_response_callback = NULL;
127247181045SMatthias Ringwald         uint8_t event[4];
127347181045SMatthias Ringwald         event[0] = GATT_EVENT_CAN_WRITE_WITHOUT_RESPONSE;
12744ea43905SMatthias Ringwald         event[1] = sizeof(event) - 2u;
12755cf1669fSMatthias Ringwald         little_endian_store_16(event, 2, gatt_client->con_handle);
12765cf1669fSMatthias Ringwald         packet_handler(HCI_EVENT_PACKET, gatt_client->con_handle, event, sizeof(event));
12771979f09cSMatthias Ringwald         return true; // to trigger requeueing (even if higher layer didn't sent)
127847181045SMatthias Ringwald     }
127947181045SMatthias Ringwald 
12801979f09cSMatthias Ringwald     return false;
12813deb3ec6SMatthias Ringwald }
12823deb3ec6SMatthias Ringwald 
1283544128c3SMatthias Ringwald static void gatt_client_run(void){
1284544128c3SMatthias Ringwald     btstack_linked_item_t *it;
1285a0da043fSMatthias Ringwald     for (it = (btstack_linked_item_t *) gatt_client_connections; it != NULL; it = it->next){
12865cf1669fSMatthias Ringwald         gatt_client_t * gatt_client = (gatt_client_t *) it;
1287*46012949SMatthias Ringwald         switch (gatt_client->bearer_type){
1288*46012949SMatthias Ringwald             case ATT_BEARER_UNENHANCED_LE:
1289*46012949SMatthias Ringwald                 if (!att_dispatch_client_can_send_now(gatt_client->con_handle)) {
1290*46012949SMatthias Ringwald                     att_dispatch_client_request_can_send_now_event(gatt_client->con_handle);
1291*46012949SMatthias Ringwald                     return;
1292*46012949SMatthias Ringwald                 }
1293*46012949SMatthias Ringwald                 bool packet_sent = gatt_client_run_for_gatt_client(gatt_client);
1294*46012949SMatthias Ringwald                 if (packet_sent){
1295*46012949SMatthias Ringwald                     // request new permission
1296*46012949SMatthias Ringwald                     att_dispatch_client_request_can_send_now_event(gatt_client->con_handle);
1297*46012949SMatthias Ringwald                     // requeue client for fairness and exit
1298*46012949SMatthias Ringwald                     // note: iterator has become invalid
1299*46012949SMatthias Ringwald                     btstack_linked_list_remove(&gatt_client_connections, (btstack_linked_item_t *) gatt_client);
1300*46012949SMatthias Ringwald                     btstack_linked_list_add_tail(&gatt_client_connections, (btstack_linked_item_t *) gatt_client);
1301*46012949SMatthias Ringwald                     return;
1302*46012949SMatthias Ringwald                 }
1303*46012949SMatthias Ringwald                 break;
13041450cdc6SMatthias Ringwald #ifdef ENABLE_GATT_OVER_CLASSIC
1305*46012949SMatthias Ringwald             case ATT_BEARER_UNENHANCED_CLASSIC:
13061450cdc6SMatthias Ringwald                 if (gatt_client->con_handle == HCI_CON_HANDLE_INVALID) {
13071450cdc6SMatthias Ringwald                     continue;
13081450cdc6SMatthias Ringwald                 }
13091aa9e3e8SMatthias Ringwald 
13101aa9e3e8SMatthias Ringwald                 // handle GATT over BR/EDR
13111aa9e3e8SMatthias Ringwald                 if (gatt_client->l2cap_psm != 0){
13121aa9e3e8SMatthias Ringwald                     if (l2cap_can_send_packet_now(gatt_client->l2cap_cid) == false){
13131aa9e3e8SMatthias Ringwald                         l2cap_request_can_send_now_event(gatt_client->l2cap_cid);
13141aa9e3e8SMatthias Ringwald                         return;
13151aa9e3e8SMatthias Ringwald                     }
13161aa9e3e8SMatthias Ringwald                     bool packet_sent = gatt_client_run_for_gatt_client(gatt_client);
13171aa9e3e8SMatthias Ringwald                     if (packet_sent){
13181aa9e3e8SMatthias Ringwald                         // request new permission
13191aa9e3e8SMatthias Ringwald                         att_dispatch_client_request_can_send_now_event(gatt_client->con_handle);
13201aa9e3e8SMatthias Ringwald                         // requeue client for fairness and exit
13211aa9e3e8SMatthias Ringwald                         // note: iterator has become invalid
13221aa9e3e8SMatthias Ringwald                         btstack_linked_list_remove(&gatt_client_connections, (btstack_linked_item_t *) gatt_client);
13231aa9e3e8SMatthias Ringwald                         btstack_linked_list_add_tail(&gatt_client_connections, (btstack_linked_item_t *) gatt_client);
13241aa9e3e8SMatthias Ringwald                         return;
13251aa9e3e8SMatthias Ringwald                     }
13261aa9e3e8SMatthias Ringwald                 }
1327*46012949SMatthias Ringwald                 break;
13281450cdc6SMatthias Ringwald #endif
1329*46012949SMatthias Ringwald             default:
1330*46012949SMatthias Ringwald                 btstack_unreachable();
1331*46012949SMatthias Ringwald                 break;
1332544128c3SMatthias Ringwald         }
1333*46012949SMatthias Ringwald 
1334*46012949SMatthias Ringwald 
1335544128c3SMatthias Ringwald     }
13363deb3ec6SMatthias Ringwald }
13373deb3ec6SMatthias Ringwald 
13385cf1669fSMatthias Ringwald static void gatt_client_report_error_if_pending(gatt_client_t *gatt_client, uint8_t att_error_code) {
13395cf1669fSMatthias Ringwald     if (is_ready(gatt_client) == 1) return;
13405cf1669fSMatthias Ringwald     gatt_client_handle_transaction_complete(gatt_client);
13415cf1669fSMatthias Ringwald     emit_gatt_complete_event(gatt_client, att_error_code);
13423deb3ec6SMatthias Ringwald }
13433deb3ec6SMatthias Ringwald 
134478c4542aSMatthias Ringwald static void gatt_client_handle_reencryption_complete(const uint8_t * packet){
134578c4542aSMatthias Ringwald     hci_con_handle_t con_handle = sm_event_reencryption_complete_get_handle(packet);
134678c4542aSMatthias Ringwald     gatt_client_t * gatt_client = gatt_client_get_context_for_handle(con_handle);
134778c4542aSMatthias Ringwald     if (gatt_client == NULL) return;
134878c4542aSMatthias Ringwald 
134978c4542aSMatthias Ringwald     // update security level
135078c4542aSMatthias Ringwald     gatt_client->security_level = gatt_client_le_security_level_for_connection(con_handle);
135178c4542aSMatthias Ringwald 
135278c4542aSMatthias Ringwald     gatt_client->reencryption_result = sm_event_reencryption_complete_get_status(packet);
135378c4542aSMatthias Ringwald     gatt_client->reencryption_active = false;
135478c4542aSMatthias Ringwald     gatt_client->wait_for_authentication_complete = 0;
135578c4542aSMatthias Ringwald 
135678c4542aSMatthias Ringwald     if (gatt_client->gatt_client_state == P_READY) return;
135778c4542aSMatthias Ringwald 
135878c4542aSMatthias Ringwald     switch (sm_event_reencryption_complete_get_status(packet)){
135978c4542aSMatthias Ringwald         case ERROR_CODE_SUCCESS:
136078c4542aSMatthias Ringwald             log_info("re-encryption success, retry operation");
136178c4542aSMatthias Ringwald             break;
136278c4542aSMatthias Ringwald         case ERROR_CODE_AUTHENTICATION_FAILURE:
136378c4542aSMatthias Ringwald         case ERROR_CODE_PIN_OR_KEY_MISSING:
136478c4542aSMatthias Ringwald #if defined(ENABLE_GATT_CLIENT_PAIRING) && !defined(ENABLE_LE_PROACTIVE_AUTHENTICATION)
136578c4542aSMatthias Ringwald             if (gatt_client_required_security_level == LEVEL_0) {
136678c4542aSMatthias Ringwald                 // re-encryption failed for reactive authentication with pairing and we have a pending client request
136778c4542aSMatthias Ringwald                 // => try to resolve it by deleting bonding information if we started pairing before
136878c4542aSMatthias Ringwald                 // delete bonding information
136978c4542aSMatthias Ringwald                 int le_device_db_index = sm_le_device_index(gatt_client->con_handle);
137078c4542aSMatthias Ringwald                 btstack_assert(le_device_db_index >= 0);
137178c4542aSMatthias Ringwald                 log_info("reactive auth with pairing: delete bonding and start pairing");
137278c4542aSMatthias Ringwald #ifdef ENABLE_LE_PRIVACY_ADDRESS_RESOLUTION
137378c4542aSMatthias Ringwald                 hci_remove_le_device_db_entry_from_resolving_list((uint16_t) le_device_db_index);
137478c4542aSMatthias Ringwald #endif
137578c4542aSMatthias Ringwald                 le_device_db_remove(le_device_db_index);
137678c4542aSMatthias Ringwald                 // trigger pairing again
137778c4542aSMatthias Ringwald                 sm_request_pairing(gatt_client->con_handle);
137878c4542aSMatthias Ringwald                 break;
137978c4542aSMatthias Ringwald             }
138078c4542aSMatthias Ringwald #endif
138178c4542aSMatthias Ringwald             // report bonding information missing
138278c4542aSMatthias Ringwald             gatt_client_handle_transaction_complete(gatt_client);
138378c4542aSMatthias Ringwald             emit_gatt_complete_event(gatt_client, ATT_ERROR_BONDING_INFORMATION_MISSING);
138478c4542aSMatthias Ringwald             break;
138578c4542aSMatthias Ringwald         default:
138678c4542aSMatthias Ringwald             // report bonding information missing
138778c4542aSMatthias Ringwald             gatt_client_handle_transaction_complete(gatt_client);
138878c4542aSMatthias Ringwald             emit_gatt_complete_event(gatt_client, gatt_client->pending_error_code);
138978c4542aSMatthias Ringwald             break;
139078c4542aSMatthias Ringwald     }
139178c4542aSMatthias Ringwald }
139278c4542aSMatthias Ringwald 
139378c4542aSMatthias Ringwald static void gatt_client_handle_disconnection_complete(const uint8_t * packet){
139478c4542aSMatthias Ringwald     log_info("GATT Client: HCI_EVENT_DISCONNECTION_COMPLETE");
139578c4542aSMatthias Ringwald     hci_con_handle_t con_handle = little_endian_read_16(packet,3);
139678c4542aSMatthias Ringwald     gatt_client_t * gatt_client = gatt_client_get_context_for_handle(con_handle);
139778c4542aSMatthias Ringwald     if (gatt_client == NULL) return;
139878c4542aSMatthias Ringwald 
139978c4542aSMatthias Ringwald     gatt_client_report_error_if_pending(gatt_client, ATT_ERROR_HCI_DISCONNECT_RECEIVED);
140078c4542aSMatthias Ringwald     gatt_client_timeout_stop(gatt_client);
140178c4542aSMatthias Ringwald     btstack_linked_list_remove(&gatt_client_connections, (btstack_linked_item_t *) gatt_client);
140278c4542aSMatthias Ringwald     btstack_memory_gatt_client_free(gatt_client);
140378c4542aSMatthias Ringwald }
140478c4542aSMatthias Ringwald 
1405f4b33574SMatthias Ringwald static void gatt_client_event_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
14061ac26e06SMatthias Ringwald     UNUSED(channel);    // ok: handling own l2cap events
14071ac26e06SMatthias Ringwald     UNUSED(size);       // ok: there is no channel
14089ec2630cSMatthias Ringwald 
1409361b1363SMatthias Ringwald     if (packet_type != HCI_EVENT_PACKET) return;
1410361b1363SMatthias Ringwald 
1411f4b33574SMatthias Ringwald     hci_con_handle_t con_handle;
14125cf1669fSMatthias Ringwald     gatt_client_t * gatt_client;
14130e2df43fSMatthias Ringwald     switch (hci_event_packet_get_type(packet)) {
14143deb3ec6SMatthias Ringwald         case HCI_EVENT_DISCONNECTION_COMPLETE:
141578c4542aSMatthias Ringwald             gatt_client_handle_disconnection_complete(packet);
14163deb3ec6SMatthias Ringwald             break;
1417f4b33574SMatthias Ringwald 
1418f4b33574SMatthias Ringwald         // Pairing complete (with/without bonding=storing of pairing information)
1419f4b33574SMatthias Ringwald         case SM_EVENT_PAIRING_COMPLETE:
1420f4b33574SMatthias Ringwald             con_handle = sm_event_pairing_complete_get_handle(packet);
14215cf1669fSMatthias Ringwald             gatt_client = gatt_client_get_context_for_handle(con_handle);
14225cf1669fSMatthias Ringwald             if (gatt_client == NULL) break;
1423f4b33574SMatthias Ringwald 
14241dfae9c7SMatthias Ringwald             // update security level
14251dfae9c7SMatthias Ringwald             gatt_client->security_level = gatt_client_le_security_level_for_connection(con_handle);
14261dfae9c7SMatthias Ringwald 
14273503dc74SMatthias Ringwald             if (gatt_client->wait_for_authentication_complete){
14283503dc74SMatthias Ringwald                 gatt_client->wait_for_authentication_complete = 0;
1429f4b33574SMatthias Ringwald                 if (sm_event_pairing_complete_get_status(packet)){
14305cf1669fSMatthias Ringwald                     log_info("pairing failed, report previous error 0x%x", gatt_client->pending_error_code);
1431ec9babacSMatthias Ringwald                     gatt_client_report_error_if_pending(gatt_client, gatt_client->pending_error_code);
1432f4b33574SMatthias Ringwald                 } else {
1433f4b33574SMatthias Ringwald                     log_info("pairing success, retry operation");
14343deb3ec6SMatthias Ringwald                 }
1435f4b33574SMatthias Ringwald             }
1436f4b33574SMatthias Ringwald             break;
143711279da7SMatthias Ringwald 
1438793cf6ceSMatthias Ringwald #ifdef ENABLE_LE_SIGNED_WRITE
1439793cf6ceSMatthias Ringwald         // Identity Resolving completed (no code, gatt_client_run will continue)
1440793cf6ceSMatthias Ringwald         case SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED:
1441793cf6ceSMatthias Ringwald         case SM_EVENT_IDENTITY_RESOLVING_FAILED:
1442793cf6ceSMatthias Ringwald             break;
1443793cf6ceSMatthias Ringwald #endif
1444a95ca902SMatthias Ringwald 
14458918bbdaSMatthias Ringwald         // re-encryption started
14468918bbdaSMatthias Ringwald         case SM_EVENT_REENCRYPTION_STARTED:
14478918bbdaSMatthias Ringwald             con_handle = sm_event_reencryption_complete_get_handle(packet);
14488918bbdaSMatthias Ringwald             gatt_client = gatt_client_get_context_for_handle(con_handle);
14498918bbdaSMatthias Ringwald             if (gatt_client == NULL) break;
14508918bbdaSMatthias Ringwald 
14518918bbdaSMatthias Ringwald             gatt_client->reencryption_active = true;
14528918bbdaSMatthias Ringwald             gatt_client->reencryption_result = ERROR_CODE_SUCCESS;
14538918bbdaSMatthias Ringwald             break;
14548918bbdaSMatthias Ringwald 
1455ec9babacSMatthias Ringwald         // re-encryption complete
1456ec9babacSMatthias Ringwald         case SM_EVENT_REENCRYPTION_COMPLETE:
145778c4542aSMatthias Ringwald             gatt_client_handle_reencryption_complete(packet);
1458ec9babacSMatthias Ringwald             break;
14593deb3ec6SMatthias Ringwald         default:
14603deb3ec6SMatthias Ringwald             break;
14613deb3ec6SMatthias Ringwald     }
14623deb3ec6SMatthias Ringwald 
1463361b1363SMatthias Ringwald     gatt_client_run();
14643deb3ec6SMatthias Ringwald }
14653deb3ec6SMatthias Ringwald 
14662da0d963SMatthias Ringwald static void gatt_client_handle_att_read_response(gatt_client_t *gatt_client, uint8_t *packet, uint16_t size) {
14675cf1669fSMatthias Ringwald     switch (gatt_client->gatt_client_state) {
14682da0d963SMatthias Ringwald         case P_W4_INCLUDED_SERVICE_UUID_WITH_QUERY_RESULT:
14692da0d963SMatthias Ringwald             if (size >= 17) {
14702da0d963SMatthias Ringwald                 uint8_t uuid128[16];
14712da0d963SMatthias Ringwald                 reverse_128(&packet[1], uuid128);
14722da0d963SMatthias Ringwald                 report_gatt_included_service_uuid128(gatt_client, gatt_client->start_group_handle, uuid128);
14732da0d963SMatthias Ringwald             }
14742da0d963SMatthias Ringwald             trigger_next_included_service_query(gatt_client, gatt_client->start_group_handle);
14755611a760SMatthias Ringwald             // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
14763deb3ec6SMatthias Ringwald             break;
14772da0d963SMatthias Ringwald 
14782da0d963SMatthias Ringwald         case P_W4_READ_CHARACTERISTIC_VALUE_RESULT:
14792da0d963SMatthias Ringwald             gatt_client_handle_transaction_complete(gatt_client);
14802da0d963SMatthias Ringwald             report_gatt_characteristic_value(gatt_client, gatt_client->attribute_handle, &packet[1], size - 1u);
14812da0d963SMatthias Ringwald             emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
14822da0d963SMatthias Ringwald             break;
14832da0d963SMatthias Ringwald 
14842da0d963SMatthias Ringwald         case P_W4_READ_CHARACTERISTIC_DESCRIPTOR_RESULT:
14852da0d963SMatthias Ringwald             gatt_client_handle_transaction_complete(gatt_client);
14862da0d963SMatthias Ringwald             report_gatt_characteristic_descriptor(gatt_client, gatt_client->attribute_handle, &packet[1],
14872da0d963SMatthias Ringwald                                                   size - 1u, 0u);
14882da0d963SMatthias Ringwald             emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
14892da0d963SMatthias Ringwald             break;
14902da0d963SMatthias Ringwald 
14912da0d963SMatthias Ringwald             // Use ATT_READ_REQUEST for first blob of Read Long Characteristic
14922da0d963SMatthias Ringwald         case P_W4_READ_BLOB_RESULT:
14932da0d963SMatthias Ringwald             report_gatt_long_characteristic_value_blob(gatt_client, gatt_client->attribute_handle, &packet[1],
14942da0d963SMatthias Ringwald                                                        size - 1u, gatt_client->attribute_offset);
14952da0d963SMatthias Ringwald             trigger_next_blob_query(gatt_client, P_W2_SEND_READ_BLOB_QUERY, size - 1u);
14962da0d963SMatthias Ringwald             // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
14972da0d963SMatthias Ringwald             break;
14982da0d963SMatthias Ringwald 
14992da0d963SMatthias Ringwald             // Use ATT_READ_REQUEST for first blob of Read Long Characteristic Descriptor
15002da0d963SMatthias Ringwald         case P_W4_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_RESULT:
15012da0d963SMatthias Ringwald             report_gatt_long_characteristic_descriptor(gatt_client, gatt_client->attribute_handle, &packet[1],
15022da0d963SMatthias Ringwald                                                        size - 1u, gatt_client->attribute_offset);
15032da0d963SMatthias Ringwald             trigger_next_blob_query(gatt_client, P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY,
15042da0d963SMatthias Ringwald                                     size - 1u);
15052da0d963SMatthias Ringwald             // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
15062da0d963SMatthias Ringwald             break;
15072da0d963SMatthias Ringwald 
15083deb3ec6SMatthias Ringwald         default:
15093deb3ec6SMatthias Ringwald             break;
15103deb3ec6SMatthias Ringwald     }
15112da0d963SMatthias Ringwald }
15123deb3ec6SMatthias Ringwald 
15132da0d963SMatthias Ringwald static void gatt_client_handle_att_read_by_type_response(gatt_client_t *gatt_client, uint8_t *packet, uint16_t size) {
15145cf1669fSMatthias Ringwald     switch (gatt_client->gatt_client_state) {
15153deb3ec6SMatthias Ringwald         case P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT:
15165cf1669fSMatthias Ringwald             report_gatt_characteristics(gatt_client, packet, size);
1517cf8e5718SMatthias Ringwald             trigger_next_characteristic_query(gatt_client,
1518cf8e5718SMatthias Ringwald                                               get_last_result_handle_from_characteristics_list(packet, size));
15195611a760SMatthias Ringwald             // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR
15203deb3ec6SMatthias Ringwald             break;
15213deb3ec6SMatthias Ringwald         case P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT:
15225cf1669fSMatthias Ringwald             report_gatt_characteristics(gatt_client, packet, size);
1523cf8e5718SMatthias Ringwald             trigger_next_characteristic_query(gatt_client,
1524cf8e5718SMatthias Ringwald                                               get_last_result_handle_from_characteristics_list(packet, size));
15255611a760SMatthias Ringwald             // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR
15263deb3ec6SMatthias Ringwald             break;
1527cf8e5718SMatthias Ringwald         case P_W4_INCLUDED_SERVICE_QUERY_RESULT: {
15284ea43905SMatthias Ringwald             if (size < 2u) break;
15293deb3ec6SMatthias Ringwald             uint16_t uuid16 = 0;
15303deb3ec6SMatthias Ringwald             uint16_t pair_size = packet[1];
15313deb3ec6SMatthias Ringwald 
15324ea43905SMatthias Ringwald             if (pair_size == 6u) {
15334ea43905SMatthias Ringwald                 if (size < 8u) break;
15343deb3ec6SMatthias Ringwald                 // UUIDs not available, query first included service
15355cf1669fSMatthias Ringwald                 gatt_client->start_group_handle = little_endian_read_16(packet, 2); // ready for next query
15365cf1669fSMatthias Ringwald                 gatt_client->query_start_handle = little_endian_read_16(packet, 4);
15375cf1669fSMatthias Ringwald                 gatt_client->query_end_handle = little_endian_read_16(packet, 6);
15385cf1669fSMatthias Ringwald                 gatt_client->gatt_client_state = P_W2_SEND_INCLUDED_SERVICE_WITH_UUID_QUERY;
15393deb3ec6SMatthias Ringwald                 break;
15403deb3ec6SMatthias Ringwald             }
15413deb3ec6SMatthias Ringwald 
15424ea43905SMatthias Ringwald             if (pair_size != 8u) break;
15439f698c82SMatthias Ringwald 
15449f698c82SMatthias Ringwald             // UUIDs included, report all of them
15453deb3ec6SMatthias Ringwald             uint16_t offset;
15464ea43905SMatthias Ringwald             for (offset = 2u; (offset + 8u) <= size; offset += pair_size) {
1547f8fbdce0SMatthias Ringwald                 uint16_t include_handle = little_endian_read_16(packet, offset);
15485cf1669fSMatthias Ringwald                 gatt_client->query_start_handle = little_endian_read_16(packet, offset + 2u);
15495cf1669fSMatthias Ringwald                 gatt_client->query_end_handle = little_endian_read_16(packet, offset + 4u);
15504ea43905SMatthias Ringwald                 uuid16 = little_endian_read_16(packet, offset + 6u);
15515cf1669fSMatthias Ringwald                 report_gatt_included_service_uuid16(gatt_client, include_handle, uuid16);
15523deb3ec6SMatthias Ringwald             }
15533deb3ec6SMatthias Ringwald 
1554cf8e5718SMatthias Ringwald             trigger_next_included_service_query(gatt_client,
1555cf8e5718SMatthias Ringwald                                                 get_last_result_handle_from_included_services_list(packet,
1556cf8e5718SMatthias Ringwald                                                                                                    size));
15575611a760SMatthias Ringwald             // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
15583deb3ec6SMatthias Ringwald             break;
15593deb3ec6SMatthias Ringwald         }
1560abdc9fb5SMatthias Ringwald #ifndef ENABLE_GATT_FIND_INFORMATION_FOR_CCC_DISCOVERY
15613deb3ec6SMatthias Ringwald         case P_W4_READ_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY_RESULT:
15625cf1669fSMatthias Ringwald             gatt_client->client_characteristic_configuration_handle = little_endian_read_16(packet, 2);
15635cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W2_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION;
15643deb3ec6SMatthias Ringwald             break;
1565abdc9fb5SMatthias Ringwald #endif
15663deb3ec6SMatthias Ringwald         case P_W4_READ_BY_TYPE_RESPONSE: {
15673deb3ec6SMatthias Ringwald             uint16_t pair_size = packet[1];
156839ac9711SMatthias Ringwald             // set last result handle to last valid handle, only used if pair_size invalid
156939ac9711SMatthias Ringwald             uint16_t last_result_handle = 0xffff;
157039ac9711SMatthias Ringwald             if (pair_size > 2) {
15713deb3ec6SMatthias Ringwald                 uint16_t offset;
15723deb3ec6SMatthias Ringwald                 for (offset = 2; offset < size; offset += pair_size) {
1573f8fbdce0SMatthias Ringwald                     uint16_t value_handle = little_endian_read_16(packet, offset);
1574cf8e5718SMatthias Ringwald                     report_gatt_characteristic_value(gatt_client, value_handle, &packet[offset + 2u],
1575cf8e5718SMatthias Ringwald                                                      pair_size - 2u);
15763deb3ec6SMatthias Ringwald                     last_result_handle = value_handle;
15773deb3ec6SMatthias Ringwald                 }
157839ac9711SMatthias Ringwald             }
15795cf1669fSMatthias Ringwald             trigger_next_read_by_type_query(gatt_client, last_result_handle);
15803deb3ec6SMatthias Ringwald             break;
15813deb3ec6SMatthias Ringwald         }
15823deb3ec6SMatthias Ringwald         default:
15833deb3ec6SMatthias Ringwald             break;
15843deb3ec6SMatthias Ringwald     }
158539ac9711SMatthias Ringwald }
1586dc13fd8dSMatthias Ringwald 
15872da0d963SMatthias Ringwald static void gatt_client_handle_att_write_response(gatt_client_t *gatt_client) {
15882da0d963SMatthias Ringwald     switch (gatt_client->gatt_client_state) {
15892da0d963SMatthias Ringwald         case P_W4_WRITE_CHARACTERISTIC_VALUE_RESULT:
15905cf1669fSMatthias Ringwald             gatt_client_handle_transaction_complete(gatt_client);
15915cf1669fSMatthias Ringwald             emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
15923deb3ec6SMatthias Ringwald             break;
15932da0d963SMatthias Ringwald         case P_W4_CLIENT_CHARACTERISTIC_CONFIGURATION_RESULT:
15945cf1669fSMatthias Ringwald             gatt_client_handle_transaction_complete(gatt_client);
15955cf1669fSMatthias Ringwald             emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
15963deb3ec6SMatthias Ringwald             break;
15972da0d963SMatthias Ringwald         case P_W4_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT:
15982da0d963SMatthias Ringwald             gatt_client_handle_transaction_complete(gatt_client);
15992da0d963SMatthias Ringwald             emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
16002da0d963SMatthias Ringwald             break;
16012da0d963SMatthias Ringwald         default:
16022da0d963SMatthias Ringwald             break;
16032da0d963SMatthias Ringwald     }
16042da0d963SMatthias Ringwald }
1605dc13fd8dSMatthias Ringwald 
16062da0d963SMatthias Ringwald static void gatt_client_handle_att_response(gatt_client_t * gatt_client, uint8_t * packet, uint16_t size) {
16072da0d963SMatthias Ringwald     uint8_t error_code;
16082da0d963SMatthias Ringwald     switch (packet[0]) {
16092da0d963SMatthias Ringwald         case ATT_EXCHANGE_MTU_RESPONSE: {
16102da0d963SMatthias Ringwald             if (size < 3u) break;
1611*46012949SMatthias Ringwald             bool update_gatt_server_att_mtu = false;
16122da0d963SMatthias Ringwald             uint16_t remote_rx_mtu = little_endian_read_16(packet, 1);
16132da0d963SMatthias Ringwald             uint16_t local_rx_mtu = l2cap_max_le_mtu();
1614*46012949SMatthias Ringwald             switch (gatt_client->bearer_type){
1615*46012949SMatthias Ringwald                 case ATT_BEARER_UNENHANCED_LE:
1616*46012949SMatthias Ringwald                     update_gatt_server_att_mtu = true;
1617*46012949SMatthias Ringwald                     break;
16182da0d963SMatthias Ringwald #ifdef ENABLE_GATT_OVER_CLASSIC
1619*46012949SMatthias Ringwald                 case ATT_BEARER_UNENHANCED_CLASSIC:
16202da0d963SMatthias Ringwald                     local_rx_mtu = gatt_client->mtu;
1621*46012949SMatthias Ringwald                     break;
16222da0d963SMatthias Ringwald #endif
1623*46012949SMatthias Ringwald                 default:
1624*46012949SMatthias Ringwald                     btstack_unreachable();
1625*46012949SMatthias Ringwald                     break;
1626*46012949SMatthias Ringwald             }
1627*46012949SMatthias Ringwald 
16282da0d963SMatthias Ringwald             uint16_t mtu = (remote_rx_mtu < local_rx_mtu) ? remote_rx_mtu : local_rx_mtu;
16292da0d963SMatthias Ringwald 
16302da0d963SMatthias Ringwald             // set gatt client mtu
16312da0d963SMatthias Ringwald             gatt_client->mtu = mtu;
16322da0d963SMatthias Ringwald             gatt_client->mtu_state = MTU_EXCHANGED;
16332da0d963SMatthias Ringwald 
1634*46012949SMatthias Ringwald             if (update_gatt_server_att_mtu){
16352da0d963SMatthias Ringwald                 // set per connection mtu state - for fixed channel
16362da0d963SMatthias Ringwald                 hci_connection_t *hci_connection = hci_connection_for_handle(gatt_client->con_handle);
16372da0d963SMatthias Ringwald                 hci_connection->att_connection.mtu = gatt_client->mtu;
16382da0d963SMatthias Ringwald                 hci_connection->att_connection.mtu_exchanged = true;
16392da0d963SMatthias Ringwald             }
16402da0d963SMatthias Ringwald             emit_gatt_mtu_exchanged_result_event(gatt_client, gatt_client->mtu);
16412da0d963SMatthias Ringwald             break;
16422da0d963SMatthias Ringwald         }
16432da0d963SMatthias Ringwald         case ATT_READ_BY_GROUP_TYPE_RESPONSE:
16442da0d963SMatthias Ringwald             switch (gatt_client->gatt_client_state) {
16452da0d963SMatthias Ringwald                 case P_W4_SERVICE_QUERY_RESULT:
16462da0d963SMatthias Ringwald                     report_gatt_services(gatt_client, packet, size);
16472da0d963SMatthias Ringwald                     trigger_next_service_query(gatt_client, get_last_result_handle_from_service_list(packet, size));
164830952227SMilanka Ringwald                     // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
164930952227SMilanka Ringwald                     break;
16503deb3ec6SMatthias Ringwald                 default:
16513deb3ec6SMatthias Ringwald                     break;
16523deb3ec6SMatthias Ringwald             }
16533deb3ec6SMatthias Ringwald             break;
16542da0d963SMatthias Ringwald         case ATT_HANDLE_VALUE_NOTIFICATION:
16552da0d963SMatthias Ringwald             if (size < 3u) return;
16562da0d963SMatthias Ringwald             report_gatt_notification(gatt_client, little_endian_read_16(packet, 1u), &packet[3], size - 3u);
16572da0d963SMatthias Ringwald             return;
16582da0d963SMatthias Ringwald         case ATT_HANDLE_VALUE_INDICATION:
16592da0d963SMatthias Ringwald             if (size < 3u) break;
16602da0d963SMatthias Ringwald             report_gatt_indication(gatt_client, little_endian_read_16(packet, 1u), &packet[3], size - 3u);
16612da0d963SMatthias Ringwald             gatt_client->send_confirmation = 1;
16622da0d963SMatthias Ringwald             break;
16632da0d963SMatthias Ringwald         case ATT_READ_BY_TYPE_RESPONSE:
16642da0d963SMatthias Ringwald             gatt_client_handle_att_read_by_type_response(gatt_client, packet, size);
16652da0d963SMatthias Ringwald             break;
16662da0d963SMatthias Ringwald         case ATT_READ_RESPONSE:
16672da0d963SMatthias Ringwald             gatt_client_handle_att_read_response(gatt_client, packet, size);
16682da0d963SMatthias Ringwald             break;
1669cf8e5718SMatthias Ringwald         case ATT_FIND_BY_TYPE_VALUE_RESPONSE: {
16703deb3ec6SMatthias Ringwald             uint8_t pair_size = 4;
16713deb3ec6SMatthias Ringwald             int i;
16723deb3ec6SMatthias Ringwald             uint16_t start_group_handle;
16735611a760SMatthias Ringwald             uint16_t end_group_handle = 0xffff; // asserts GATT_EVENT_QUERY_COMPLETE is emitted if no results
16744ea43905SMatthias Ringwald             for (i = 1u; (i + pair_size) <= size; i += pair_size) {
1675f8fbdce0SMatthias Ringwald                 start_group_handle = little_endian_read_16(packet, i);
1676f8fbdce0SMatthias Ringwald                 end_group_handle = little_endian_read_16(packet, i + 2);
1677cf8e5718SMatthias Ringwald                 emit_gatt_service_query_result_event(gatt_client, start_group_handle, end_group_handle,
1678cf8e5718SMatthias Ringwald                                                      gatt_client->uuid128);
16793deb3ec6SMatthias Ringwald             }
16805cf1669fSMatthias Ringwald             trigger_next_service_by_uuid_query(gatt_client, end_group_handle);
16815611a760SMatthias Ringwald             // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
16823deb3ec6SMatthias Ringwald             break;
16833deb3ec6SMatthias Ringwald         }
1684cf8e5718SMatthias Ringwald         case ATT_FIND_INFORMATION_REPLY: {
16854ea43905SMatthias Ringwald             if (size < 2u) break;
1686a6121b51SMilanka Ringwald 
16873deb3ec6SMatthias Ringwald             uint8_t pair_size = 4;
16884ea43905SMatthias Ringwald             if (packet[1u] == 2u) {
16893deb3ec6SMatthias Ringwald                 pair_size = 18;
16903deb3ec6SMatthias Ringwald             }
1691a6121b51SMilanka Ringwald             uint16_t offset = 2;
1692a6121b51SMilanka Ringwald 
1693a6121b51SMilanka Ringwald             if (size < (pair_size + offset)) break;
1694f8fbdce0SMatthias Ringwald             uint16_t last_descriptor_handle = little_endian_read_16(packet, size - pair_size);
1695abdc9fb5SMatthias Ringwald 
1696abdc9fb5SMatthias Ringwald #ifdef ENABLE_GATT_FIND_INFORMATION_FOR_CCC_DISCOVERY
16975cf1669fSMatthias Ringwald             log_info("ENABLE_GATT_FIND_INFORMATION_FOR_CCC_DISCOVERY, state %x", gatt_client->gatt_client_state);
16985cf1669fSMatthias Ringwald             if (gatt_client->gatt_client_state == P_W4_FIND_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY_RESULT){
1699abdc9fb5SMatthias Ringwald                 // iterate over descriptors looking for CCC
1700abdc9fb5SMatthias Ringwald                 if (pair_size == 4){
1701a6121b51SMilanka Ringwald                     while ((offset + 4) <= size){
1702abdc9fb5SMatthias Ringwald                         uint16_t uuid16 = little_endian_read_16(packet, offset + 2);
1703abdc9fb5SMatthias Ringwald                         if (uuid16 == GATT_CLIENT_CHARACTERISTICS_CONFIGURATION){
17045cf1669fSMatthias Ringwald                             gatt_client->client_characteristic_configuration_handle = little_endian_read_16(packet, offset);
17055cf1669fSMatthias Ringwald                             gatt_client->gatt_client_state = P_W2_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION;
17065cf1669fSMatthias Ringwald                             log_info("CCC found %x", gatt_client->client_characteristic_configuration_handle);
1707abdc9fb5SMatthias Ringwald                             break;
1708abdc9fb5SMatthias Ringwald                         }
1709abdc9fb5SMatthias Ringwald                         offset += pair_size;
1710abdc9fb5SMatthias Ringwald                     }
1711abdc9fb5SMatthias Ringwald                 }
17125cf1669fSMatthias Ringwald                 if (is_query_done(gatt_client, last_descriptor_handle)){
1713abdc9fb5SMatthias Ringwald 
1714abdc9fb5SMatthias Ringwald                 } else {
1715abdc9fb5SMatthias Ringwald                     // next
17165cf1669fSMatthias Ringwald                     gatt_client->start_group_handle = last_descriptor_handle + 1;
17175cf1669fSMatthias Ringwald                     gatt_client->gatt_client_state = P_W2_SEND_FIND_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY;
1718abdc9fb5SMatthias Ringwald                 }
1719abdc9fb5SMatthias Ringwald                 break;
1720abdc9fb5SMatthias Ringwald             }
1721abdc9fb5SMatthias Ringwald #endif
17225cf1669fSMatthias Ringwald             report_gatt_all_characteristic_descriptors(gatt_client, &packet[2], size - 2u, pair_size);
17235cf1669fSMatthias Ringwald             trigger_next_characteristic_descriptor_query(gatt_client, last_descriptor_handle);
17245611a760SMatthias Ringwald             // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
17253deb3ec6SMatthias Ringwald             break;
17263deb3ec6SMatthias Ringwald         }
17273deb3ec6SMatthias Ringwald 
17283deb3ec6SMatthias Ringwald         case ATT_WRITE_RESPONSE:
17292da0d963SMatthias Ringwald             gatt_client_handle_att_write_response(gatt_client);
17303deb3ec6SMatthias Ringwald             break;
17313deb3ec6SMatthias Ringwald 
17323deb3ec6SMatthias Ringwald         case ATT_READ_BLOB_RESPONSE: {
17334ea43905SMatthias Ringwald             uint16_t received_blob_length = size - 1u;
17345cf1669fSMatthias Ringwald             switch (gatt_client->gatt_client_state) {
17353deb3ec6SMatthias Ringwald                 case P_W4_READ_BLOB_RESULT:
1736cf8e5718SMatthias Ringwald                     report_gatt_long_characteristic_value_blob(gatt_client, gatt_client->attribute_handle, &packet[1],
1737cf8e5718SMatthias Ringwald                                                                received_blob_length, gatt_client->attribute_offset);
17385cf1669fSMatthias Ringwald                     trigger_next_blob_query(gatt_client, P_W2_SEND_READ_BLOB_QUERY, received_blob_length);
17395611a760SMatthias Ringwald                     // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
17403deb3ec6SMatthias Ringwald                     break;
17413deb3ec6SMatthias Ringwald                 case P_W4_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_RESULT:
17425cf1669fSMatthias Ringwald                     report_gatt_long_characteristic_descriptor(gatt_client, gatt_client->attribute_handle,
17433deb3ec6SMatthias Ringwald                                                                &packet[1], received_blob_length,
17445cf1669fSMatthias Ringwald                                                                gatt_client->attribute_offset);
1745cf8e5718SMatthias Ringwald                     trigger_next_blob_query(gatt_client, P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY,
1746cf8e5718SMatthias Ringwald                                             received_blob_length);
17475611a760SMatthias Ringwald                     // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
17483deb3ec6SMatthias Ringwald                     break;
17493deb3ec6SMatthias Ringwald                 default:
17503deb3ec6SMatthias Ringwald                     break;
17513deb3ec6SMatthias Ringwald             }
17523deb3ec6SMatthias Ringwald             break;
17533deb3ec6SMatthias Ringwald         }
17543deb3ec6SMatthias Ringwald         case ATT_PREPARE_WRITE_RESPONSE:
17555cf1669fSMatthias Ringwald             switch (gatt_client->gatt_client_state) {
17563deb3ec6SMatthias Ringwald                 case P_W4_PREPARE_WRITE_SINGLE_RESULT:
17575cf1669fSMatthias Ringwald                     gatt_client_handle_transaction_complete(gatt_client);
17585cf1669fSMatthias Ringwald                     if (is_value_valid(gatt_client, packet, size)) {
17595cf1669fSMatthias Ringwald                         emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
17603deb3ec6SMatthias Ringwald                     } else {
17615cf1669fSMatthias Ringwald                         emit_gatt_complete_event(gatt_client, ATT_ERROR_DATA_MISMATCH);
17623deb3ec6SMatthias Ringwald                     }
17633deb3ec6SMatthias Ringwald                     break;
17643deb3ec6SMatthias Ringwald 
17653deb3ec6SMatthias Ringwald                 case P_W4_PREPARE_WRITE_RESULT: {
17665cf1669fSMatthias Ringwald                     gatt_client->attribute_offset = little_endian_read_16(packet, 3);
17675cf1669fSMatthias Ringwald                     trigger_next_prepare_write_query(gatt_client, P_W2_PREPARE_WRITE, P_W2_EXECUTE_PREPARED_WRITE);
17685611a760SMatthias Ringwald                     // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
17693deb3ec6SMatthias Ringwald                     break;
17703deb3ec6SMatthias Ringwald                 }
17713deb3ec6SMatthias Ringwald                 case P_W4_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT: {
17725cf1669fSMatthias Ringwald                     gatt_client->attribute_offset = little_endian_read_16(packet, 3);
1773cf8e5718SMatthias Ringwald                     trigger_next_prepare_write_query(gatt_client, P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR,
1774cf8e5718SMatthias Ringwald                                                      P_W2_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR);
17755611a760SMatthias Ringwald                     // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
17763deb3ec6SMatthias Ringwald                     break;
17773deb3ec6SMatthias Ringwald                 }
17783deb3ec6SMatthias Ringwald                 case P_W4_PREPARE_RELIABLE_WRITE_RESULT: {
17795cf1669fSMatthias Ringwald                     if (is_value_valid(gatt_client, packet, size)) {
17805cf1669fSMatthias Ringwald                         gatt_client->attribute_offset = little_endian_read_16(packet, 3);
1781cf8e5718SMatthias Ringwald                         trigger_next_prepare_write_query(gatt_client, P_W2_PREPARE_RELIABLE_WRITE,
1782cf8e5718SMatthias Ringwald                                                          P_W2_EXECUTE_PREPARED_WRITE);
17835611a760SMatthias Ringwald                         // GATT_EVENT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
17843deb3ec6SMatthias Ringwald                         break;
17853deb3ec6SMatthias Ringwald                     }
17865cf1669fSMatthias Ringwald                     gatt_client->gatt_client_state = P_W2_CANCEL_PREPARED_WRITE_DATA_MISMATCH;
17873deb3ec6SMatthias Ringwald                     break;
17883deb3ec6SMatthias Ringwald                 }
17893deb3ec6SMatthias Ringwald                 default:
17903deb3ec6SMatthias Ringwald                     break;
17913deb3ec6SMatthias Ringwald             }
17923deb3ec6SMatthias Ringwald             break;
17933deb3ec6SMatthias Ringwald 
17943deb3ec6SMatthias Ringwald         case ATT_EXECUTE_WRITE_RESPONSE:
17955cf1669fSMatthias Ringwald             switch (gatt_client->gatt_client_state) {
17963deb3ec6SMatthias Ringwald                 case P_W4_EXECUTE_PREPARED_WRITE_RESULT:
17975cf1669fSMatthias Ringwald                     gatt_client_handle_transaction_complete(gatt_client);
17985cf1669fSMatthias Ringwald                     emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
17993deb3ec6SMatthias Ringwald                     break;
18003deb3ec6SMatthias Ringwald                 case P_W4_CANCEL_PREPARED_WRITE_RESULT:
18015cf1669fSMatthias Ringwald                     gatt_client_handle_transaction_complete(gatt_client);
18025cf1669fSMatthias Ringwald                     emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
18033deb3ec6SMatthias Ringwald                     break;
18043deb3ec6SMatthias Ringwald                 case P_W4_CANCEL_PREPARED_WRITE_DATA_MISMATCH_RESULT:
18055cf1669fSMatthias Ringwald                     gatt_client_handle_transaction_complete(gatt_client);
18065cf1669fSMatthias Ringwald                     emit_gatt_complete_event(gatt_client, ATT_ERROR_DATA_MISMATCH);
18073deb3ec6SMatthias Ringwald                     break;
18083deb3ec6SMatthias Ringwald                 case P_W4_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT:
18095cf1669fSMatthias Ringwald                     gatt_client_handle_transaction_complete(gatt_client);
18105cf1669fSMatthias Ringwald                     emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
18113deb3ec6SMatthias Ringwald                     break;
18123deb3ec6SMatthias Ringwald                 default:
18133deb3ec6SMatthias Ringwald                     break;
18143deb3ec6SMatthias Ringwald 
18153deb3ec6SMatthias Ringwald             }
18163deb3ec6SMatthias Ringwald             break;
18173deb3ec6SMatthias Ringwald 
18183deb3ec6SMatthias Ringwald         case ATT_READ_MULTIPLE_RESPONSE:
18195cf1669fSMatthias Ringwald             switch (gatt_client->gatt_client_state) {
18203deb3ec6SMatthias Ringwald                 case P_W4_READ_MULTIPLE_RESPONSE:
18215cf1669fSMatthias Ringwald                     report_gatt_characteristic_value(gatt_client, 0u, &packet[1], size - 1u);
18225cf1669fSMatthias Ringwald                     gatt_client_handle_transaction_complete(gatt_client);
18235cf1669fSMatthias Ringwald                     emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
18243deb3ec6SMatthias Ringwald                     break;
18253deb3ec6SMatthias Ringwald                 default:
18263deb3ec6SMatthias Ringwald                     break;
18273deb3ec6SMatthias Ringwald             }
18283deb3ec6SMatthias Ringwald             break;
18293deb3ec6SMatthias Ringwald 
18303deb3ec6SMatthias Ringwald         case ATT_ERROR_RESPONSE:
18314ea43905SMatthias Ringwald             if (size < 5u) return;
1832f060f108SMatthias Ringwald             error_code = packet[4];
1833f060f108SMatthias Ringwald             switch (error_code) {
18343deb3ec6SMatthias Ringwald                 case ATT_ERROR_ATTRIBUTE_NOT_FOUND: {
18355cf1669fSMatthias Ringwald                     switch (gatt_client->gatt_client_state) {
18363deb3ec6SMatthias Ringwald                         case P_W4_SERVICE_QUERY_RESULT:
18373deb3ec6SMatthias Ringwald                         case P_W4_SERVICE_WITH_UUID_RESULT:
18383deb3ec6SMatthias Ringwald                         case P_W4_INCLUDED_SERVICE_QUERY_RESULT:
18393deb3ec6SMatthias Ringwald                         case P_W4_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT:
18405cf1669fSMatthias Ringwald                             gatt_client_handle_transaction_complete(gatt_client);
18415cf1669fSMatthias Ringwald                             emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
18423deb3ec6SMatthias Ringwald                             break;
18433deb3ec6SMatthias Ringwald                         case P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT:
18443deb3ec6SMatthias Ringwald                         case P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT:
18455cf1669fSMatthias Ringwald                             characteristic_end_found(gatt_client, gatt_client->end_group_handle);
18465cf1669fSMatthias Ringwald                             gatt_client_handle_transaction_complete(gatt_client);
18475cf1669fSMatthias Ringwald                             emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
18483deb3ec6SMatthias Ringwald                             break;
18493deb3ec6SMatthias Ringwald                         case P_W4_READ_BY_TYPE_RESPONSE:
18505cf1669fSMatthias Ringwald                             gatt_client_handle_transaction_complete(gatt_client);
18515cf1669fSMatthias Ringwald                             if (gatt_client->start_group_handle == gatt_client->query_start_handle) {
18525cf1669fSMatthias Ringwald                                 emit_gatt_complete_event(gatt_client, ATT_ERROR_ATTRIBUTE_NOT_FOUND);
18533deb3ec6SMatthias Ringwald                             } else {
18545cf1669fSMatthias Ringwald                                 emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
18553deb3ec6SMatthias Ringwald                             }
18563deb3ec6SMatthias Ringwald                             break;
18573deb3ec6SMatthias Ringwald                         default:
1858f060f108SMatthias Ringwald                             gatt_client_report_error_if_pending(gatt_client, error_code);
18593deb3ec6SMatthias Ringwald                             break;
18603deb3ec6SMatthias Ringwald                     }
18613deb3ec6SMatthias Ringwald                     break;
18623deb3ec6SMatthias Ringwald                 }
1863f4b33574SMatthias Ringwald 
1864f4b33574SMatthias Ringwald #ifdef ENABLE_GATT_CLIENT_PAIRING
1865f4b33574SMatthias Ringwald 
1866f4b33574SMatthias Ringwald                     case ATT_ERROR_INSUFFICIENT_AUTHENTICATION:
1867f4b33574SMatthias Ringwald                     case ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE:
1868a0e0c2beSMatthias Ringwald                     case ATT_ERROR_INSUFFICIENT_ENCRYPTION: {
1869a0e0c2beSMatthias Ringwald 
1870f4b33574SMatthias Ringwald                         // security too low
18715cf1669fSMatthias Ringwald                         if (gatt_client->security_counter > 0) {
1872f060f108SMatthias Ringwald                             gatt_client_report_error_if_pending(gatt_client, error_code);
1873f4b33574SMatthias Ringwald                             break;
1874f4b33574SMatthias Ringwald                         }
1875f4b33574SMatthias Ringwald                         // start security
18765cf1669fSMatthias Ringwald                         gatt_client->security_counter++;
1877f4b33574SMatthias Ringwald 
1878f4b33574SMatthias Ringwald                         // setup action
1879f4b33574SMatthias Ringwald                         int retry = 1;
18805cf1669fSMatthias Ringwald                         switch (gatt_client->gatt_client_state){
1881f4b33574SMatthias Ringwald                             case P_W4_READ_CHARACTERISTIC_VALUE_RESULT:
18825cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_SEND_READ_CHARACTERISTIC_VALUE_QUERY ;
1883f4b33574SMatthias Ringwald                                 break;
1884f4b33574SMatthias Ringwald                             case P_W4_READ_BLOB_RESULT:
18855cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_SEND_READ_BLOB_QUERY;
1886f4b33574SMatthias Ringwald                                 break;
1887f4b33574SMatthias Ringwald                             case P_W4_READ_BY_TYPE_RESPONSE:
18885cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_SEND_READ_BY_TYPE_REQUEST;
1889f4b33574SMatthias Ringwald                                 break;
1890f4b33574SMatthias Ringwald                             case P_W4_READ_MULTIPLE_RESPONSE:
18915cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_SEND_READ_MULTIPLE_REQUEST;
1892f4b33574SMatthias Ringwald                                 break;
1893f4b33574SMatthias Ringwald                             case P_W4_WRITE_CHARACTERISTIC_VALUE_RESULT:
18945cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_SEND_WRITE_CHARACTERISTIC_VALUE;
1895f4b33574SMatthias Ringwald                                 break;
1896f4b33574SMatthias Ringwald                             case P_W4_PREPARE_WRITE_RESULT:
18975cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_PREPARE_WRITE;
1898f4b33574SMatthias Ringwald                                 break;
1899f4b33574SMatthias Ringwald                             case P_W4_PREPARE_WRITE_SINGLE_RESULT:
19005cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_PREPARE_WRITE_SINGLE;
1901f4b33574SMatthias Ringwald                                 break;
1902f4b33574SMatthias Ringwald                             case P_W4_PREPARE_RELIABLE_WRITE_RESULT:
19035cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_PREPARE_RELIABLE_WRITE;
1904f4b33574SMatthias Ringwald                                 break;
1905f4b33574SMatthias Ringwald                             case P_W4_EXECUTE_PREPARED_WRITE_RESULT:
19065cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_EXECUTE_PREPARED_WRITE;
1907f4b33574SMatthias Ringwald                                 break;
1908f4b33574SMatthias Ringwald                             case P_W4_CANCEL_PREPARED_WRITE_RESULT:
19095cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_CANCEL_PREPARED_WRITE;
1910f4b33574SMatthias Ringwald                                 break;
1911f4b33574SMatthias Ringwald                             case P_W4_CANCEL_PREPARED_WRITE_DATA_MISMATCH_RESULT:
19125cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_CANCEL_PREPARED_WRITE_DATA_MISMATCH;
1913f4b33574SMatthias Ringwald                                 break;
1914f4b33574SMatthias Ringwald                             case P_W4_READ_CHARACTERISTIC_DESCRIPTOR_RESULT:
19155cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_SEND_READ_CHARACTERISTIC_DESCRIPTOR_QUERY;
1916f4b33574SMatthias Ringwald                                 break;
1917f4b33574SMatthias Ringwald                             case P_W4_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_RESULT:
19185cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY;
1919f4b33574SMatthias Ringwald                                 break;
1920f4b33574SMatthias Ringwald                             case P_W4_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT:
19215cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_SEND_WRITE_CHARACTERISTIC_DESCRIPTOR;
1922f4b33574SMatthias Ringwald                                 break;
1923f4b33574SMatthias Ringwald                             case P_W4_CLIENT_CHARACTERISTIC_CONFIGURATION_RESULT:
19245cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION;
1925f4b33574SMatthias Ringwald                                 break;
1926f4b33574SMatthias Ringwald                             case P_W4_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT:
19275cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR;
1928f4b33574SMatthias Ringwald                                 break;
1929f4b33574SMatthias Ringwald                             case P_W4_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT:
19305cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR;
1931f4b33574SMatthias Ringwald                                 break;
1932f4b33574SMatthias Ringwald #ifdef ENABLE_LE_SIGNED_WRITE
1933f4b33574SMatthias Ringwald                             case P_W4_SEND_SINGED_WRITE_DONE:
19345cf1669fSMatthias Ringwald                                 gatt_client->gatt_client_state = P_W2_SEND_SIGNED_WRITE;
1935f4b33574SMatthias Ringwald                                 break;
1936f4b33574SMatthias Ringwald #endif
1937f4b33574SMatthias Ringwald                             default:
19385cf1669fSMatthias Ringwald                                 log_info("retry not supported for state %x", gatt_client->gatt_client_state);
1939f4b33574SMatthias Ringwald                                 retry = 0;
1940f4b33574SMatthias Ringwald                                 break;
1941f4b33574SMatthias Ringwald                         }
1942f4b33574SMatthias Ringwald 
1943f4b33574SMatthias Ringwald                         if (!retry) {
1944f060f108SMatthias Ringwald                             gatt_client_report_error_if_pending(gatt_client, error_code);
1945f4b33574SMatthias Ringwald                             break;
1946f4b33574SMatthias Ringwald                         }
1947f4b33574SMatthias Ringwald 
1948f4b33574SMatthias Ringwald                         log_info("security error, start pairing");
1949f4b33574SMatthias Ringwald 
1950f060f108SMatthias Ringwald                         // start pairing for higher security level
19513503dc74SMatthias Ringwald                         gatt_client->wait_for_authentication_complete = 1;
1952f060f108SMatthias Ringwald                         gatt_client->pending_error_code = error_code;
19535cf1669fSMatthias Ringwald                         sm_request_pairing(gatt_client->con_handle);
1954f4b33574SMatthias Ringwald                         break;
1955a0e0c2beSMatthias Ringwald                     }
1956f4b33574SMatthias Ringwald #endif
1957f4b33574SMatthias Ringwald 
1958f4b33574SMatthias Ringwald                     // nothing we can do about that
1959f4b33574SMatthias Ringwald                 case ATT_ERROR_INSUFFICIENT_AUTHORIZATION:
19603deb3ec6SMatthias Ringwald                 default:
1961f060f108SMatthias Ringwald                     gatt_client_report_error_if_pending(gatt_client, error_code);
19623deb3ec6SMatthias Ringwald                     break;
19633deb3ec6SMatthias Ringwald             }
19643deb3ec6SMatthias Ringwald             break;
19653deb3ec6SMatthias Ringwald 
19663deb3ec6SMatthias Ringwald         default:
19673deb3ec6SMatthias Ringwald             log_info("ATT Handler, unhandled response type 0x%02x", packet[0]);
19683deb3ec6SMatthias Ringwald             break;
19693deb3ec6SMatthias Ringwald     }
1970cf8e5718SMatthias Ringwald }
1971cf8e5718SMatthias Ringwald 
1972cf8e5718SMatthias Ringwald static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size) {
1973cf8e5718SMatthias Ringwald     gatt_client_t *gatt_client;
1974cf8e5718SMatthias Ringwald     if (size < 1u) return;
1975cf8e5718SMatthias Ringwald 
1976cf8e5718SMatthias Ringwald     if (packet_type == HCI_EVENT_PACKET) {
1977cf8e5718SMatthias Ringwald         switch (packet[0]) {
1978cf8e5718SMatthias Ringwald             case L2CAP_EVENT_CAN_SEND_NOW:
19793deb3ec6SMatthias Ringwald                 gatt_client_run();
1980cf8e5718SMatthias Ringwald                 break;
1981cf8e5718SMatthias Ringwald                 // att_server has negotiated the mtu for this connection, cache if context exists
1982cf8e5718SMatthias Ringwald             case ATT_EVENT_MTU_EXCHANGE_COMPLETE:
1983cf8e5718SMatthias Ringwald                 if (size < 6u) break;
1984cf8e5718SMatthias Ringwald                 gatt_client = gatt_client_get_context_for_handle(handle);
1985cf8e5718SMatthias Ringwald                 if (gatt_client == NULL) break;
1986cf8e5718SMatthias Ringwald                 gatt_client->mtu = little_endian_read_16(packet, 4);
1987cf8e5718SMatthias Ringwald                 break;
1988cf8e5718SMatthias Ringwald             default:
1989cf8e5718SMatthias Ringwald                 break;
1990cf8e5718SMatthias Ringwald         }
1991cf8e5718SMatthias Ringwald         return;
1992cf8e5718SMatthias Ringwald     }
1993cf8e5718SMatthias Ringwald 
1994cf8e5718SMatthias Ringwald     if (packet_type != ATT_DATA_PACKET) return;
1995cf8e5718SMatthias Ringwald 
1996cf8e5718SMatthias Ringwald     // special cases: notifications & indications motivate creating context
1997cf8e5718SMatthias Ringwald     switch (packet[0]) {
1998cf8e5718SMatthias Ringwald         case ATT_HANDLE_VALUE_NOTIFICATION:
1999cf8e5718SMatthias Ringwald         case ATT_HANDLE_VALUE_INDICATION:
2000cf8e5718SMatthias Ringwald             gatt_client_provide_context_for_handle(handle, &gatt_client);
2001cf8e5718SMatthias Ringwald             break;
2002cf8e5718SMatthias Ringwald         default:
2003cf8e5718SMatthias Ringwald             gatt_client = gatt_client_get_context_for_handle(handle);
2004cf8e5718SMatthias Ringwald             break;
2005cf8e5718SMatthias Ringwald     }
2006cf8e5718SMatthias Ringwald 
2007cf8e5718SMatthias Ringwald     if (gatt_client != NULL) {
2008cf8e5718SMatthias Ringwald         gatt_client_handle_att_response(gatt_client, packet, size);
2009cf8e5718SMatthias Ringwald         gatt_client_run();
2010cf8e5718SMatthias Ringwald     }
20113deb3ec6SMatthias Ringwald }
20123deb3ec6SMatthias Ringwald 
20137a766ebfSMatthias Ringwald #ifdef ENABLE_LE_SIGNED_WRITE
20143deb3ec6SMatthias Ringwald static void att_signed_write_handle_cmac_result(uint8_t hash[8]){
2015665d90f2SMatthias Ringwald     btstack_linked_list_iterator_t it;
2016665d90f2SMatthias Ringwald     btstack_linked_list_iterator_init(&it, &gatt_client_connections);
2017665d90f2SMatthias Ringwald     while (btstack_linked_list_iterator_has_next(&it)){
20185cf1669fSMatthias Ringwald         gatt_client_t * gatt_client = (gatt_client_t *) btstack_linked_list_iterator_next(&it);
20195cf1669fSMatthias Ringwald         if (gatt_client->gatt_client_state == P_W4_CMAC_RESULT){
20203deb3ec6SMatthias Ringwald             // store result
20215cf1669fSMatthias Ringwald             (void)memcpy(gatt_client->cmac, hash, 8);
20225cf1669fSMatthias Ringwald             // reverse_64(hash, gatt_client->cmac);
20235cf1669fSMatthias Ringwald             gatt_client->gatt_client_state = P_W2_SEND_SIGNED_WRITE;
20243deb3ec6SMatthias Ringwald             gatt_client_run();
20253deb3ec6SMatthias Ringwald             return;
20263deb3ec6SMatthias Ringwald         }
20273deb3ec6SMatthias Ringwald     }
20283deb3ec6SMatthias Ringwald }
20293deb3ec6SMatthias Ringwald 
2030b45b7749SMilanka Ringwald uint8_t gatt_client_signed_write_without_response(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t message_len, uint8_t * message){
203140faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
203240faeb84SMilanka Ringwald     uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client);
203340faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
203440faeb84SMilanka Ringwald         return status;
203540faeb84SMilanka Ringwald     }
203640faeb84SMilanka Ringwald     if (is_ready(gatt_client) == 0){
203740faeb84SMilanka Ringwald         return GATT_CLIENT_IN_WRONG_STATE;
203840faeb84SMilanka Ringwald     }
20393deb3ec6SMatthias Ringwald 
20405cf1669fSMatthias Ringwald     gatt_client->callback = callback;
2041b45b7749SMilanka Ringwald     gatt_client->attribute_handle = value_handle;
20425cf1669fSMatthias Ringwald     gatt_client->attribute_length = message_len;
20435cf1669fSMatthias Ringwald     gatt_client->attribute_value = message;
20445cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W4_IDENTITY_RESOLVING;
20453deb3ec6SMatthias Ringwald     gatt_client_run();
204625b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
20473deb3ec6SMatthias Ringwald }
20487a766ebfSMatthias Ringwald #endif
20493deb3ec6SMatthias Ringwald 
2050711e6c80SMatthias Ringwald uint8_t gatt_client_discover_primary_services(btstack_packet_handler_t callback, hci_con_handle_t con_handle){
205140faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2052de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
205340faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
205440faeb84SMilanka Ringwald         return status;
205540faeb84SMilanka Ringwald     }
20563deb3ec6SMatthias Ringwald 
20575cf1669fSMatthias Ringwald     gatt_client->callback = callback;
20585cf1669fSMatthias Ringwald     gatt_client->start_group_handle = 0x0001;
20595cf1669fSMatthias Ringwald     gatt_client->end_group_handle   = 0xffff;
20605cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_SERVICE_QUERY;
20618d1f34d3SMatheus Eduardo Garbelini     gatt_client->uuid16 = GATT_PRIMARY_SERVICE_UUID;
20623deb3ec6SMatthias Ringwald     gatt_client_run();
206325b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
20643deb3ec6SMatthias Ringwald }
20653deb3ec6SMatthias Ringwald 
20668d1f34d3SMatheus Eduardo Garbelini uint8_t gatt_client_discover_secondary_services(btstack_packet_handler_t callback, hci_con_handle_t con_handle){
206740faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2068de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
206940faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
207040faeb84SMilanka Ringwald         return status;
207140faeb84SMilanka Ringwald     }
20728d1f34d3SMatheus Eduardo Garbelini 
20738d1f34d3SMatheus Eduardo Garbelini     gatt_client->callback = callback;
20748d1f34d3SMatheus Eduardo Garbelini     gatt_client->start_group_handle = 0x0001;
20758d1f34d3SMatheus Eduardo Garbelini     gatt_client->end_group_handle   = 0xffff;
20768d1f34d3SMatheus Eduardo Garbelini     gatt_client->gatt_client_state = P_W2_SEND_SERVICE_QUERY;
20778d1f34d3SMatheus Eduardo Garbelini     gatt_client->uuid16 = GATT_SECONDARY_SERVICE_UUID;
20788d1f34d3SMatheus Eduardo Garbelini     gatt_client_run();
20798d1f34d3SMatheus Eduardo Garbelini     return ERROR_CODE_SUCCESS;
20808d1f34d3SMatheus Eduardo Garbelini }
20813deb3ec6SMatthias Ringwald 
2082711e6c80SMatthias Ringwald uint8_t gatt_client_discover_primary_services_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t uuid16){
208340faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2084de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
208540faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
208640faeb84SMilanka Ringwald         return status;
208740faeb84SMilanka Ringwald     }
20883deb3ec6SMatthias Ringwald 
20895cf1669fSMatthias Ringwald     gatt_client->callback = callback;
20905cf1669fSMatthias Ringwald     gatt_client->start_group_handle = 0x0001;
20915cf1669fSMatthias Ringwald     gatt_client->end_group_handle   = 0xffff;
20925cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_SERVICE_WITH_UUID_QUERY;
20935cf1669fSMatthias Ringwald     gatt_client->uuid16 = uuid16;
20945cf1669fSMatthias Ringwald     uuid_add_bluetooth_prefix((uint8_t*) &(gatt_client->uuid128), gatt_client->uuid16);
20953deb3ec6SMatthias Ringwald     gatt_client_run();
209625b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
20973deb3ec6SMatthias Ringwald }
20983deb3ec6SMatthias Ringwald 
2099711e6c80SMatthias Ringwald uint8_t gatt_client_discover_primary_services_by_uuid128(btstack_packet_handler_t callback, hci_con_handle_t con_handle, const uint8_t * uuid128){
210040faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2101de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
210240faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
210340faeb84SMilanka Ringwald         return status;
210440faeb84SMilanka Ringwald     }
21053deb3ec6SMatthias Ringwald 
21065cf1669fSMatthias Ringwald     gatt_client->callback = callback;
21075cf1669fSMatthias Ringwald     gatt_client->start_group_handle = 0x0001;
21085cf1669fSMatthias Ringwald     gatt_client->end_group_handle   = 0xffff;
21095cf1669fSMatthias Ringwald     gatt_client->uuid16 = 0;
21105cf1669fSMatthias Ringwald     (void)memcpy(gatt_client->uuid128, uuid128, 16);
21115cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_SERVICE_WITH_UUID_QUERY;
21123deb3ec6SMatthias Ringwald     gatt_client_run();
211325b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
21143deb3ec6SMatthias Ringwald }
21153deb3ec6SMatthias Ringwald 
2116711e6c80SMatthias Ringwald uint8_t gatt_client_discover_characteristics_for_service(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_service_t * service){
211740faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2118de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
211940faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
212040faeb84SMilanka Ringwald         return status;
212140faeb84SMilanka Ringwald     }
21223deb3ec6SMatthias Ringwald 
21235cf1669fSMatthias Ringwald     gatt_client->callback = callback;
21245cf1669fSMatthias Ringwald     gatt_client->start_group_handle = service->start_group_handle;
21255cf1669fSMatthias Ringwald     gatt_client->end_group_handle   = service->end_group_handle;
21265cf1669fSMatthias Ringwald     gatt_client->filter_with_uuid = 0;
21275cf1669fSMatthias Ringwald     gatt_client->characteristic_start_handle = 0;
21285cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_ALL_CHARACTERISTICS_OF_SERVICE_QUERY;
21293deb3ec6SMatthias Ringwald     gatt_client_run();
213025b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
21313deb3ec6SMatthias Ringwald }
21323deb3ec6SMatthias Ringwald 
2133711e6c80SMatthias Ringwald uint8_t gatt_client_find_included_services_for_service(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_service_t * service){
213440faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2135de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
213640faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
213740faeb84SMilanka Ringwald         return status;
213840faeb84SMilanka Ringwald     }
2139de27733dSMatthias Ringwald 
21405cf1669fSMatthias Ringwald     gatt_client->callback = callback;
21415cf1669fSMatthias Ringwald     gatt_client->start_group_handle = service->start_group_handle;
21425cf1669fSMatthias Ringwald     gatt_client->end_group_handle   = service->end_group_handle;
21435cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_INCLUDED_SERVICE_QUERY;
21443deb3ec6SMatthias Ringwald 
21453deb3ec6SMatthias Ringwald     gatt_client_run();
214625b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
21473deb3ec6SMatthias Ringwald }
21483deb3ec6SMatthias Ringwald 
2149711e6c80SMatthias Ringwald uint8_t gatt_client_discover_characteristics_for_handle_range_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){
215040faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2151de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
215240faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
215340faeb84SMilanka Ringwald         return status;
215440faeb84SMilanka Ringwald     }
21553deb3ec6SMatthias Ringwald 
21565cf1669fSMatthias Ringwald     gatt_client->callback = callback;
21575cf1669fSMatthias Ringwald     gatt_client->start_group_handle = start_handle;
21585cf1669fSMatthias Ringwald     gatt_client->end_group_handle   = end_handle;
21595cf1669fSMatthias Ringwald     gatt_client->filter_with_uuid = 1;
21605cf1669fSMatthias Ringwald     gatt_client->uuid16 = uuid16;
21615cf1669fSMatthias Ringwald     uuid_add_bluetooth_prefix((uint8_t*) &(gatt_client->uuid128), uuid16);
21625cf1669fSMatthias Ringwald     gatt_client->characteristic_start_handle = 0;
21635cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_CHARACTERISTIC_WITH_UUID_QUERY;
21643deb3ec6SMatthias Ringwald     gatt_client_run();
216525b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
21663deb3ec6SMatthias Ringwald }
21673deb3ec6SMatthias Ringwald 
2168045d700dSDavid Lechner uint8_t gatt_client_discover_characteristics_for_handle_range_by_uuid128(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128){
216940faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2170de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
217140faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
217240faeb84SMilanka Ringwald         return status;
217340faeb84SMilanka Ringwald     }
21743deb3ec6SMatthias Ringwald 
21755cf1669fSMatthias Ringwald     gatt_client->callback = callback;
21765cf1669fSMatthias Ringwald     gatt_client->start_group_handle = start_handle;
21775cf1669fSMatthias Ringwald     gatt_client->end_group_handle   = end_handle;
21785cf1669fSMatthias Ringwald     gatt_client->filter_with_uuid = 1;
21795cf1669fSMatthias Ringwald     gatt_client->uuid16 = 0;
21805cf1669fSMatthias Ringwald     (void)memcpy(gatt_client->uuid128, uuid128, 16);
21815cf1669fSMatthias Ringwald     gatt_client->characteristic_start_handle = 0;
21825cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_CHARACTERISTIC_WITH_UUID_QUERY;
21833deb3ec6SMatthias Ringwald     gatt_client_run();
218425b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
21853deb3ec6SMatthias Ringwald }
21863deb3ec6SMatthias Ringwald 
21873deb3ec6SMatthias Ringwald 
2188b45b7749SMilanka Ringwald uint8_t gatt_client_discover_characteristics_for_service_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_service_t * service, uint16_t uuid16){
2189b45b7749SMilanka Ringwald     return gatt_client_discover_characteristics_for_handle_range_by_uuid16(callback, con_handle, service->start_group_handle, service->end_group_handle, uuid16);
21903deb3ec6SMatthias Ringwald }
21913deb3ec6SMatthias Ringwald 
2192b45b7749SMilanka Ringwald uint8_t gatt_client_discover_characteristics_for_service_by_uuid128(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_service_t * service, const uint8_t * uuid128){
2193b45b7749SMilanka Ringwald     return gatt_client_discover_characteristics_for_handle_range_by_uuid128(callback, con_handle, service->start_group_handle, service->end_group_handle, uuid128);
21943deb3ec6SMatthias Ringwald }
21953deb3ec6SMatthias Ringwald 
2196711e6c80SMatthias Ringwald uint8_t gatt_client_discover_characteristic_descriptors(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){
219740faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2198de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
219940faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
220040faeb84SMilanka Ringwald         return status;
220140faeb84SMilanka Ringwald     }
22023deb3ec6SMatthias Ringwald 
22033deb3ec6SMatthias Ringwald     if (characteristic->value_handle == characteristic->end_handle){
22045cf1669fSMatthias Ringwald         emit_gatt_complete_event(gatt_client, ATT_ERROR_SUCCESS);
220525b7c058SMilanka Ringwald         return ERROR_CODE_SUCCESS;
22063deb3ec6SMatthias Ringwald     }
22075cf1669fSMatthias Ringwald     gatt_client->callback = callback;
22085cf1669fSMatthias Ringwald     gatt_client->start_group_handle = characteristic->value_handle + 1u;
22095cf1669fSMatthias Ringwald     gatt_client->end_group_handle   = characteristic->end_handle;
22105cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY;
22113deb3ec6SMatthias Ringwald     gatt_client_run();
221225b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
22133deb3ec6SMatthias Ringwald }
22143deb3ec6SMatthias Ringwald 
2215711e6c80SMatthias Ringwald uint8_t gatt_client_read_value_of_characteristic_using_value_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle){
221640faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2217de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
221840faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
221940faeb84SMilanka Ringwald         return status;
222040faeb84SMilanka Ringwald     }
22213deb3ec6SMatthias Ringwald 
22225cf1669fSMatthias Ringwald     gatt_client->callback = callback;
22235cf1669fSMatthias Ringwald     gatt_client->attribute_handle = value_handle;
22245cf1669fSMatthias Ringwald     gatt_client->attribute_offset = 0;
22255cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_READ_CHARACTERISTIC_VALUE_QUERY;
22263deb3ec6SMatthias Ringwald     gatt_client_run();
222725b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
22283deb3ec6SMatthias Ringwald }
22293deb3ec6SMatthias Ringwald 
2230711e6c80SMatthias Ringwald uint8_t gatt_client_read_value_of_characteristics_by_uuid16(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){
223140faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2232de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
223340faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
223440faeb84SMilanka Ringwald         return status;
223540faeb84SMilanka Ringwald     }
22363deb3ec6SMatthias Ringwald 
22375cf1669fSMatthias Ringwald     gatt_client->callback = callback;
22385cf1669fSMatthias Ringwald     gatt_client->start_group_handle = start_handle;
22395cf1669fSMatthias Ringwald     gatt_client->end_group_handle = end_handle;
22405cf1669fSMatthias Ringwald     gatt_client->query_start_handle = start_handle;
22415cf1669fSMatthias Ringwald     gatt_client->query_end_handle = end_handle;
22425cf1669fSMatthias Ringwald     gatt_client->uuid16 = uuid16;
22435cf1669fSMatthias Ringwald     uuid_add_bluetooth_prefix((uint8_t*) &(gatt_client->uuid128), uuid16);
22445cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_READ_BY_TYPE_REQUEST;
22453deb3ec6SMatthias Ringwald     gatt_client_run();
224625b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
22473deb3ec6SMatthias Ringwald }
22483deb3ec6SMatthias Ringwald 
2249045d700dSDavid Lechner uint8_t gatt_client_read_value_of_characteristics_by_uuid128(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t start_handle, uint16_t end_handle, const uint8_t * uuid128){
225040faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2251de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
225240faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
225340faeb84SMilanka Ringwald         return status;
225440faeb84SMilanka Ringwald     }
22553deb3ec6SMatthias Ringwald 
22565cf1669fSMatthias Ringwald     gatt_client->callback = callback;
22575cf1669fSMatthias Ringwald     gatt_client->start_group_handle = start_handle;
22585cf1669fSMatthias Ringwald     gatt_client->end_group_handle = end_handle;
22595cf1669fSMatthias Ringwald     gatt_client->query_start_handle = start_handle;
22605cf1669fSMatthias Ringwald     gatt_client->query_end_handle = end_handle;
22615cf1669fSMatthias Ringwald     gatt_client->uuid16 = 0;
22625cf1669fSMatthias Ringwald     (void)memcpy(gatt_client->uuid128, uuid128, 16);
22635cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_READ_BY_TYPE_REQUEST;
22643deb3ec6SMatthias Ringwald     gatt_client_run();
226525b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
22663deb3ec6SMatthias Ringwald }
22673deb3ec6SMatthias Ringwald 
22683deb3ec6SMatthias Ringwald 
2269b45b7749SMilanka Ringwald uint8_t gatt_client_read_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){
2270b45b7749SMilanka Ringwald     return gatt_client_read_value_of_characteristic_using_value_handle(callback, con_handle, characteristic->value_handle);
22713deb3ec6SMatthias Ringwald }
22723deb3ec6SMatthias Ringwald 
2273b45b7749SMilanka Ringwald uint8_t gatt_client_read_long_value_of_characteristic_using_value_handle_with_offset(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t offset){
227440faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2275de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
227640faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
227740faeb84SMilanka Ringwald         return status;
227840faeb84SMilanka Ringwald     }
22793deb3ec6SMatthias Ringwald 
22805cf1669fSMatthias Ringwald     gatt_client->callback = callback;
2281b45b7749SMilanka Ringwald     gatt_client->attribute_handle = value_handle;
22825cf1669fSMatthias Ringwald     gatt_client->attribute_offset = offset;
22835cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_READ_BLOB_QUERY;
22843deb3ec6SMatthias Ringwald     gatt_client_run();
228525b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
22863deb3ec6SMatthias Ringwald }
22873deb3ec6SMatthias Ringwald 
2288b45b7749SMilanka Ringwald uint8_t gatt_client_read_long_value_of_characteristic_using_value_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle){
2289b45b7749SMilanka Ringwald     return gatt_client_read_long_value_of_characteristic_using_value_handle_with_offset(callback, con_handle, value_handle, 0);
22903deb3ec6SMatthias Ringwald }
22913deb3ec6SMatthias Ringwald 
2292b45b7749SMilanka Ringwald uint8_t gatt_client_read_long_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic){
2293b45b7749SMilanka Ringwald     return gatt_client_read_long_value_of_characteristic_using_value_handle(callback, con_handle, characteristic->value_handle);
22943deb3ec6SMatthias Ringwald }
22953deb3ec6SMatthias Ringwald 
2296711e6c80SMatthias Ringwald uint8_t gatt_client_read_multiple_characteristic_values(btstack_packet_handler_t callback, hci_con_handle_t con_handle, int num_value_handles, uint16_t * value_handles){
229740faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2298de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
229940faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
230040faeb84SMilanka Ringwald         return status;
230140faeb84SMilanka Ringwald     }
23023deb3ec6SMatthias Ringwald 
23035cf1669fSMatthias Ringwald     gatt_client->callback = callback;
23045cf1669fSMatthias Ringwald     gatt_client->read_multiple_handle_count = num_value_handles;
23055cf1669fSMatthias Ringwald     gatt_client->read_multiple_handles = value_handles;
23065cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_READ_MULTIPLE_REQUEST;
23073deb3ec6SMatthias Ringwald     gatt_client_run();
230825b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
23093deb3ec6SMatthias Ringwald }
23103deb3ec6SMatthias Ringwald 
2311de9f8e94SMatthias Ringwald uint8_t gatt_client_write_value_of_characteristic_without_response(hci_con_handle_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){
231240faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
231340faeb84SMilanka Ringwald     uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client);
231440faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
231540faeb84SMilanka Ringwald         return status;
231640faeb84SMilanka Ringwald     }
23173deb3ec6SMatthias Ringwald 
2318dda77937SMatthias Ringwald     if (value_length > (gatt_client->mtu - 3u)) return GATT_CLIENT_VALUE_TOO_LONG;
23195cf1669fSMatthias Ringwald     if (!att_dispatch_client_can_send_now(gatt_client->con_handle)) return GATT_CLIENT_BUSY;
23203deb3ec6SMatthias Ringwald 
23216e7b444cSMatthias Ringwald     return att_write_request(gatt_client, ATT_WRITE_COMMAND, value_handle, value_length, value);
23223deb3ec6SMatthias Ringwald }
23233deb3ec6SMatthias Ringwald 
2324b45b7749SMilanka Ringwald uint8_t gatt_client_write_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){
232540faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2326de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
232740faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
232840faeb84SMilanka Ringwald         return status;
232940faeb84SMilanka Ringwald     }
23303deb3ec6SMatthias Ringwald 
23315cf1669fSMatthias Ringwald     gatt_client->callback = callback;
23325cf1669fSMatthias Ringwald     gatt_client->attribute_handle = value_handle;
23335cf1669fSMatthias Ringwald     gatt_client->attribute_length = value_length;
2334b45b7749SMilanka Ringwald     gatt_client->attribute_value = value;
23355cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_WRITE_CHARACTERISTIC_VALUE;
23363deb3ec6SMatthias Ringwald     gatt_client_run();
233725b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
23383deb3ec6SMatthias Ringwald }
23393deb3ec6SMatthias Ringwald 
2340b45b7749SMilanka Ringwald uint8_t gatt_client_write_long_value_of_characteristic_with_offset(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t offset, uint16_t value_length, uint8_t * value){
234140faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2342de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
234340faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
234440faeb84SMilanka Ringwald         return status;
234540faeb84SMilanka Ringwald     }
23463deb3ec6SMatthias Ringwald 
23475cf1669fSMatthias Ringwald     gatt_client->callback = callback;
23485cf1669fSMatthias Ringwald     gatt_client->attribute_handle = value_handle;
23495cf1669fSMatthias Ringwald     gatt_client->attribute_length = value_length;
23505cf1669fSMatthias Ringwald     gatt_client->attribute_offset = offset;
2351b45b7749SMilanka Ringwald     gatt_client->attribute_value = value;
23525cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_PREPARE_WRITE;
23533deb3ec6SMatthias Ringwald     gatt_client_run();
235425b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
23553deb3ec6SMatthias Ringwald }
23563deb3ec6SMatthias Ringwald 
2357711e6c80SMatthias Ringwald uint8_t gatt_client_write_long_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){
23589c662c9bSMatthias Ringwald     return gatt_client_write_long_value_of_characteristic_with_offset(callback, con_handle, value_handle, 0, value_length, value);
23593deb3ec6SMatthias Ringwald }
23603deb3ec6SMatthias Ringwald 
2361711e6c80SMatthias Ringwald uint8_t gatt_client_reliable_write_long_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){
236240faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2363de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
236440faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
236540faeb84SMilanka Ringwald         return status;
236640faeb84SMilanka Ringwald     }
23673deb3ec6SMatthias Ringwald 
23685cf1669fSMatthias Ringwald     gatt_client->callback = callback;
23695cf1669fSMatthias Ringwald     gatt_client->attribute_handle = value_handle;
23705cf1669fSMatthias Ringwald     gatt_client->attribute_length = value_length;
23715cf1669fSMatthias Ringwald     gatt_client->attribute_offset = 0;
23725cf1669fSMatthias Ringwald     gatt_client->attribute_value = value;
23735cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_PREPARE_RELIABLE_WRITE;
23743deb3ec6SMatthias Ringwald     gatt_client_run();
237525b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
23763deb3ec6SMatthias Ringwald }
23773deb3ec6SMatthias Ringwald 
2378711e6c80SMatthias Ringwald uint8_t gatt_client_write_client_characteristic_configuration(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_t * characteristic, uint16_t configuration){
237940faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2380de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
238140faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
238240faeb84SMilanka Ringwald         return status;
238340faeb84SMilanka Ringwald     }
23843deb3ec6SMatthias Ringwald 
23853deb3ec6SMatthias Ringwald     if ( (configuration & GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION) &&
23864ea43905SMatthias Ringwald         ((characteristic->properties & ATT_PROPERTY_NOTIFY) == 0u)) {
2387d8e8f12aSMatthias Ringwald         log_info("gatt_client_write_client_characteristic_configuration: GATT_CLIENT_CHARACTERISTIC_NOTIFICATION_NOT_SUPPORTED");
2388616edd56SMatthias Ringwald         return GATT_CLIENT_CHARACTERISTIC_NOTIFICATION_NOT_SUPPORTED;
23893deb3ec6SMatthias Ringwald     } else if ( (configuration & GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_INDICATION) &&
23904ea43905SMatthias Ringwald                ((characteristic->properties & ATT_PROPERTY_INDICATE) == 0u)){
2391d8e8f12aSMatthias Ringwald         log_info("gatt_client_write_client_characteristic_configuration: GATT_CLIENT_CHARACTERISTIC_INDICATION_NOT_SUPPORTED");
2392616edd56SMatthias Ringwald         return GATT_CLIENT_CHARACTERISTIC_INDICATION_NOT_SUPPORTED;
23933deb3ec6SMatthias Ringwald     }
23943deb3ec6SMatthias Ringwald 
23955cf1669fSMatthias Ringwald     gatt_client->callback = callback;
23965cf1669fSMatthias Ringwald     gatt_client->start_group_handle = characteristic->value_handle;
23975cf1669fSMatthias Ringwald     gatt_client->end_group_handle = characteristic->end_handle;
23985cf1669fSMatthias Ringwald     little_endian_store_16(gatt_client->client_characteristic_configuration_value, 0, configuration);
23993deb3ec6SMatthias Ringwald 
2400abdc9fb5SMatthias Ringwald #ifdef ENABLE_GATT_FIND_INFORMATION_FOR_CCC_DISCOVERY
24015cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_FIND_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY;
2402abdc9fb5SMatthias Ringwald #else
24035cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_READ_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY;
2404abdc9fb5SMatthias Ringwald #endif
24053deb3ec6SMatthias Ringwald     gatt_client_run();
24069cb80b17SMilanka Ringwald     return ERROR_CODE_SUCCESS;
24073deb3ec6SMatthias Ringwald }
24083deb3ec6SMatthias Ringwald 
2409711e6c80SMatthias Ringwald uint8_t gatt_client_read_characteristic_descriptor_using_descriptor_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle){
241040faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2411de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
241240faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
241340faeb84SMilanka Ringwald         return status;
241440faeb84SMilanka Ringwald     }
24153deb3ec6SMatthias Ringwald 
24165cf1669fSMatthias Ringwald     gatt_client->callback = callback;
24175cf1669fSMatthias Ringwald     gatt_client->attribute_handle = descriptor_handle;
24183deb3ec6SMatthias Ringwald 
24195cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_READ_CHARACTERISTIC_DESCRIPTOR_QUERY;
24203deb3ec6SMatthias Ringwald     gatt_client_run();
242125b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
24223deb3ec6SMatthias Ringwald }
24233deb3ec6SMatthias Ringwald 
2424711e6c80SMatthias Ringwald uint8_t gatt_client_read_characteristic_descriptor(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_descriptor_t * descriptor){
24259c662c9bSMatthias Ringwald     return gatt_client_read_characteristic_descriptor_using_descriptor_handle(callback, con_handle, descriptor->handle);
24263deb3ec6SMatthias Ringwald }
24273deb3ec6SMatthias Ringwald 
2428711e6c80SMatthias Ringwald uint8_t gatt_client_read_long_characteristic_descriptor_using_descriptor_handle_with_offset(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle, uint16_t offset){
242940faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2430de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
243140faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
243240faeb84SMilanka Ringwald         return status;
243340faeb84SMilanka Ringwald     }
24343deb3ec6SMatthias Ringwald 
24355cf1669fSMatthias Ringwald     gatt_client->callback = callback;
24365cf1669fSMatthias Ringwald     gatt_client->attribute_handle = descriptor_handle;
24375cf1669fSMatthias Ringwald     gatt_client->attribute_offset = offset;
24385cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY;
24393deb3ec6SMatthias Ringwald     gatt_client_run();
244025b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
24413deb3ec6SMatthias Ringwald }
24423deb3ec6SMatthias Ringwald 
2443711e6c80SMatthias Ringwald uint8_t gatt_client_read_long_characteristic_descriptor_using_descriptor_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle){
24449c662c9bSMatthias Ringwald     return gatt_client_read_long_characteristic_descriptor_using_descriptor_handle_with_offset(callback, con_handle, descriptor_handle, 0);
24453deb3ec6SMatthias Ringwald }
24463deb3ec6SMatthias Ringwald 
2447711e6c80SMatthias Ringwald uint8_t gatt_client_read_long_characteristic_descriptor(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_descriptor_t * descriptor){
24489c662c9bSMatthias Ringwald     return gatt_client_read_long_characteristic_descriptor_using_descriptor_handle(callback, con_handle, descriptor->handle);
24493deb3ec6SMatthias Ringwald }
24503deb3ec6SMatthias Ringwald 
2451b45b7749SMilanka Ringwald uint8_t gatt_client_write_characteristic_descriptor_using_descriptor_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle, uint16_t value_length, uint8_t * value){
245240faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2453de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
245440faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
245540faeb84SMilanka Ringwald         return status;
245640faeb84SMilanka Ringwald     }
24573deb3ec6SMatthias Ringwald 
24585cf1669fSMatthias Ringwald     gatt_client->callback = callback;
24595cf1669fSMatthias Ringwald     gatt_client->attribute_handle = descriptor_handle;
2460b45b7749SMilanka Ringwald     gatt_client->attribute_length = value_length;
24615cf1669fSMatthias Ringwald     gatt_client->attribute_offset = 0;
2462b45b7749SMilanka Ringwald     gatt_client->attribute_value = value;
24635cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SEND_WRITE_CHARACTERISTIC_DESCRIPTOR;
24643deb3ec6SMatthias Ringwald     gatt_client_run();
246525b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
24663deb3ec6SMatthias Ringwald }
24673deb3ec6SMatthias Ringwald 
246848cdff9cSMilanka Ringwald uint8_t gatt_client_write_characteristic_descriptor(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_descriptor_t * descriptor, uint16_t value_length, uint8_t * value){
246948cdff9cSMilanka Ringwald     return gatt_client_write_characteristic_descriptor_using_descriptor_handle(callback, con_handle, descriptor->handle, value_length, value);
24703deb3ec6SMatthias Ringwald }
24713deb3ec6SMatthias Ringwald 
2472b45b7749SMilanka Ringwald uint8_t gatt_client_write_long_characteristic_descriptor_using_descriptor_handle_with_offset(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle, uint16_t offset, uint16_t value_length, uint8_t * value){
247340faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2474de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
247540faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
247640faeb84SMilanka Ringwald         return status;
247740faeb84SMilanka Ringwald     }
24783deb3ec6SMatthias Ringwald 
24795cf1669fSMatthias Ringwald     gatt_client->callback = callback;
24805cf1669fSMatthias Ringwald     gatt_client->attribute_handle = descriptor_handle;
2481b45b7749SMilanka Ringwald     gatt_client->attribute_length = value_length;
24825cf1669fSMatthias Ringwald     gatt_client->attribute_offset = offset;
2483b45b7749SMilanka Ringwald     gatt_client->attribute_value = value;
24845cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR;
24853deb3ec6SMatthias Ringwald     gatt_client_run();
248625b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
24873deb3ec6SMatthias Ringwald }
24883deb3ec6SMatthias Ringwald 
2489b45b7749SMilanka Ringwald uint8_t gatt_client_write_long_characteristic_descriptor_using_descriptor_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t descriptor_handle, uint16_t value_length, uint8_t * value){
2490b45b7749SMilanka Ringwald     return gatt_client_write_long_characteristic_descriptor_using_descriptor_handle_with_offset(callback, con_handle, descriptor_handle, 0, value_length, value);
24913deb3ec6SMatthias Ringwald }
24923deb3ec6SMatthias Ringwald 
2493b45b7749SMilanka Ringwald uint8_t gatt_client_write_long_characteristic_descriptor(btstack_packet_handler_t callback, hci_con_handle_t con_handle, gatt_client_characteristic_descriptor_t * descriptor, uint16_t value_length, uint8_t * value){
2494b45b7749SMilanka Ringwald     return gatt_client_write_long_characteristic_descriptor_using_descriptor_handle(callback, con_handle, descriptor->handle, value_length, value);
24953deb3ec6SMatthias Ringwald }
24963deb3ec6SMatthias Ringwald 
24973deb3ec6SMatthias Ringwald /**
24983deb3ec6SMatthias Ringwald  * @brief -> gatt complete event
24993deb3ec6SMatthias Ringwald  */
2500b45b7749SMilanka Ringwald uint8_t gatt_client_prepare_write(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint16_t value_length, uint8_t * value){
250140faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2502de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
250340faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
250440faeb84SMilanka Ringwald         return status;
250540faeb84SMilanka Ringwald     }
25063deb3ec6SMatthias Ringwald 
25075cf1669fSMatthias Ringwald     gatt_client->callback = callback;
25085cf1669fSMatthias Ringwald     gatt_client->attribute_handle = attribute_handle;
2509b45b7749SMilanka Ringwald     gatt_client->attribute_length = value_length;
25105cf1669fSMatthias Ringwald     gatt_client->attribute_offset = offset;
2511b45b7749SMilanka Ringwald     gatt_client->attribute_value = value;
25125cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_PREPARE_WRITE_SINGLE;
25133deb3ec6SMatthias Ringwald     gatt_client_run();
251425b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
25153deb3ec6SMatthias Ringwald }
25163deb3ec6SMatthias Ringwald 
25173deb3ec6SMatthias Ringwald /**
25183deb3ec6SMatthias Ringwald  * @brief -> gatt complete event
25193deb3ec6SMatthias Ringwald  */
2520711e6c80SMatthias Ringwald uint8_t gatt_client_execute_write(btstack_packet_handler_t callback, hci_con_handle_t con_handle){
252140faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2522de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
252340faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
252440faeb84SMilanka Ringwald         return status;
252540faeb84SMilanka Ringwald     }
25263deb3ec6SMatthias Ringwald 
25275cf1669fSMatthias Ringwald     gatt_client->callback = callback;
25285cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_EXECUTE_PREPARED_WRITE;
25293deb3ec6SMatthias Ringwald     gatt_client_run();
253025b7c058SMilanka Ringwald     return ERROR_CODE_SUCCESS;
25313deb3ec6SMatthias Ringwald }
25323deb3ec6SMatthias Ringwald 
25333deb3ec6SMatthias Ringwald /**
25343deb3ec6SMatthias Ringwald  * @brief -> gatt complete event
25353deb3ec6SMatthias Ringwald  */
2536711e6c80SMatthias Ringwald uint8_t gatt_client_cancel_write(btstack_packet_handler_t callback, hci_con_handle_t con_handle){
253740faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
2538de27733dSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_request(con_handle, &gatt_client);
253940faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
254040faeb84SMilanka Ringwald         return status;
254140faeb84SMilanka Ringwald     }
25423deb3ec6SMatthias Ringwald 
25435cf1669fSMatthias Ringwald     gatt_client->callback = callback;
25445cf1669fSMatthias Ringwald     gatt_client->gatt_client_state = P_W2_CANCEL_PREPARED_WRITE;
25453deb3ec6SMatthias Ringwald     gatt_client_run();
25467d2258b3SMilanka Ringwald     return ERROR_CODE_SUCCESS;
25473deb3ec6SMatthias Ringwald }
25483deb3ec6SMatthias Ringwald 
2549313e337bSMatthias Ringwald void gatt_client_deserialize_service(const uint8_t *packet, int offset, gatt_client_service_t * service){
25506ba2ad22SMatthias Ringwald     service->start_group_handle = little_endian_read_16(packet, offset);
25516ba2ad22SMatthias Ringwald     service->end_group_handle = little_endian_read_16(packet, offset + 2);
25526ba2ad22SMatthias Ringwald     reverse_128(&packet[offset + 4], service->uuid128);
25536ba2ad22SMatthias Ringwald     if (uuid_has_bluetooth_prefix(service->uuid128)){
25546ba2ad22SMatthias Ringwald         service->uuid16 = big_endian_read_32(service->uuid128, 0);
2555c839c6f9SMatthias Ringwald     } else {
2556c839c6f9SMatthias Ringwald         service->uuid16 = 0;
25576ba2ad22SMatthias Ringwald     }
25586ba2ad22SMatthias Ringwald }
25596ba2ad22SMatthias Ringwald 
2560313e337bSMatthias Ringwald void gatt_client_deserialize_characteristic(const uint8_t * packet, int offset, gatt_client_characteristic_t * characteristic){
25616ba2ad22SMatthias Ringwald     characteristic->start_handle = little_endian_read_16(packet, offset);
25626ba2ad22SMatthias Ringwald     characteristic->value_handle = little_endian_read_16(packet, offset + 2);
25636ba2ad22SMatthias Ringwald     characteristic->end_handle = little_endian_read_16(packet, offset + 4);
25646ba2ad22SMatthias Ringwald     characteristic->properties = little_endian_read_16(packet, offset + 6);
256586c38559SMatthias Ringwald     reverse_128(&packet[offset+8], characteristic->uuid128);
25666ba2ad22SMatthias Ringwald     if (uuid_has_bluetooth_prefix(characteristic->uuid128)){
25676ba2ad22SMatthias Ringwald         characteristic->uuid16 = big_endian_read_32(characteristic->uuid128, 0);
2568c839c6f9SMatthias Ringwald     } else {
2569c839c6f9SMatthias Ringwald         characteristic->uuid16 = 0;
25706ba2ad22SMatthias Ringwald     }
25716ba2ad22SMatthias Ringwald }
25726ba2ad22SMatthias Ringwald 
2573313e337bSMatthias Ringwald void gatt_client_deserialize_characteristic_descriptor(const uint8_t * packet, int offset, gatt_client_characteristic_descriptor_t * descriptor){
25746ba2ad22SMatthias Ringwald     descriptor->handle = little_endian_read_16(packet, offset);
25756ba2ad22SMatthias Ringwald     reverse_128(&packet[offset+2], descriptor->uuid128);
2576b4895529SJakob Krantz     if (uuid_has_bluetooth_prefix(descriptor->uuid128)){
2577b4895529SJakob Krantz         descriptor->uuid16 = big_endian_read_32(descriptor->uuid128, 0);
2578c839c6f9SMatthias Ringwald     } else {
2579c839c6f9SMatthias Ringwald         descriptor->uuid16 = 0;
2580b4895529SJakob Krantz     }
25816ba2ad22SMatthias Ringwald }
25825cf6c434SJakob Krantz 
25835cf6c434SJakob Krantz void gatt_client_send_mtu_negotiation(btstack_packet_handler_t callback, hci_con_handle_t con_handle){
258440faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
258540faeb84SMilanka Ringwald     uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client);
258640faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
258740faeb84SMilanka Ringwald         return;
258840faeb84SMilanka Ringwald     }
258940faeb84SMilanka Ringwald     if (gatt_client->mtu_state == MTU_AUTO_EXCHANGE_DISABLED){
259040faeb84SMilanka Ringwald         gatt_client->callback = callback;
259140faeb84SMilanka Ringwald         gatt_client->mtu_state = SEND_MTU_EXCHANGE;
25925cf6c434SJakob Krantz         gatt_client_run();
25935cf6c434SJakob Krantz     }
25945cf6c434SJakob Krantz }
259547181045SMatthias Ringwald 
259659d34cd2SMatthias Ringwald uint8_t gatt_client_request_to_write_without_response(btstack_context_callback_registration_t * callback_registration, hci_con_handle_t con_handle){
259759d34cd2SMatthias Ringwald     gatt_client_t * gatt_client;
259859d34cd2SMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client);
259959d34cd2SMatthias Ringwald     if (status != ERROR_CODE_SUCCESS){
260059d34cd2SMatthias Ringwald         return status;
260159d34cd2SMatthias Ringwald     }
260259d34cd2SMatthias Ringwald     bool added = btstack_linked_list_add_tail(&gatt_client->write_without_response_requests, (btstack_linked_item_t*) callback_registration);
260359d34cd2SMatthias Ringwald     att_dispatch_client_request_can_send_now_event(gatt_client->con_handle);
260459d34cd2SMatthias Ringwald     if (added){
260559d34cd2SMatthias Ringwald         return ERROR_CODE_SUCCESS;
260659d34cd2SMatthias Ringwald     } else {
260759d34cd2SMatthias Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
260859d34cd2SMatthias Ringwald     }
260959d34cd2SMatthias Ringwald }
261059d34cd2SMatthias Ringwald 
261153e9c18fSMatthias Ringwald uint8_t gatt_client_request_to_send_gatt_query(btstack_context_callback_registration_t * callback_registration, hci_con_handle_t con_handle){
261253e9c18fSMatthias Ringwald     gatt_client_t * gatt_client;
261353e9c18fSMatthias Ringwald     uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client);
261453e9c18fSMatthias Ringwald     if (status != ERROR_CODE_SUCCESS){
261553e9c18fSMatthias Ringwald         return status;
261653e9c18fSMatthias Ringwald     }
261753e9c18fSMatthias Ringwald     bool added = btstack_linked_list_add_tail(&gatt_client->query_requests, (btstack_linked_item_t*) callback_registration);
261853e9c18fSMatthias Ringwald     gatt_client_notify_can_send_query(gatt_client);
261953e9c18fSMatthias Ringwald     if (added){
262053e9c18fSMatthias Ringwald         return ERROR_CODE_SUCCESS;
262153e9c18fSMatthias Ringwald     } else {
262253e9c18fSMatthias Ringwald         return ERROR_CODE_COMMAND_DISALLOWED;
262353e9c18fSMatthias Ringwald     }
262453e9c18fSMatthias Ringwald }
262553e9c18fSMatthias Ringwald 
262647181045SMatthias Ringwald uint8_t gatt_client_request_can_write_without_response_event(btstack_packet_handler_t callback, hci_con_handle_t con_handle){
262740faeb84SMilanka Ringwald     gatt_client_t * gatt_client;
262840faeb84SMilanka Ringwald     uint8_t status = gatt_client_provide_context_for_handle(con_handle, &gatt_client);
262940faeb84SMilanka Ringwald     if (status != ERROR_CODE_SUCCESS){
263040faeb84SMilanka Ringwald         return status;
263140faeb84SMilanka Ringwald     }
263240faeb84SMilanka Ringwald     if (gatt_client->write_without_response_callback != NULL){
263340faeb84SMilanka Ringwald         return GATT_CLIENT_IN_WRONG_STATE;
263440faeb84SMilanka Ringwald     }
263540faeb84SMilanka Ringwald     gatt_client->write_without_response_callback = callback;
263640faeb84SMilanka Ringwald     att_dispatch_client_request_can_send_now_event(gatt_client->con_handle);
26377d2258b3SMilanka Ringwald     return ERROR_CODE_SUCCESS;
263847181045SMatthias Ringwald }
2639a6121b51SMilanka Ringwald 
26401450cdc6SMatthias Ringwald #ifdef ENABLE_GATT_OVER_CLASSIC
26411450cdc6SMatthias Ringwald 
26421450cdc6SMatthias Ringwald #include "hci_event.h"
26431450cdc6SMatthias Ringwald 
26441450cdc6SMatthias Ringwald // single active SDP query
26451450cdc6SMatthias Ringwald static gatt_client_t * gatt_client_classic_active_sdp_query;
26461450cdc6SMatthias Ringwald 
26471450cdc6SMatthias Ringwald // macos protocol descriptor list requires 16 bytes
26481450cdc6SMatthias Ringwald static uint8_t gatt_client_classic_sdp_buffer[32];
26491450cdc6SMatthias Ringwald 
26501450cdc6SMatthias Ringwald static const hci_event_t gatt_client_connected = {
26511450cdc6SMatthias Ringwald         GATT_EVENT_CONNECTED, 0, "1BH"
26521450cdc6SMatthias Ringwald };
26531450cdc6SMatthias Ringwald 
26546b4a68c3SMatthias Ringwald static const hci_event_t gatt_client_disconnected = {
26556b4a68c3SMatthias Ringwald         GATT_EVENT_DISCONNECTED, 0, "H"
26566b4a68c3SMatthias Ringwald };
26576b4a68c3SMatthias Ringwald 
26581450cdc6SMatthias Ringwald static gatt_client_t * gatt_client_get_context_for_classic_addr(bd_addr_t addr){
26591450cdc6SMatthias Ringwald     btstack_linked_item_t *it;
26601450cdc6SMatthias Ringwald     for (it = (btstack_linked_item_t *) gatt_client_connections; it != NULL; it = it->next){
26611450cdc6SMatthias Ringwald         gatt_client_t * gatt_client = (gatt_client_t *) it;
26621450cdc6SMatthias Ringwald         if (memcmp(gatt_client->addr, addr, 6) == 0){
26631450cdc6SMatthias Ringwald             return gatt_client;
26641450cdc6SMatthias Ringwald         }
26651450cdc6SMatthias Ringwald     }
26661450cdc6SMatthias Ringwald     return NULL;
26671450cdc6SMatthias Ringwald }
26681450cdc6SMatthias Ringwald 
26691450cdc6SMatthias Ringwald static gatt_client_t * gatt_client_get_context_for_l2cap_cid(uint16_t l2cap_cid){
26701450cdc6SMatthias Ringwald     btstack_linked_item_t *it;
26711450cdc6SMatthias Ringwald     for (it = (btstack_linked_item_t *) gatt_client_connections; it != NULL; it = it->next){
26721450cdc6SMatthias Ringwald         gatt_client_t * gatt_client = (gatt_client_t *) it;
26731450cdc6SMatthias Ringwald         if (gatt_client->l2cap_cid == l2cap_cid){
26741450cdc6SMatthias Ringwald             return gatt_client;
26751450cdc6SMatthias Ringwald         }
26761450cdc6SMatthias Ringwald     }
26771450cdc6SMatthias Ringwald     return NULL;
26781450cdc6SMatthias Ringwald }
26791450cdc6SMatthias Ringwald 
26801450cdc6SMatthias Ringwald static void gatt_client_classic_handle_connected(gatt_client_t * gatt_client, uint8_t status){
26811450cdc6SMatthias Ringwald     bd_addr_t addr;
2682d5529700SMatthias Ringwald     // cppcheck-suppress uninitvar ; addr is reported as uninitialized although it's the destination of the memcpy
26831450cdc6SMatthias Ringwald     memcpy(addr, gatt_client->addr, 6);
26841450cdc6SMatthias Ringwald     hci_con_handle_t con_handle = gatt_client->con_handle;
26851450cdc6SMatthias Ringwald     btstack_packet_handler_t callback = gatt_client->callback;
26861450cdc6SMatthias Ringwald     if (status != ERROR_CODE_SUCCESS){
26871450cdc6SMatthias Ringwald         btstack_linked_list_remove(&gatt_client_connections, (btstack_linked_item_t *) gatt_client);
26881450cdc6SMatthias Ringwald         btstack_memory_gatt_client_free(gatt_client);
26891450cdc6SMatthias Ringwald     }
26901450cdc6SMatthias Ringwald     uint8_t buffer[20];
26911450cdc6SMatthias Ringwald     uint16_t len = hci_event_create_from_template_and_arguments(buffer, sizeof(buffer), &gatt_client_connected, status, addr,
26921450cdc6SMatthias Ringwald                                                                 con_handle);
26931450cdc6SMatthias Ringwald     (*callback)(HCI_EVENT_PACKET, 0, buffer, len);
26941450cdc6SMatthias Ringwald }
26951450cdc6SMatthias Ringwald 
26966b4a68c3SMatthias Ringwald static void gatt_client_classic_handle_disconnected(gatt_client_t * gatt_client){
26976b4a68c3SMatthias Ringwald 
26986b4a68c3SMatthias Ringwald     gatt_client_report_error_if_pending(gatt_client, ATT_ERROR_HCI_DISCONNECT_RECEIVED);
26996b4a68c3SMatthias Ringwald     gatt_client_timeout_stop(gatt_client);
27006b4a68c3SMatthias Ringwald 
27016b4a68c3SMatthias Ringwald     hci_con_handle_t con_handle = gatt_client->con_handle;
27026b4a68c3SMatthias Ringwald     btstack_packet_handler_t callback = gatt_client->callback;
27036b4a68c3SMatthias Ringwald     btstack_linked_list_remove(&gatt_client_connections, (btstack_linked_item_t *) gatt_client);
27046b4a68c3SMatthias Ringwald     btstack_memory_gatt_client_free(gatt_client);
27056b4a68c3SMatthias Ringwald 
27066b4a68c3SMatthias Ringwald     uint8_t buffer[20];
27076b4a68c3SMatthias Ringwald     uint16_t len = hci_event_create_from_template_and_arguments(buffer, sizeof(buffer), &gatt_client_disconnected, con_handle);
27086b4a68c3SMatthias Ringwald     (*callback)(HCI_EVENT_PACKET, 0, buffer, len);
27096b4a68c3SMatthias Ringwald }
27106b4a68c3SMatthias Ringwald 
27111450cdc6SMatthias Ringwald static void gatt_client_l2cap_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
27121450cdc6SMatthias Ringwald     gatt_client_t * gatt_client = NULL;
27131450cdc6SMatthias Ringwald     uint8_t status;
27141450cdc6SMatthias Ringwald     switch (packet_type){
27151450cdc6SMatthias Ringwald         case HCI_EVENT_PACKET:
27161450cdc6SMatthias Ringwald             switch (hci_event_packet_get_type(packet)) {
27171450cdc6SMatthias Ringwald                 case L2CAP_EVENT_CHANNEL_OPENED:
27181450cdc6SMatthias Ringwald                     status = l2cap_event_channel_opened_get_status(packet);
27191450cdc6SMatthias Ringwald                     gatt_client = gatt_client_get_context_for_l2cap_cid(l2cap_event_channel_opened_get_local_cid(packet));
27201450cdc6SMatthias Ringwald                     btstack_assert(gatt_client != NULL);
2721664e1f18SMatthias Ringwald                     // if status != 0, gatt_client will be discarded
2722664e1f18SMatthias Ringwald                     gatt_client->gatt_client_state = P_READY;
27231450cdc6SMatthias Ringwald                     gatt_client->con_handle = l2cap_event_channel_opened_get_handle(packet);
2724ac4c2bc6SMatthias Ringwald                     gatt_client->mtu = l2cap_event_channel_opened_get_remote_mtu(packet);
27251450cdc6SMatthias Ringwald                     gatt_client_classic_handle_connected(gatt_client, status);
2726664e1f18SMatthias Ringwald                     break;
27271450cdc6SMatthias Ringwald                 case L2CAP_EVENT_CHANNEL_CLOSED:
27286b4a68c3SMatthias Ringwald                     gatt_client = gatt_client_get_context_for_l2cap_cid(l2cap_event_channel_closed_get_local_cid(packet));
27296b4a68c3SMatthias Ringwald                     gatt_client_classic_handle_disconnected(gatt_client);
27301450cdc6SMatthias Ringwald                     break;
27311450cdc6SMatthias Ringwald                 default:
27321450cdc6SMatthias Ringwald                     break;
27331450cdc6SMatthias Ringwald             }
27341450cdc6SMatthias Ringwald             break;
27351450cdc6SMatthias Ringwald         case L2CAP_DATA_PACKET:
27361450cdc6SMatthias Ringwald             gatt_client = gatt_client_get_context_for_l2cap_cid(channel);
27371450cdc6SMatthias Ringwald             btstack_assert(gatt_client != NULL);
2738664e1f18SMatthias Ringwald             gatt_client_handle_att_response(gatt_client, packet, size);
2739664e1f18SMatthias Ringwald             gatt_client_run();
27401450cdc6SMatthias Ringwald             break;
274110cae6eaSMatthias Ringwald         default:
274210cae6eaSMatthias Ringwald             break;
27431450cdc6SMatthias Ringwald     }
27441450cdc6SMatthias Ringwald }
27451450cdc6SMatthias Ringwald 
27461450cdc6SMatthias Ringwald static void gatt_client_handle_sdp_client_query_attribute_value(gatt_client_t * connection, uint8_t *packet){
27471450cdc6SMatthias Ringwald     des_iterator_t des_list_it;
27481450cdc6SMatthias Ringwald     des_iterator_t prot_it;
27491450cdc6SMatthias Ringwald 
27501450cdc6SMatthias Ringwald     if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= sizeof(gatt_client_classic_sdp_buffer)) {
27511450cdc6SMatthias Ringwald         gatt_client_classic_sdp_buffer[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet);
27521450cdc6SMatthias Ringwald         if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) {
27531450cdc6SMatthias Ringwald             switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) {
27541450cdc6SMatthias Ringwald                 case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST:
27551450cdc6SMatthias Ringwald                     for (des_iterator_init(&des_list_it, gatt_client_classic_sdp_buffer); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) {
27561450cdc6SMatthias Ringwald                         uint8_t       *des_element;
27571450cdc6SMatthias Ringwald                         uint8_t       *element;
27581450cdc6SMatthias Ringwald                         uint32_t       uuid;
27591450cdc6SMatthias Ringwald 
27601450cdc6SMatthias Ringwald                         if (des_iterator_get_type(&des_list_it) != DE_DES) continue;
27611450cdc6SMatthias Ringwald 
27621450cdc6SMatthias Ringwald                         des_element = des_iterator_get_element(&des_list_it);
27631450cdc6SMatthias Ringwald                         des_iterator_init(&prot_it, des_element);
27641450cdc6SMatthias Ringwald                         element = des_iterator_get_element(&prot_it);
27651450cdc6SMatthias Ringwald 
27661450cdc6SMatthias Ringwald                         if (de_get_element_type(element) != DE_UUID) continue;
27671450cdc6SMatthias Ringwald 
27681450cdc6SMatthias Ringwald                         uuid = de_get_uuid32(element);
27691450cdc6SMatthias Ringwald                         des_iterator_next(&prot_it);
27701450cdc6SMatthias Ringwald                         // we assume that the even if there are both roles supported, remote device uses the same psm and avdtp version for both
27711450cdc6SMatthias Ringwald                         switch (uuid){
27721450cdc6SMatthias Ringwald                             case BLUETOOTH_PROTOCOL_L2CAP:
27731450cdc6SMatthias Ringwald                                 if (!des_iterator_has_more(&prot_it)) continue;
27741450cdc6SMatthias Ringwald                                 de_element_get_uint16(des_iterator_get_element(&prot_it), &connection->l2cap_psm);
27751450cdc6SMatthias Ringwald                                 break;
27761450cdc6SMatthias Ringwald                             default:
27771450cdc6SMatthias Ringwald                                 break;
27781450cdc6SMatthias Ringwald                         }
27791450cdc6SMatthias Ringwald                     }
27801450cdc6SMatthias Ringwald                     break;
27811450cdc6SMatthias Ringwald 
27821450cdc6SMatthias Ringwald                 default:
27831450cdc6SMatthias Ringwald                     break;
27841450cdc6SMatthias Ringwald             }
27851450cdc6SMatthias Ringwald         }
27861450cdc6SMatthias Ringwald     }
27871450cdc6SMatthias Ringwald }
27881450cdc6SMatthias Ringwald 
27891450cdc6SMatthias Ringwald static void gatt_client_classic_sdp_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size){
27901450cdc6SMatthias Ringwald     gatt_client_t * gatt_client = gatt_client_classic_active_sdp_query;
27911450cdc6SMatthias Ringwald     btstack_assert(gatt_client != NULL);
27921450cdc6SMatthias Ringwald     uint8_t status;
27931450cdc6SMatthias Ringwald 
27941450cdc6SMatthias Ringwald     // TODO: handle sdp events, get l2cap psm
27951450cdc6SMatthias Ringwald     switch (hci_event_packet_get_type(packet)){
27961450cdc6SMatthias Ringwald         case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
27971450cdc6SMatthias Ringwald             gatt_client_handle_sdp_client_query_attribute_value(gatt_client, packet);
27981450cdc6SMatthias Ringwald             // TODO:
27991450cdc6SMatthias Ringwald             return;
28001450cdc6SMatthias Ringwald         case SDP_EVENT_QUERY_COMPLETE:
28011450cdc6SMatthias Ringwald             status = sdp_event_query_complete_get_status(packet);
28021450cdc6SMatthias Ringwald             gatt_client_classic_active_sdp_query = NULL;
28031450cdc6SMatthias Ringwald             log_info("l2cap psm: %0x, status %02x", gatt_client->l2cap_psm, status);
28041450cdc6SMatthias Ringwald             if (status != ERROR_CODE_SUCCESS) break;
28051450cdc6SMatthias Ringwald             if (gatt_client->l2cap_psm == 0) {
28061450cdc6SMatthias Ringwald                 status = SDP_SERVICE_NOT_FOUND;
28071450cdc6SMatthias Ringwald                 break;
28081450cdc6SMatthias Ringwald             }
28091450cdc6SMatthias Ringwald             break;
28101450cdc6SMatthias Ringwald         default:
28111450cdc6SMatthias Ringwald             btstack_assert(false);
28121450cdc6SMatthias Ringwald             return;
28131450cdc6SMatthias Ringwald     }
28141450cdc6SMatthias Ringwald 
28151450cdc6SMatthias Ringwald     // done
28161450cdc6SMatthias Ringwald     if (status == ERROR_CODE_SUCCESS){
28171450cdc6SMatthias Ringwald         gatt_client->gatt_client_state = P_W4_L2CAP_CONNECTION;
28181450cdc6SMatthias Ringwald         status = l2cap_create_channel(gatt_client_l2cap_handler, gatt_client->addr, gatt_client->l2cap_psm, 0xffff,
28191450cdc6SMatthias Ringwald                              &gatt_client->l2cap_cid);
28201450cdc6SMatthias Ringwald     }
28211450cdc6SMatthias Ringwald     if (status != ERROR_CODE_SUCCESS) {
28221450cdc6SMatthias Ringwald         gatt_client_classic_handle_connected(gatt_client, status);
28231450cdc6SMatthias Ringwald     }
28241450cdc6SMatthias Ringwald }
28251450cdc6SMatthias Ringwald 
28261450cdc6SMatthias Ringwald static void gatt_client_classic_sdp_start(void * context){
28271450cdc6SMatthias Ringwald     gatt_client_classic_active_sdp_query = (gatt_client_t *) context;
28281450cdc6SMatthias Ringwald     gatt_client_classic_active_sdp_query->gatt_client_state = P_W4_SDP_QUERY;
28291450cdc6SMatthias Ringwald     sdp_client_query_uuid16(gatt_client_classic_sdp_handler, gatt_client_classic_active_sdp_query->addr, ORG_BLUETOOTH_SERVICE_GENERIC_ATTRIBUTE);
28301450cdc6SMatthias Ringwald }
28311450cdc6SMatthias Ringwald 
28321450cdc6SMatthias Ringwald uint8_t gatt_client_classic_connect(btstack_packet_handler_t callback, bd_addr_t addr){
28331450cdc6SMatthias Ringwald     gatt_client_t * gatt_client = gatt_client_get_context_for_classic_addr(addr);
28341450cdc6SMatthias Ringwald     if (gatt_client != NULL){
28351450cdc6SMatthias Ringwald         return ERROR_CODE_ACL_CONNECTION_ALREADY_EXISTS;
28361450cdc6SMatthias Ringwald     }
28371450cdc6SMatthias Ringwald     gatt_client = btstack_memory_gatt_client_get();
28381450cdc6SMatthias Ringwald     if (gatt_client == NULL){
28391450cdc6SMatthias Ringwald         return ERROR_CODE_MEMORY_CAPACITY_EXCEEDED;
28401450cdc6SMatthias Ringwald     }
28411450cdc6SMatthias Ringwald     // init state
2842e9cdf30bSMatthias Ringwald     gatt_client->bearer_type = ATT_BEARER_UNENHANCED_CLASSIC;
28431450cdc6SMatthias Ringwald     gatt_client->con_handle = HCI_CON_HANDLE_INVALID;
28441450cdc6SMatthias Ringwald     memcpy(gatt_client->addr, addr, 6);
28451450cdc6SMatthias Ringwald     gatt_client->mtu = ATT_DEFAULT_MTU;
28461450cdc6SMatthias Ringwald     gatt_client->security_level = LEVEL_0;
28471450cdc6SMatthias Ringwald     gatt_client->mtu_state = MTU_AUTO_EXCHANGE_DISABLED;
28481450cdc6SMatthias Ringwald     gatt_client->gatt_client_state = P_W2_SDP_QUERY;
28491450cdc6SMatthias Ringwald     gatt_client->sdp_query_request.callback = &gatt_client_classic_sdp_start;
28501450cdc6SMatthias Ringwald     gatt_client->sdp_query_request.context = gatt_client;
28511450cdc6SMatthias Ringwald     gatt_client->callback = callback;
28521450cdc6SMatthias Ringwald     btstack_linked_list_add(&gatt_client_connections, (btstack_linked_item_t*)gatt_client);
28531450cdc6SMatthias Ringwald     sdp_client_register_query_callback(&gatt_client->sdp_query_request);
2854b7b03a30SMatthias Ringwald     return ERROR_CODE_SUCCESS;
28551450cdc6SMatthias Ringwald }
28561450cdc6SMatthias Ringwald 
28571450cdc6SMatthias Ringwald uint8_t gatt_client_classic_disconnect(btstack_packet_handler_t callback, hci_con_handle_t con_handle){
28581450cdc6SMatthias Ringwald     gatt_client_t * gatt_client = gatt_client_get_context_for_handle(con_handle);
28591450cdc6SMatthias Ringwald     if (gatt_client == NULL){
28601450cdc6SMatthias Ringwald         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
28611450cdc6SMatthias Ringwald     }
28621450cdc6SMatthias Ringwald     gatt_client->callback = callback;
28631450cdc6SMatthias Ringwald     return l2cap_disconnect(gatt_client->l2cap_cid);
28641450cdc6SMatthias Ringwald }
28651450cdc6SMatthias Ringwald #endif
28661450cdc6SMatthias Ringwald 
2867a6121b51SMilanka Ringwald #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
2868a6121b51SMilanka Ringwald void gatt_client_att_packet_handler_fuzz(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size){
2869a6121b51SMilanka Ringwald     gatt_client_att_packet_handler(packet_type, handle, packet, size);
2870a6121b51SMilanka Ringwald }
2871ae1ee62dSMilanka Ringwald 
287240faeb84SMilanka Ringwald uint8_t gatt_client_get_client(hci_con_handle_t con_handle, gatt_client_t ** out_gatt_client){
287340faeb84SMilanka Ringwald     uint8_t status = gatt_client_provide_context_for_handle(con_handle, out_gatt_client);
287440faeb84SMilanka Ringwald     return status;
2875ae1ee62dSMilanka Ringwald }
2876a6121b51SMilanka Ringwald #endif
2877