xref: /btstack/src/ble/gatt_client.c (revision 3deb3ec68039c68a16974dffc53343233662f909)
1*3deb3ec6SMatthias Ringwald /*
2*3deb3ec6SMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
3*3deb3ec6SMatthias Ringwald  *
4*3deb3ec6SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*3deb3ec6SMatthias Ringwald  * modification, are permitted provided that the following conditions
6*3deb3ec6SMatthias Ringwald  * are met:
7*3deb3ec6SMatthias Ringwald  *
8*3deb3ec6SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*3deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*3deb3ec6SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*3deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*3deb3ec6SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*3deb3ec6SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*3deb3ec6SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*3deb3ec6SMatthias Ringwald  *    from this software without specific prior written permission.
16*3deb3ec6SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*3deb3ec6SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*3deb3ec6SMatthias Ringwald  *    monetary gain.
19*3deb3ec6SMatthias Ringwald  *
20*3deb3ec6SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*3deb3ec6SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*3deb3ec6SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*3deb3ec6SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*3deb3ec6SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*3deb3ec6SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*3deb3ec6SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*3deb3ec6SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*3deb3ec6SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*3deb3ec6SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*3deb3ec6SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*3deb3ec6SMatthias Ringwald  * SUCH DAMAGE.
32*3deb3ec6SMatthias Ringwald  *
33*3deb3ec6SMatthias Ringwald  * Please inquire about commercial licensing options at
34*3deb3ec6SMatthias Ringwald  * [email protected]
35*3deb3ec6SMatthias Ringwald  *
36*3deb3ec6SMatthias Ringwald  */
37*3deb3ec6SMatthias Ringwald 
38*3deb3ec6SMatthias Ringwald #include <stdint.h>
39*3deb3ec6SMatthias Ringwald #include <stdio.h>
40*3deb3ec6SMatthias Ringwald #include <stdlib.h>
41*3deb3ec6SMatthias Ringwald #include <string.h>
42*3deb3ec6SMatthias Ringwald #include "run_loop.h"
43*3deb3ec6SMatthias Ringwald #include "hci_cmds.h"
44*3deb3ec6SMatthias Ringwald #include "utils.h"
45*3deb3ec6SMatthias Ringwald #include "sdp_util.h"
46*3deb3ec6SMatthias Ringwald 
47*3deb3ec6SMatthias Ringwald #include "btstack-config.h"
48*3deb3ec6SMatthias Ringwald 
49*3deb3ec6SMatthias Ringwald #include "gatt_client.h"
50*3deb3ec6SMatthias Ringwald #include "ad_parser.h"
51*3deb3ec6SMatthias Ringwald 
52*3deb3ec6SMatthias Ringwald #include "debug.h"
53*3deb3ec6SMatthias Ringwald #include "btstack_memory.h"
54*3deb3ec6SMatthias Ringwald #include "hci.h"
55*3deb3ec6SMatthias Ringwald #include "hci_dump.h"
56*3deb3ec6SMatthias Ringwald #include "l2cap.h"
57*3deb3ec6SMatthias Ringwald #include "att.h"
58*3deb3ec6SMatthias Ringwald #include "att_dispatch.h"
59*3deb3ec6SMatthias Ringwald #include "sm.h"
60*3deb3ec6SMatthias Ringwald #include "le_device_db.h"
61*3deb3ec6SMatthias Ringwald 
62*3deb3ec6SMatthias Ringwald static linked_list_t gatt_client_connections = NULL;
63*3deb3ec6SMatthias Ringwald static linked_list_t gatt_subclients = NULL;
64*3deb3ec6SMatthias Ringwald static uint16_t next_gatt_client_id = 0;
65*3deb3ec6SMatthias Ringwald static uint8_t  pts_suppress_mtu_exchange;
66*3deb3ec6SMatthias Ringwald 
67*3deb3ec6SMatthias Ringwald static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size);
68*3deb3ec6SMatthias Ringwald static void gatt_client_report_error_if_pending(gatt_client_t *peripheral, uint8_t error_code);
69*3deb3ec6SMatthias Ringwald static void att_signed_write_handle_cmac_result(uint8_t hash[8]);
70*3deb3ec6SMatthias Ringwald 
71*3deb3ec6SMatthias Ringwald static uint16_t peripheral_mtu(gatt_client_t *peripheral){
72*3deb3ec6SMatthias Ringwald     if (peripheral->mtu > l2cap_max_le_mtu()){
73*3deb3ec6SMatthias Ringwald         log_error("Peripheral mtu is not initialized");
74*3deb3ec6SMatthias Ringwald         return l2cap_max_le_mtu();
75*3deb3ec6SMatthias Ringwald     }
76*3deb3ec6SMatthias Ringwald     return peripheral->mtu;
77*3deb3ec6SMatthias Ringwald }
78*3deb3ec6SMatthias Ringwald 
79*3deb3ec6SMatthias Ringwald static uint16_t gatt_client_next_id(void){
80*3deb3ec6SMatthias Ringwald     if (next_gatt_client_id < 0xFFFF) {
81*3deb3ec6SMatthias Ringwald         next_gatt_client_id++;
82*3deb3ec6SMatthias Ringwald     } else {
83*3deb3ec6SMatthias Ringwald         next_gatt_client_id = 1;
84*3deb3ec6SMatthias Ringwald     }
85*3deb3ec6SMatthias Ringwald     return next_gatt_client_id;
86*3deb3ec6SMatthias Ringwald }
87*3deb3ec6SMatthias Ringwald 
88*3deb3ec6SMatthias Ringwald static gatt_client_callback_t gatt_client_callback_for_id_new(uint16_t id){
89*3deb3ec6SMatthias Ringwald     linked_list_iterator_t it;
90*3deb3ec6SMatthias Ringwald     linked_list_iterator_init(&it, &gatt_subclients);
91*3deb3ec6SMatthias Ringwald     while (linked_list_iterator_has_next(&it)){
92*3deb3ec6SMatthias Ringwald         gatt_subclient_t * item = (gatt_subclient_t*) linked_list_iterator_next(&it);
93*3deb3ec6SMatthias Ringwald         if ( item->id != id) continue;
94*3deb3ec6SMatthias Ringwald         return item->callback;
95*3deb3ec6SMatthias Ringwald     }
96*3deb3ec6SMatthias Ringwald     return NULL;
97*3deb3ec6SMatthias Ringwald }
98*3deb3ec6SMatthias Ringwald 
99*3deb3ec6SMatthias Ringwald uint16_t gatt_client_register_packet_handler(gatt_client_callback_t gatt_callback){
100*3deb3ec6SMatthias Ringwald     if (gatt_callback == NULL){
101*3deb3ec6SMatthias Ringwald         log_error("gatt_client_register_packet_handler called with NULL callback");
102*3deb3ec6SMatthias Ringwald         return 0;
103*3deb3ec6SMatthias Ringwald     }
104*3deb3ec6SMatthias Ringwald 
105*3deb3ec6SMatthias Ringwald     gatt_subclient_t * subclient = btstack_memory_gatt_subclient_get();
106*3deb3ec6SMatthias Ringwald     if (!subclient) {
107*3deb3ec6SMatthias Ringwald         log_error("gatt_client_register_packet_handler failed (no memory)");
108*3deb3ec6SMatthias Ringwald         return 0;
109*3deb3ec6SMatthias Ringwald     }
110*3deb3ec6SMatthias Ringwald 
111*3deb3ec6SMatthias Ringwald     subclient->id = gatt_client_next_id();
112*3deb3ec6SMatthias Ringwald     subclient->callback = gatt_callback;
113*3deb3ec6SMatthias Ringwald     linked_list_add(&gatt_subclients, (linked_item_t *) subclient);
114*3deb3ec6SMatthias Ringwald     log_info("gatt_client_register_packet_handler with new id %u", subclient->id);
115*3deb3ec6SMatthias Ringwald 
116*3deb3ec6SMatthias Ringwald     return subclient->id;
117*3deb3ec6SMatthias Ringwald }
118*3deb3ec6SMatthias Ringwald 
119*3deb3ec6SMatthias Ringwald void gatt_client_unregister_packet_handler(uint16_t gatt_client_id){
120*3deb3ec6SMatthias Ringwald     linked_list_iterator_t it;
121*3deb3ec6SMatthias Ringwald     linked_list_iterator_init(&it, &gatt_subclients);
122*3deb3ec6SMatthias Ringwald     while (linked_list_iterator_has_next(&it)){
123*3deb3ec6SMatthias Ringwald         gatt_subclient_t * subclient = (gatt_subclient_t*) linked_list_iterator_next(&it);
124*3deb3ec6SMatthias Ringwald         if ( subclient->id != gatt_client_id) continue;
125*3deb3ec6SMatthias Ringwald         linked_list_remove(&gatt_subclients, (linked_item_t *) subclient);
126*3deb3ec6SMatthias Ringwald         btstack_memory_gatt_subclient_free(subclient);
127*3deb3ec6SMatthias Ringwald     }
128*3deb3ec6SMatthias Ringwald }
129*3deb3ec6SMatthias Ringwald 
130*3deb3ec6SMatthias Ringwald void gatt_client_init(void){
131*3deb3ec6SMatthias Ringwald     gatt_client_connections = NULL;
132*3deb3ec6SMatthias Ringwald     pts_suppress_mtu_exchange = 0;
133*3deb3ec6SMatthias Ringwald     att_dispatch_register_client(gatt_client_att_packet_handler);
134*3deb3ec6SMatthias Ringwald }
135*3deb3ec6SMatthias Ringwald 
136*3deb3ec6SMatthias Ringwald static gatt_client_t * gatt_client_for_timer(timer_source_t * ts){
137*3deb3ec6SMatthias Ringwald     linked_list_iterator_t it;
138*3deb3ec6SMatthias Ringwald     linked_list_iterator_init(&it, &gatt_client_connections);
139*3deb3ec6SMatthias Ringwald     while (linked_list_iterator_has_next(&it)){
140*3deb3ec6SMatthias Ringwald         gatt_client_t * peripheral = (gatt_client_t *) linked_list_iterator_next(&it);
141*3deb3ec6SMatthias Ringwald         if ( &peripheral->gc_timeout == ts) {
142*3deb3ec6SMatthias Ringwald             return peripheral;
143*3deb3ec6SMatthias Ringwald         }
144*3deb3ec6SMatthias Ringwald     }
145*3deb3ec6SMatthias Ringwald     return NULL;
146*3deb3ec6SMatthias Ringwald }
147*3deb3ec6SMatthias Ringwald 
148*3deb3ec6SMatthias Ringwald static void gatt_client_timeout_handler(timer_source_t * timer){
149*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = gatt_client_for_timer(timer);
150*3deb3ec6SMatthias Ringwald     if (!peripheral) return;
151*3deb3ec6SMatthias Ringwald     log_info("GATT client timeout handle, handle 0x%02x", peripheral->handle);
152*3deb3ec6SMatthias Ringwald     gatt_client_report_error_if_pending(peripheral, ATT_ERROR_TIMEOUT);
153*3deb3ec6SMatthias Ringwald }
154*3deb3ec6SMatthias Ringwald 
155*3deb3ec6SMatthias Ringwald static void gatt_client_timeout_start(gatt_client_t * peripheral){
156*3deb3ec6SMatthias Ringwald     log_info("GATT client timeout start, handle 0x%02x", peripheral->handle);
157*3deb3ec6SMatthias Ringwald     run_loop_remove_timer(&peripheral->gc_timeout);
158*3deb3ec6SMatthias Ringwald     run_loop_set_timer_handler(&peripheral->gc_timeout, gatt_client_timeout_handler);
159*3deb3ec6SMatthias Ringwald     run_loop_set_timer(&peripheral->gc_timeout, 30000); // 30 seconds sm timeout
160*3deb3ec6SMatthias Ringwald     run_loop_add_timer(&peripheral->gc_timeout);
161*3deb3ec6SMatthias Ringwald }
162*3deb3ec6SMatthias Ringwald 
163*3deb3ec6SMatthias Ringwald static void gatt_client_timeout_stop(gatt_client_t * peripheral){
164*3deb3ec6SMatthias Ringwald     log_info("GATT client timeout stop, handle 0x%02x", peripheral->handle);
165*3deb3ec6SMatthias Ringwald     run_loop_remove_timer(&peripheral->gc_timeout);
166*3deb3ec6SMatthias Ringwald }
167*3deb3ec6SMatthias Ringwald 
168*3deb3ec6SMatthias Ringwald static gatt_client_t * get_gatt_client_context_for_handle(uint16_t handle){
169*3deb3ec6SMatthias Ringwald     linked_item_t *it;
170*3deb3ec6SMatthias Ringwald     for (it = (linked_item_t *) gatt_client_connections; it ; it = it->next){
171*3deb3ec6SMatthias Ringwald         gatt_client_t * peripheral = (gatt_client_t *) it;
172*3deb3ec6SMatthias Ringwald         if (peripheral->handle == handle){
173*3deb3ec6SMatthias Ringwald             return peripheral;
174*3deb3ec6SMatthias Ringwald         }
175*3deb3ec6SMatthias Ringwald     }
176*3deb3ec6SMatthias Ringwald     return NULL;
177*3deb3ec6SMatthias Ringwald }
178*3deb3ec6SMatthias Ringwald 
179*3deb3ec6SMatthias Ringwald 
180*3deb3ec6SMatthias Ringwald // @returns context
181*3deb3ec6SMatthias Ringwald // returns existing one, or tries to setup new one
182*3deb3ec6SMatthias Ringwald static gatt_client_t * provide_context_for_conn_handle(uint16_t con_handle){
183*3deb3ec6SMatthias Ringwald     gatt_client_t * context = get_gatt_client_context_for_handle(con_handle);
184*3deb3ec6SMatthias Ringwald     if (context) return  context;
185*3deb3ec6SMatthias Ringwald 
186*3deb3ec6SMatthias Ringwald     context = btstack_memory_gatt_client_get();
187*3deb3ec6SMatthias Ringwald     if (!context) return NULL;
188*3deb3ec6SMatthias Ringwald     // init state
189*3deb3ec6SMatthias Ringwald     memset(context, 0, sizeof(gatt_client_t));
190*3deb3ec6SMatthias Ringwald     context->handle = con_handle;
191*3deb3ec6SMatthias Ringwald     context->mtu = ATT_DEFAULT_MTU;
192*3deb3ec6SMatthias Ringwald     context->mtu_state = SEND_MTU_EXCHANGE;
193*3deb3ec6SMatthias Ringwald     context->gatt_client_state = P_READY;
194*3deb3ec6SMatthias Ringwald     linked_list_add(&gatt_client_connections, (linked_item_t*)context);
195*3deb3ec6SMatthias Ringwald 
196*3deb3ec6SMatthias Ringwald     // skip mtu exchange for testing sm with pts
197*3deb3ec6SMatthias Ringwald     if (pts_suppress_mtu_exchange){
198*3deb3ec6SMatthias Ringwald          context->mtu_state = MTU_EXCHANGED;
199*3deb3ec6SMatthias Ringwald     }
200*3deb3ec6SMatthias Ringwald     return context;
201*3deb3ec6SMatthias Ringwald }
202*3deb3ec6SMatthias Ringwald 
203*3deb3ec6SMatthias Ringwald static gatt_client_t * provide_context_for_conn_handle_and_start_timer(uint16_t con_handle){
204*3deb3ec6SMatthias Ringwald     gatt_client_t * context = provide_context_for_conn_handle(con_handle);
205*3deb3ec6SMatthias Ringwald     if (!context) return NULL;
206*3deb3ec6SMatthias Ringwald     gatt_client_timeout_start(context);
207*3deb3ec6SMatthias Ringwald     return context;
208*3deb3ec6SMatthias Ringwald }
209*3deb3ec6SMatthias Ringwald 
210*3deb3ec6SMatthias Ringwald static int is_ready(gatt_client_t * context){
211*3deb3ec6SMatthias Ringwald     return context->gatt_client_state == P_READY;
212*3deb3ec6SMatthias Ringwald }
213*3deb3ec6SMatthias Ringwald 
214*3deb3ec6SMatthias Ringwald int gatt_client_is_ready(uint16_t handle){
215*3deb3ec6SMatthias Ringwald     gatt_client_t * context = provide_context_for_conn_handle(handle);
216*3deb3ec6SMatthias Ringwald     if (!context) return 0;
217*3deb3ec6SMatthias Ringwald     return is_ready(context);
218*3deb3ec6SMatthias Ringwald }
219*3deb3ec6SMatthias Ringwald 
220*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_get_mtu(uint16_t handle, uint16_t * mtu){
221*3deb3ec6SMatthias Ringwald     gatt_client_t * context = provide_context_for_conn_handle(handle);
222*3deb3ec6SMatthias Ringwald     if (context && context->mtu_state == MTU_EXCHANGED){
223*3deb3ec6SMatthias Ringwald         *mtu = context->mtu;
224*3deb3ec6SMatthias Ringwald         return BLE_PERIPHERAL_OK;
225*3deb3ec6SMatthias Ringwald     }
226*3deb3ec6SMatthias Ringwald     *mtu = ATT_DEFAULT_MTU;
227*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_IN_WRONG_STATE;
228*3deb3ec6SMatthias Ringwald }
229*3deb3ec6SMatthias Ringwald 
230*3deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
231*3deb3ec6SMatthias Ringwald static void att_confirmation(uint16_t peripheral_handle){
232*3deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
233*3deb3ec6SMatthias Ringwald     uint8_t * request = l2cap_get_outgoing_buffer();
234*3deb3ec6SMatthias Ringwald     request[0] = ATT_HANDLE_VALUE_CONFIRMATION;
235*3deb3ec6SMatthias Ringwald     l2cap_send_prepared_connectionless(peripheral_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, 1);
236*3deb3ec6SMatthias Ringwald }
237*3deb3ec6SMatthias Ringwald 
238*3deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
239*3deb3ec6SMatthias Ringwald static void att_find_information_request(uint16_t request_type, uint16_t peripheral_handle, uint16_t start_handle, uint16_t end_handle){
240*3deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
241*3deb3ec6SMatthias Ringwald     uint8_t * request = l2cap_get_outgoing_buffer();
242*3deb3ec6SMatthias Ringwald     request[0] = request_type;
243*3deb3ec6SMatthias Ringwald     bt_store_16(request, 1, start_handle);
244*3deb3ec6SMatthias Ringwald     bt_store_16(request, 3, end_handle);
245*3deb3ec6SMatthias Ringwald 
246*3deb3ec6SMatthias Ringwald     l2cap_send_prepared_connectionless(peripheral_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, 5);
247*3deb3ec6SMatthias Ringwald }
248*3deb3ec6SMatthias Ringwald 
249*3deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
250*3deb3ec6SMatthias Ringwald static void att_find_by_type_value_request(uint16_t request_type, uint16_t attribute_group_type, uint16_t peripheral_handle, uint16_t start_handle, uint16_t end_handle, uint8_t * value, uint16_t value_size){
251*3deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
252*3deb3ec6SMatthias Ringwald     uint8_t * request = l2cap_get_outgoing_buffer();
253*3deb3ec6SMatthias Ringwald 
254*3deb3ec6SMatthias Ringwald     request[0] = request_type;
255*3deb3ec6SMatthias Ringwald     bt_store_16(request, 1, start_handle);
256*3deb3ec6SMatthias Ringwald     bt_store_16(request, 3, end_handle);
257*3deb3ec6SMatthias Ringwald     bt_store_16(request, 5, attribute_group_type);
258*3deb3ec6SMatthias Ringwald     memcpy(&request[7], value, value_size);
259*3deb3ec6SMatthias Ringwald 
260*3deb3ec6SMatthias Ringwald     l2cap_send_prepared_connectionless(peripheral_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, 7+value_size);
261*3deb3ec6SMatthias Ringwald }
262*3deb3ec6SMatthias Ringwald 
263*3deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
264*3deb3ec6SMatthias Ringwald static void att_read_by_type_or_group_request_for_uuid16(uint16_t request_type, uint16_t uuid16, uint16_t peripheral_handle, uint16_t start_handle, uint16_t end_handle){
265*3deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
266*3deb3ec6SMatthias Ringwald     uint8_t * request = l2cap_get_outgoing_buffer();
267*3deb3ec6SMatthias Ringwald     request[0] = request_type;
268*3deb3ec6SMatthias Ringwald     bt_store_16(request, 1, start_handle);
269*3deb3ec6SMatthias Ringwald     bt_store_16(request, 3, end_handle);
270*3deb3ec6SMatthias Ringwald     bt_store_16(request, 5, uuid16);
271*3deb3ec6SMatthias Ringwald 
272*3deb3ec6SMatthias Ringwald     l2cap_send_prepared_connectionless(peripheral_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, 7);
273*3deb3ec6SMatthias Ringwald }
274*3deb3ec6SMatthias Ringwald 
275*3deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
276*3deb3ec6SMatthias Ringwald static void att_read_by_type_or_group_request_for_uuid128(uint16_t request_type, uint8_t * uuid128, uint16_t peripheral_handle, uint16_t start_handle, uint16_t end_handle){
277*3deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
278*3deb3ec6SMatthias Ringwald     uint8_t * request = l2cap_get_outgoing_buffer();
279*3deb3ec6SMatthias Ringwald     request[0] = request_type;
280*3deb3ec6SMatthias Ringwald     bt_store_16(request, 1, start_handle);
281*3deb3ec6SMatthias Ringwald     bt_store_16(request, 3, end_handle);
282*3deb3ec6SMatthias Ringwald     swap128(uuid128, &request[5]);
283*3deb3ec6SMatthias Ringwald 
284*3deb3ec6SMatthias Ringwald     l2cap_send_prepared_connectionless(peripheral_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, 21);
285*3deb3ec6SMatthias Ringwald }
286*3deb3ec6SMatthias Ringwald 
287*3deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
288*3deb3ec6SMatthias Ringwald static void att_read_request(uint16_t request_type, uint16_t peripheral_handle, uint16_t attribute_handle){
289*3deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
290*3deb3ec6SMatthias Ringwald     uint8_t * request = l2cap_get_outgoing_buffer();
291*3deb3ec6SMatthias Ringwald     request[0] = request_type;
292*3deb3ec6SMatthias Ringwald     bt_store_16(request, 1, attribute_handle);
293*3deb3ec6SMatthias Ringwald 
294*3deb3ec6SMatthias Ringwald     l2cap_send_prepared_connectionless(peripheral_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, 3);
295*3deb3ec6SMatthias Ringwald }
296*3deb3ec6SMatthias Ringwald 
297*3deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
298*3deb3ec6SMatthias Ringwald static void att_read_blob_request(uint16_t request_type, uint16_t peripheral_handle, uint16_t attribute_handle, uint16_t value_offset){
299*3deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
300*3deb3ec6SMatthias Ringwald     uint8_t * request = l2cap_get_outgoing_buffer();
301*3deb3ec6SMatthias Ringwald     request[0] = request_type;
302*3deb3ec6SMatthias Ringwald     bt_store_16(request, 1, attribute_handle);
303*3deb3ec6SMatthias Ringwald     bt_store_16(request, 3, value_offset);
304*3deb3ec6SMatthias Ringwald 
305*3deb3ec6SMatthias Ringwald     l2cap_send_prepared_connectionless(peripheral_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, 5);
306*3deb3ec6SMatthias Ringwald }
307*3deb3ec6SMatthias Ringwald 
308*3deb3ec6SMatthias Ringwald static void att_read_multiple_request(uint16_t peripheral_handle, uint16_t num_value_handles, uint16_t * value_handles){
309*3deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
310*3deb3ec6SMatthias Ringwald     uint8_t * request = l2cap_get_outgoing_buffer();
311*3deb3ec6SMatthias Ringwald     request[0] = ATT_READ_MULTIPLE_REQUEST;
312*3deb3ec6SMatthias Ringwald     int i;
313*3deb3ec6SMatthias Ringwald     int offset = 1;
314*3deb3ec6SMatthias Ringwald     for (i=0;i<num_value_handles;i++){
315*3deb3ec6SMatthias Ringwald         bt_store_16(request, offset, value_handles[i]);
316*3deb3ec6SMatthias Ringwald         offset += 2;
317*3deb3ec6SMatthias Ringwald     }
318*3deb3ec6SMatthias Ringwald     l2cap_send_prepared_connectionless(peripheral_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, offset);
319*3deb3ec6SMatthias Ringwald }
320*3deb3ec6SMatthias Ringwald 
321*3deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
322*3deb3ec6SMatthias Ringwald static void att_signed_write_request(uint16_t request_type, uint16_t peripheral_handle, uint16_t attribute_handle, uint16_t value_length, uint8_t * value, uint32_t sign_counter, uint8_t sgn[8]){
323*3deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
324*3deb3ec6SMatthias Ringwald     uint8_t * request = l2cap_get_outgoing_buffer();
325*3deb3ec6SMatthias Ringwald     request[0] = request_type;
326*3deb3ec6SMatthias Ringwald     bt_store_16(request, 1, attribute_handle);
327*3deb3ec6SMatthias Ringwald     memcpy(&request[3], value, value_length);
328*3deb3ec6SMatthias Ringwald     bt_store_32(request, 3 + value_length, sign_counter);
329*3deb3ec6SMatthias Ringwald     swap64(sgn, &request[3 + value_length + 4]);
330*3deb3ec6SMatthias Ringwald     l2cap_send_prepared_connectionless(peripheral_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, 3 + value_length + 12);
331*3deb3ec6SMatthias Ringwald }
332*3deb3ec6SMatthias Ringwald 
333*3deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
334*3deb3ec6SMatthias Ringwald static void att_write_request(uint16_t request_type, uint16_t peripheral_handle, uint16_t attribute_handle, uint16_t value_length, uint8_t * value){
335*3deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
336*3deb3ec6SMatthias Ringwald     uint8_t * request = l2cap_get_outgoing_buffer();
337*3deb3ec6SMatthias Ringwald     request[0] = request_type;
338*3deb3ec6SMatthias Ringwald     bt_store_16(request, 1, attribute_handle);
339*3deb3ec6SMatthias Ringwald     memcpy(&request[3], value, value_length);
340*3deb3ec6SMatthias Ringwald 
341*3deb3ec6SMatthias Ringwald     l2cap_send_prepared_connectionless(peripheral_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, 3 + value_length);
342*3deb3ec6SMatthias Ringwald }
343*3deb3ec6SMatthias Ringwald 
344*3deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
345*3deb3ec6SMatthias Ringwald static void att_execute_write_request(uint16_t request_type, uint16_t peripheral_handle, uint8_t execute_write){
346*3deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
347*3deb3ec6SMatthias Ringwald     uint8_t * request = l2cap_get_outgoing_buffer();
348*3deb3ec6SMatthias Ringwald     request[0] = request_type;
349*3deb3ec6SMatthias Ringwald     request[1] = execute_write;
350*3deb3ec6SMatthias Ringwald     l2cap_send_prepared_connectionless(peripheral_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, 2);
351*3deb3ec6SMatthias Ringwald }
352*3deb3ec6SMatthias Ringwald 
353*3deb3ec6SMatthias Ringwald // precondition: can_send_packet_now == TRUE
354*3deb3ec6SMatthias Ringwald static void att_prepare_write_request(uint16_t request_type, uint16_t peripheral_handle,  uint16_t attribute_handle, uint16_t value_offset, uint16_t blob_length, uint8_t * value){
355*3deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
356*3deb3ec6SMatthias Ringwald     uint8_t * request = l2cap_get_outgoing_buffer();
357*3deb3ec6SMatthias Ringwald     request[0] = request_type;
358*3deb3ec6SMatthias Ringwald     bt_store_16(request, 1, attribute_handle);
359*3deb3ec6SMatthias Ringwald     bt_store_16(request, 3, value_offset);
360*3deb3ec6SMatthias Ringwald     memcpy(&request[5], &value[value_offset], blob_length);
361*3deb3ec6SMatthias Ringwald 
362*3deb3ec6SMatthias Ringwald     l2cap_send_prepared_connectionless(peripheral_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, 5+blob_length);
363*3deb3ec6SMatthias Ringwald }
364*3deb3ec6SMatthias Ringwald 
365*3deb3ec6SMatthias Ringwald static void att_exchange_mtu_request(uint16_t peripheral_handle){
366*3deb3ec6SMatthias Ringwald     uint16_t mtu = l2cap_max_le_mtu();
367*3deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
368*3deb3ec6SMatthias Ringwald     uint8_t * request = l2cap_get_outgoing_buffer();
369*3deb3ec6SMatthias Ringwald     request[0] = ATT_EXCHANGE_MTU_REQUEST;
370*3deb3ec6SMatthias Ringwald     bt_store_16(request, 1, mtu);
371*3deb3ec6SMatthias Ringwald     l2cap_send_prepared_connectionless(peripheral_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, 3);
372*3deb3ec6SMatthias Ringwald }
373*3deb3ec6SMatthias Ringwald 
374*3deb3ec6SMatthias Ringwald static uint16_t write_blob_length(gatt_client_t * peripheral){
375*3deb3ec6SMatthias Ringwald     uint16_t max_blob_length = peripheral_mtu(peripheral) - 5;
376*3deb3ec6SMatthias Ringwald     if (peripheral->attribute_offset >= peripheral->attribute_length) {
377*3deb3ec6SMatthias Ringwald         return 0;
378*3deb3ec6SMatthias Ringwald     }
379*3deb3ec6SMatthias Ringwald     uint16_t rest_length = peripheral->attribute_length - peripheral->attribute_offset;
380*3deb3ec6SMatthias Ringwald     if (max_blob_length > rest_length){
381*3deb3ec6SMatthias Ringwald         return rest_length;
382*3deb3ec6SMatthias Ringwald     }
383*3deb3ec6SMatthias Ringwald     return max_blob_length;
384*3deb3ec6SMatthias Ringwald }
385*3deb3ec6SMatthias Ringwald 
386*3deb3ec6SMatthias Ringwald static void send_gatt_services_request(gatt_client_t *peripheral){
387*3deb3ec6SMatthias Ringwald     att_read_by_type_or_group_request_for_uuid16(ATT_READ_BY_GROUP_TYPE_REQUEST, GATT_PRIMARY_SERVICE_UUID, peripheral->handle, peripheral->start_group_handle, peripheral->end_group_handle);
388*3deb3ec6SMatthias Ringwald }
389*3deb3ec6SMatthias Ringwald 
390*3deb3ec6SMatthias Ringwald static void send_gatt_by_uuid_request(gatt_client_t *peripheral, uint16_t attribute_group_type){
391*3deb3ec6SMatthias Ringwald     if (peripheral->uuid16){
392*3deb3ec6SMatthias Ringwald         uint8_t uuid16[2];
393*3deb3ec6SMatthias Ringwald         bt_store_16(uuid16, 0, peripheral->uuid16);
394*3deb3ec6SMatthias Ringwald         att_find_by_type_value_request(ATT_FIND_BY_TYPE_VALUE_REQUEST, attribute_group_type, peripheral->handle, peripheral->start_group_handle, peripheral->end_group_handle, uuid16, 2);
395*3deb3ec6SMatthias Ringwald         return;
396*3deb3ec6SMatthias Ringwald     }
397*3deb3ec6SMatthias Ringwald     uint8_t uuid128[16];
398*3deb3ec6SMatthias Ringwald     swap128(peripheral->uuid128, uuid128);
399*3deb3ec6SMatthias Ringwald     att_find_by_type_value_request(ATT_FIND_BY_TYPE_VALUE_REQUEST, attribute_group_type, peripheral->handle, peripheral->start_group_handle, peripheral->end_group_handle, uuid128, 16);
400*3deb3ec6SMatthias Ringwald }
401*3deb3ec6SMatthias Ringwald 
402*3deb3ec6SMatthias Ringwald static void send_gatt_services_by_uuid_request(gatt_client_t *peripheral){
403*3deb3ec6SMatthias Ringwald     send_gatt_by_uuid_request(peripheral, GATT_PRIMARY_SERVICE_UUID);
404*3deb3ec6SMatthias Ringwald }
405*3deb3ec6SMatthias Ringwald 
406*3deb3ec6SMatthias Ringwald static void send_gatt_included_service_uuid_request(gatt_client_t *peripheral){
407*3deb3ec6SMatthias Ringwald     att_read_request(ATT_READ_REQUEST, peripheral->handle, peripheral->query_start_handle);
408*3deb3ec6SMatthias Ringwald }
409*3deb3ec6SMatthias Ringwald 
410*3deb3ec6SMatthias Ringwald static void send_gatt_included_service_request(gatt_client_t *peripheral){
411*3deb3ec6SMatthias Ringwald     att_read_by_type_or_group_request_for_uuid16(ATT_READ_BY_TYPE_REQUEST, GATT_INCLUDE_SERVICE_UUID, peripheral->handle, peripheral->start_group_handle, peripheral->end_group_handle);
412*3deb3ec6SMatthias Ringwald }
413*3deb3ec6SMatthias Ringwald 
414*3deb3ec6SMatthias Ringwald static void send_gatt_characteristic_request(gatt_client_t *peripheral){
415*3deb3ec6SMatthias Ringwald     att_read_by_type_or_group_request_for_uuid16(ATT_READ_BY_TYPE_REQUEST, GATT_CHARACTERISTICS_UUID, peripheral->handle, peripheral->start_group_handle, peripheral->end_group_handle);
416*3deb3ec6SMatthias Ringwald }
417*3deb3ec6SMatthias Ringwald 
418*3deb3ec6SMatthias Ringwald static void send_gatt_characteristic_descriptor_request(gatt_client_t *peripheral){
419*3deb3ec6SMatthias Ringwald     att_find_information_request(ATT_FIND_INFORMATION_REQUEST, peripheral->handle, peripheral->start_group_handle, peripheral->end_group_handle);
420*3deb3ec6SMatthias Ringwald }
421*3deb3ec6SMatthias Ringwald 
422*3deb3ec6SMatthias Ringwald static void send_gatt_read_characteristic_value_request(gatt_client_t *peripheral){
423*3deb3ec6SMatthias Ringwald     att_read_request(ATT_READ_REQUEST, peripheral->handle, peripheral->attribute_handle);
424*3deb3ec6SMatthias Ringwald }
425*3deb3ec6SMatthias Ringwald 
426*3deb3ec6SMatthias Ringwald static void send_gatt_read_by_type_request(gatt_client_t * peripheral){
427*3deb3ec6SMatthias Ringwald     if (peripheral->uuid16){
428*3deb3ec6SMatthias Ringwald         att_read_by_type_or_group_request_for_uuid16(ATT_READ_BY_TYPE_REQUEST, peripheral->uuid16, peripheral->handle, peripheral->start_group_handle, peripheral->end_group_handle);
429*3deb3ec6SMatthias Ringwald     } else {
430*3deb3ec6SMatthias Ringwald         att_read_by_type_or_group_request_for_uuid128(ATT_READ_BY_TYPE_REQUEST, peripheral->uuid128, peripheral->handle, peripheral->start_group_handle, peripheral->end_group_handle);
431*3deb3ec6SMatthias Ringwald     }
432*3deb3ec6SMatthias Ringwald }
433*3deb3ec6SMatthias Ringwald 
434*3deb3ec6SMatthias Ringwald static void send_gatt_read_blob_request(gatt_client_t *peripheral){
435*3deb3ec6SMatthias Ringwald     att_read_blob_request(ATT_READ_BLOB_REQUEST, peripheral->handle, peripheral->attribute_handle, peripheral->attribute_offset);
436*3deb3ec6SMatthias Ringwald }
437*3deb3ec6SMatthias Ringwald 
438*3deb3ec6SMatthias Ringwald static void send_gatt_read_multiple_request(gatt_client_t * peripheral){
439*3deb3ec6SMatthias Ringwald     att_read_multiple_request(peripheral->handle, peripheral->read_multiple_handle_count, peripheral->read_multiple_handles);
440*3deb3ec6SMatthias Ringwald }
441*3deb3ec6SMatthias Ringwald 
442*3deb3ec6SMatthias Ringwald static void send_gatt_write_attribute_value_request(gatt_client_t * peripheral){
443*3deb3ec6SMatthias Ringwald     att_write_request(ATT_WRITE_REQUEST, peripheral->handle, peripheral->attribute_handle, peripheral->attribute_length, peripheral->attribute_value);
444*3deb3ec6SMatthias Ringwald }
445*3deb3ec6SMatthias Ringwald 
446*3deb3ec6SMatthias Ringwald static void send_gatt_write_client_characteristic_configuration_request(gatt_client_t * peripheral){
447*3deb3ec6SMatthias Ringwald     att_write_request(ATT_WRITE_REQUEST, peripheral->handle, peripheral->client_characteristic_configuration_handle, 2, peripheral->client_characteristic_configuration_value);
448*3deb3ec6SMatthias Ringwald }
449*3deb3ec6SMatthias Ringwald 
450*3deb3ec6SMatthias Ringwald static void send_gatt_prepare_write_request(gatt_client_t * peripheral){
451*3deb3ec6SMatthias Ringwald     att_prepare_write_request(ATT_PREPARE_WRITE_REQUEST, peripheral->handle, peripheral->attribute_handle, peripheral->attribute_offset, write_blob_length(peripheral), peripheral->attribute_value);
452*3deb3ec6SMatthias Ringwald }
453*3deb3ec6SMatthias Ringwald 
454*3deb3ec6SMatthias Ringwald static void send_gatt_execute_write_request(gatt_client_t * peripheral){
455*3deb3ec6SMatthias Ringwald     att_execute_write_request(ATT_EXECUTE_WRITE_REQUEST, peripheral->handle, 1);
456*3deb3ec6SMatthias Ringwald }
457*3deb3ec6SMatthias Ringwald 
458*3deb3ec6SMatthias Ringwald static void send_gatt_cancel_prepared_write_request(gatt_client_t * peripheral){
459*3deb3ec6SMatthias Ringwald     att_execute_write_request(ATT_EXECUTE_WRITE_REQUEST, peripheral->handle, 0);
460*3deb3ec6SMatthias Ringwald }
461*3deb3ec6SMatthias Ringwald 
462*3deb3ec6SMatthias Ringwald static void send_gatt_read_client_characteristic_configuration_request(gatt_client_t * peripheral){
463*3deb3ec6SMatthias Ringwald     att_read_by_type_or_group_request_for_uuid16(ATT_READ_BY_TYPE_REQUEST, GATT_CLIENT_CHARACTERISTICS_CONFIGURATION, peripheral->handle, peripheral->start_group_handle, peripheral->end_group_handle);
464*3deb3ec6SMatthias Ringwald }
465*3deb3ec6SMatthias Ringwald 
466*3deb3ec6SMatthias Ringwald static void send_gatt_read_characteristic_descriptor_request(gatt_client_t * peripheral){
467*3deb3ec6SMatthias Ringwald     att_read_request(ATT_READ_REQUEST, peripheral->handle, peripheral->attribute_handle);
468*3deb3ec6SMatthias Ringwald }
469*3deb3ec6SMatthias Ringwald 
470*3deb3ec6SMatthias Ringwald static void send_gatt_signed_write_request(gatt_client_t * peripheral, uint32_t sign_counter){
471*3deb3ec6SMatthias Ringwald     att_signed_write_request(ATT_SIGNED_WRITE_COMMAND, peripheral->handle, peripheral->attribute_handle, peripheral->attribute_length, peripheral->attribute_value, sign_counter, peripheral->cmac);
472*3deb3ec6SMatthias Ringwald }
473*3deb3ec6SMatthias Ringwald 
474*3deb3ec6SMatthias Ringwald static uint16_t get_last_result_handle_from_service_list(uint8_t * packet, uint16_t size){
475*3deb3ec6SMatthias Ringwald     uint8_t attr_length = packet[1];
476*3deb3ec6SMatthias Ringwald     return READ_BT_16(packet, size - attr_length + 2);
477*3deb3ec6SMatthias Ringwald }
478*3deb3ec6SMatthias Ringwald 
479*3deb3ec6SMatthias Ringwald static uint16_t get_last_result_handle_from_characteristics_list(uint8_t * packet, uint16_t size){
480*3deb3ec6SMatthias Ringwald     uint8_t attr_length = packet[1];
481*3deb3ec6SMatthias Ringwald     return READ_BT_16(packet, size - attr_length + 3);
482*3deb3ec6SMatthias Ringwald }
483*3deb3ec6SMatthias Ringwald 
484*3deb3ec6SMatthias Ringwald static uint16_t get_last_result_handle_from_included_services_list(uint8_t * packet, uint16_t size){
485*3deb3ec6SMatthias Ringwald     uint8_t attr_length = packet[1];
486*3deb3ec6SMatthias Ringwald     return READ_BT_16(packet, size - attr_length);
487*3deb3ec6SMatthias Ringwald }
488*3deb3ec6SMatthias Ringwald 
489*3deb3ec6SMatthias Ringwald static void gatt_client_handle_transaction_complete(gatt_client_t * peripheral){
490*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_READY;
491*3deb3ec6SMatthias Ringwald     gatt_client_timeout_stop(peripheral);
492*3deb3ec6SMatthias Ringwald }
493*3deb3ec6SMatthias Ringwald 
494*3deb3ec6SMatthias Ringwald static void emit_event_new(uint16_t gatt_client_id, uint8_t * packet, uint16_t size){
495*3deb3ec6SMatthias Ringwald     gatt_client_callback_t gatt_client_callback = gatt_client_callback_for_id_new(gatt_client_id);
496*3deb3ec6SMatthias Ringwald     if (!gatt_client_callback) return;
497*3deb3ec6SMatthias Ringwald     (*gatt_client_callback)(HCI_EVENT_PACKET, packet, size);
498*3deb3ec6SMatthias Ringwald }
499*3deb3ec6SMatthias Ringwald 
500*3deb3ec6SMatthias Ringwald static void emit_event_to_all_subclients_new(uint8_t * packet, uint16_t size){
501*3deb3ec6SMatthias Ringwald     linked_list_iterator_t it;
502*3deb3ec6SMatthias Ringwald     linked_list_iterator_init(&it, &gatt_subclients);
503*3deb3ec6SMatthias Ringwald     while (linked_list_iterator_has_next(&it)){
504*3deb3ec6SMatthias Ringwald         gatt_subclient_t * subclient = (gatt_subclient_t*) linked_list_iterator_next(&it);
505*3deb3ec6SMatthias Ringwald         (*subclient->callback)(HCI_EVENT_PACKET, packet, size);
506*3deb3ec6SMatthias Ringwald     }
507*3deb3ec6SMatthias Ringwald }
508*3deb3ec6SMatthias Ringwald 
509*3deb3ec6SMatthias Ringwald static void emit_gatt_complete_event(gatt_client_t * peripheral, uint8_t status){
510*3deb3ec6SMatthias Ringwald     // @format H1
511*3deb3ec6SMatthias Ringwald     uint8_t packet[5];
512*3deb3ec6SMatthias Ringwald     packet[0] = GATT_QUERY_COMPLETE;
513*3deb3ec6SMatthias Ringwald     packet[1] = 3;
514*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 2, peripheral->handle);
515*3deb3ec6SMatthias Ringwald     packet[4] = status;
516*3deb3ec6SMatthias Ringwald     emit_event_new(peripheral->subclient_id, packet, sizeof(packet));
517*3deb3ec6SMatthias Ringwald }
518*3deb3ec6SMatthias Ringwald 
519*3deb3ec6SMatthias Ringwald static void emit_gatt_service_query_result_event(gatt_client_t * peripheral, uint16_t start_group_handle, uint16_t end_group_handle, uint8_t * uuid128){
520*3deb3ec6SMatthias Ringwald     // @format HX
521*3deb3ec6SMatthias Ringwald     uint8_t packet[24];
522*3deb3ec6SMatthias Ringwald     packet[0] = GATT_SERVICE_QUERY_RESULT;
523*3deb3ec6SMatthias Ringwald     packet[1] = sizeof(packet) - 2;
524*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 2, peripheral->handle);
525*3deb3ec6SMatthias Ringwald     ///
526*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 4, start_group_handle);
527*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 6, end_group_handle);
528*3deb3ec6SMatthias Ringwald     swap128(uuid128, &packet[8]);
529*3deb3ec6SMatthias Ringwald     emit_event_new(peripheral->subclient_id, packet, sizeof(packet));
530*3deb3ec6SMatthias Ringwald }
531*3deb3ec6SMatthias Ringwald 
532*3deb3ec6SMatthias Ringwald static void emit_gatt_included_service_query_result_event(gatt_client_t * peripheral, uint16_t include_handle, uint16_t start_group_handle, uint16_t end_group_handle, uint8_t * uuid128){
533*3deb3ec6SMatthias Ringwald     // @format HX
534*3deb3ec6SMatthias Ringwald     uint8_t packet[26];
535*3deb3ec6SMatthias Ringwald     packet[0] = GATT_INCLUDED_SERVICE_QUERY_RESULT;
536*3deb3ec6SMatthias Ringwald     packet[1] = sizeof(packet) - 2;
537*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 2, peripheral->handle);
538*3deb3ec6SMatthias Ringwald     ///
539*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 4, include_handle);
540*3deb3ec6SMatthias Ringwald     //
541*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 6, start_group_handle);
542*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 8, end_group_handle);
543*3deb3ec6SMatthias Ringwald     swap128(uuid128, &packet[10]);
544*3deb3ec6SMatthias Ringwald     emit_event_new(peripheral->subclient_id, packet, sizeof(packet));
545*3deb3ec6SMatthias Ringwald }
546*3deb3ec6SMatthias Ringwald 
547*3deb3ec6SMatthias Ringwald static void emit_gatt_characteristic_query_result_event(gatt_client_t * peripheral, uint16_t start_handle, uint16_t value_handle, uint16_t end_handle,
548*3deb3ec6SMatthias Ringwald         uint16_t properties, uint8_t * uuid128){
549*3deb3ec6SMatthias Ringwald     // @format HY
550*3deb3ec6SMatthias Ringwald     uint8_t packet[28];
551*3deb3ec6SMatthias Ringwald     packet[0] = GATT_CHARACTERISTIC_QUERY_RESULT;
552*3deb3ec6SMatthias Ringwald     packet[1] = sizeof(packet) - 2;
553*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 2, peripheral->handle);
554*3deb3ec6SMatthias Ringwald     ///
555*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 4,  start_handle);
556*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 6,  value_handle);
557*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 8,  end_handle);
558*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 10, properties);
559*3deb3ec6SMatthias Ringwald     swap128(uuid128, &packet[12]);
560*3deb3ec6SMatthias Ringwald     emit_event_new(peripheral->subclient_id, packet, sizeof(packet));
561*3deb3ec6SMatthias Ringwald }
562*3deb3ec6SMatthias Ringwald 
563*3deb3ec6SMatthias Ringwald static void emit_gatt_all_characteristic_descriptors_result_event(
564*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral, uint16_t descriptor_handle, uint8_t * uuid128){
565*3deb3ec6SMatthias Ringwald     // @format HZ
566*3deb3ec6SMatthias Ringwald     uint8_t packet[22];
567*3deb3ec6SMatthias Ringwald     packet[0] = GATT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT;
568*3deb3ec6SMatthias Ringwald     packet[1] = sizeof(packet) - 2;
569*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 2, peripheral->handle);
570*3deb3ec6SMatthias Ringwald     ///
571*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 4,  descriptor_handle);
572*3deb3ec6SMatthias Ringwald     swap128(uuid128, &packet[6]);
573*3deb3ec6SMatthias Ringwald     emit_event_new(peripheral->subclient_id, packet, sizeof(packet));
574*3deb3ec6SMatthias Ringwald }
575*3deb3ec6SMatthias Ringwald ///
576*3deb3ec6SMatthias Ringwald 
577*3deb3ec6SMatthias Ringwald static void report_gatt_services(gatt_client_t * peripheral, uint8_t * packet,  uint16_t size){
578*3deb3ec6SMatthias Ringwald     uint8_t attr_length = packet[1];
579*3deb3ec6SMatthias Ringwald     uint8_t uuid_length = attr_length - 4;
580*3deb3ec6SMatthias Ringwald 
581*3deb3ec6SMatthias Ringwald     int i;
582*3deb3ec6SMatthias Ringwald     for (i = 2; i < size; i += attr_length){
583*3deb3ec6SMatthias Ringwald         uint16_t start_group_handle = READ_BT_16(packet,i);
584*3deb3ec6SMatthias Ringwald         uint16_t end_group_handle   = READ_BT_16(packet,i+2);
585*3deb3ec6SMatthias Ringwald         uint8_t  uuid128[16];
586*3deb3ec6SMatthias Ringwald         uint16_t uuid16 = 0;
587*3deb3ec6SMatthias Ringwald 
588*3deb3ec6SMatthias Ringwald         if (uuid_length == 2){
589*3deb3ec6SMatthias Ringwald             uuid16 = READ_BT_16(packet, i+4);
590*3deb3ec6SMatthias Ringwald             sdp_normalize_uuid((uint8_t*) &uuid128, uuid16);
591*3deb3ec6SMatthias Ringwald         } else {
592*3deb3ec6SMatthias Ringwald             swap128(&packet[i+4], uuid128);
593*3deb3ec6SMatthias Ringwald         }
594*3deb3ec6SMatthias Ringwald         emit_gatt_service_query_result_event(peripheral, start_group_handle, end_group_handle, uuid128);
595*3deb3ec6SMatthias Ringwald     }
596*3deb3ec6SMatthias Ringwald     // log_info("report_gatt_services for %02X done", peripheral->handle);
597*3deb3ec6SMatthias Ringwald }
598*3deb3ec6SMatthias Ringwald 
599*3deb3ec6SMatthias Ringwald // helper
600*3deb3ec6SMatthias Ringwald static void characteristic_start_found(gatt_client_t * peripheral, uint16_t start_handle, uint8_t properties, uint16_t value_handle, uint8_t * uuid, uint16_t uuid_length){
601*3deb3ec6SMatthias Ringwald     uint8_t uuid128[16];
602*3deb3ec6SMatthias Ringwald     uint16_t uuid16 = 0;
603*3deb3ec6SMatthias Ringwald     if (uuid_length == 2){
604*3deb3ec6SMatthias Ringwald         uuid16 = READ_BT_16(uuid, 0);
605*3deb3ec6SMatthias Ringwald         sdp_normalize_uuid((uint8_t*) uuid128, uuid16);
606*3deb3ec6SMatthias Ringwald     } else {
607*3deb3ec6SMatthias Ringwald         swap128(uuid, uuid128);
608*3deb3ec6SMatthias Ringwald     }
609*3deb3ec6SMatthias Ringwald 
610*3deb3ec6SMatthias Ringwald     if (peripheral->filter_with_uuid && memcmp(peripheral->uuid128, uuid128, 16) != 0) return;
611*3deb3ec6SMatthias Ringwald 
612*3deb3ec6SMatthias Ringwald     peripheral->characteristic_properties = properties;
613*3deb3ec6SMatthias Ringwald     peripheral->characteristic_start_handle = start_handle;
614*3deb3ec6SMatthias Ringwald     peripheral->attribute_handle = value_handle;
615*3deb3ec6SMatthias Ringwald 
616*3deb3ec6SMatthias Ringwald     if (peripheral->filter_with_uuid) return;
617*3deb3ec6SMatthias Ringwald 
618*3deb3ec6SMatthias Ringwald     peripheral->uuid16 = uuid16;
619*3deb3ec6SMatthias Ringwald     memcpy(peripheral->uuid128, uuid128, 16);
620*3deb3ec6SMatthias Ringwald }
621*3deb3ec6SMatthias Ringwald 
622*3deb3ec6SMatthias Ringwald static void characteristic_end_found(gatt_client_t * peripheral, uint16_t end_handle){
623*3deb3ec6SMatthias Ringwald     // TODO: stop searching if filter and uuid found
624*3deb3ec6SMatthias Ringwald 
625*3deb3ec6SMatthias Ringwald     if (!peripheral->characteristic_start_handle) return;
626*3deb3ec6SMatthias Ringwald 
627*3deb3ec6SMatthias Ringwald     emit_gatt_characteristic_query_result_event(peripheral, peripheral->characteristic_start_handle, peripheral->attribute_handle,
628*3deb3ec6SMatthias Ringwald         end_handle, peripheral->characteristic_properties, peripheral->uuid128);
629*3deb3ec6SMatthias Ringwald 
630*3deb3ec6SMatthias Ringwald     peripheral->characteristic_start_handle = 0;
631*3deb3ec6SMatthias Ringwald }
632*3deb3ec6SMatthias Ringwald 
633*3deb3ec6SMatthias Ringwald static void report_gatt_characteristics(gatt_client_t * peripheral, uint8_t * packet,  uint16_t size){
634*3deb3ec6SMatthias Ringwald     uint8_t attr_length = packet[1];
635*3deb3ec6SMatthias Ringwald     uint8_t uuid_length = attr_length - 5;
636*3deb3ec6SMatthias Ringwald     int i;
637*3deb3ec6SMatthias Ringwald     for (i = 2; i < size; i += attr_length){
638*3deb3ec6SMatthias Ringwald         uint16_t start_handle = READ_BT_16(packet, i);
639*3deb3ec6SMatthias Ringwald         uint8_t  properties = packet[i+2];
640*3deb3ec6SMatthias Ringwald         uint16_t value_handle = READ_BT_16(packet, i+3);
641*3deb3ec6SMatthias Ringwald         characteristic_end_found(peripheral, start_handle-1);
642*3deb3ec6SMatthias Ringwald         characteristic_start_found(peripheral, start_handle, properties, value_handle, &packet[i+5], uuid_length);
643*3deb3ec6SMatthias Ringwald     }
644*3deb3ec6SMatthias Ringwald }
645*3deb3ec6SMatthias Ringwald 
646*3deb3ec6SMatthias Ringwald static void report_gatt_included_service_uuid16(gatt_client_t * peripheral, uint16_t include_handle, uint16_t uuid16){
647*3deb3ec6SMatthias Ringwald     uint8_t normalized_uuid128[16];
648*3deb3ec6SMatthias Ringwald     sdp_normalize_uuid(normalized_uuid128, uuid16);
649*3deb3ec6SMatthias Ringwald     emit_gatt_included_service_query_result_event(peripheral, include_handle, peripheral->query_start_handle,
650*3deb3ec6SMatthias Ringwald         peripheral->query_end_handle, normalized_uuid128);
651*3deb3ec6SMatthias Ringwald }
652*3deb3ec6SMatthias Ringwald 
653*3deb3ec6SMatthias Ringwald static void report_gatt_included_service_uuid128(gatt_client_t * peripheral, uint16_t include_handle, uint8_t *uuid128){
654*3deb3ec6SMatthias Ringwald     emit_gatt_included_service_query_result_event(peripheral, include_handle, peripheral->query_start_handle,
655*3deb3ec6SMatthias Ringwald         peripheral->query_end_handle, uuid128);
656*3deb3ec6SMatthias Ringwald }
657*3deb3ec6SMatthias Ringwald 
658*3deb3ec6SMatthias Ringwald // @returns packet pointer
659*3deb3ec6SMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite HCI + L2CAP packet headers
660*3deb3ec6SMatthias Ringwald static const int characteristic_value_event_header_size = 8;
661*3deb3ec6SMatthias Ringwald static uint8_t * setup_characteristic_value_packet(uint8_t type, uint16_t con_handle, uint16_t attribute_handle, uint8_t * value, uint16_t length){
662*3deb3ec6SMatthias Ringwald     // before the value inside the ATT PDU
663*3deb3ec6SMatthias Ringwald     uint8_t * packet = value - characteristic_value_event_header_size;
664*3deb3ec6SMatthias Ringwald     packet[0] = type;
665*3deb3ec6SMatthias Ringwald     packet[1] = characteristic_value_event_header_size - 2 + length;
666*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 2, con_handle);
667*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 4, attribute_handle);
668*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 6, length);
669*3deb3ec6SMatthias Ringwald     return packet;
670*3deb3ec6SMatthias Ringwald }
671*3deb3ec6SMatthias Ringwald 
672*3deb3ec6SMatthias Ringwald // @returns packet pointer
673*3deb3ec6SMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes
674*3deb3ec6SMatthias Ringwald static const int long_characteristic_value_event_header_size = 10;
675*3deb3ec6SMatthias Ringwald static uint8_t * setup_long_characteristic_value_packet(uint8_t type, uint16_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * value, uint16_t length){
676*3deb3ec6SMatthias Ringwald #if defined(HCI_INCOMING_PRE_BUFFER_SIZE) && (HCI_INCOMING_PRE_BUFFER_SIZE >= 10 - 8) // L2CAP Header (4) - ACL Header (4)
677*3deb3ec6SMatthias Ringwald     // before the value inside the ATT PDU
678*3deb3ec6SMatthias Ringwald     uint8_t * packet = value - long_characteristic_value_event_header_size;
679*3deb3ec6SMatthias Ringwald     packet[0] = type;
680*3deb3ec6SMatthias Ringwald     packet[1] = long_characteristic_value_event_header_size - 2 + length;
681*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 2, con_handle);
682*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 4, attribute_handle);
683*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 6, offset);
684*3deb3ec6SMatthias Ringwald     bt_store_16(packet, 8, length);
685*3deb3ec6SMatthias Ringwald     return packet;
686*3deb3ec6SMatthias Ringwald #else
687*3deb3ec6SMatthias Ringwald     log_error("HCI_INCOMING_PRE_BUFFER_SIZE >= 2 required for long characteristic reads");
688*3deb3ec6SMatthias Ringwald     return NULL;
689*3deb3ec6SMatthias Ringwald #endif
690*3deb3ec6SMatthias Ringwald }
691*3deb3ec6SMatthias Ringwald 
692*3deb3ec6SMatthias Ringwald 
693*3deb3ec6SMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes
694*3deb3ec6SMatthias Ringwald static void report_gatt_notification(uint16_t con_handle, uint16_t value_handle, uint8_t * value, int length){
695*3deb3ec6SMatthias Ringwald     uint8_t * packet = setup_characteristic_value_packet(GATT_NOTIFICATION, con_handle, value_handle, value, length);
696*3deb3ec6SMatthias Ringwald     emit_event_to_all_subclients_new(packet, characteristic_value_event_header_size + length);
697*3deb3ec6SMatthias Ringwald }
698*3deb3ec6SMatthias Ringwald 
699*3deb3ec6SMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes
700*3deb3ec6SMatthias Ringwald static void report_gatt_indication(uint16_t con_handle, uint16_t value_handle, uint8_t * value, int length){
701*3deb3ec6SMatthias Ringwald     uint8_t * packet = setup_characteristic_value_packet(GATT_INDICATION, con_handle, value_handle, value, length);
702*3deb3ec6SMatthias Ringwald     emit_event_to_all_subclients_new(packet, characteristic_value_event_header_size + length);
703*3deb3ec6SMatthias Ringwald }
704*3deb3ec6SMatthias Ringwald 
705*3deb3ec6SMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes
706*3deb3ec6SMatthias Ringwald static void report_gatt_characteristic_value(gatt_client_t * peripheral, uint16_t attribute_handle, uint8_t * value, uint16_t length){
707*3deb3ec6SMatthias Ringwald     uint8_t * packet = setup_characteristic_value_packet(GATT_CHARACTERISTIC_VALUE_QUERY_RESULT, peripheral->handle, attribute_handle, value, length);
708*3deb3ec6SMatthias Ringwald     emit_event_new(peripheral->subclient_id, packet, characteristic_value_event_header_size + length);
709*3deb3ec6SMatthias Ringwald }
710*3deb3ec6SMatthias Ringwald 
711*3deb3ec6SMatthias Ringwald // @note assume that value is part of an l2cap buffer - overwrite parts of the HCI/L2CAP/ATT packet (4/4/3) bytes
712*3deb3ec6SMatthias Ringwald static void report_gatt_long_characteristic_value_blob(gatt_client_t * peripheral, uint16_t attribute_handle, uint8_t * blob, uint16_t blob_length, int value_offset){
713*3deb3ec6SMatthias Ringwald     uint8_t * packet = setup_long_characteristic_value_packet(GATT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT, peripheral->handle, attribute_handle, value_offset, blob, blob_length);
714*3deb3ec6SMatthias Ringwald     if (!packet) return;
715*3deb3ec6SMatthias Ringwald     emit_event_new(peripheral->subclient_id, packet, blob_length + long_characteristic_value_event_header_size);
716*3deb3ec6SMatthias Ringwald }
717*3deb3ec6SMatthias Ringwald 
718*3deb3ec6SMatthias Ringwald static void report_gatt_characteristic_descriptor(gatt_client_t * peripheral, uint16_t descriptor_handle, uint8_t *value, uint16_t value_length, uint16_t value_offset){
719*3deb3ec6SMatthias Ringwald     uint8_t * packet = setup_characteristic_value_packet(GATT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT, peripheral->handle, descriptor_handle, value, value_length);
720*3deb3ec6SMatthias Ringwald     emit_event_new(peripheral->subclient_id, packet, value_length + 8);
721*3deb3ec6SMatthias Ringwald }
722*3deb3ec6SMatthias Ringwald 
723*3deb3ec6SMatthias Ringwald static void report_gatt_long_characteristic_descriptor(gatt_client_t * peripheral, uint16_t descriptor_handle, uint8_t *blob, uint16_t blob_length, uint16_t value_offset){
724*3deb3ec6SMatthias Ringwald     uint8_t * packet = setup_long_characteristic_value_packet(GATT_LONG_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT, peripheral->handle, descriptor_handle, value_offset, blob, blob_length);
725*3deb3ec6SMatthias Ringwald     if (!packet) return;
726*3deb3ec6SMatthias Ringwald     emit_event_new(peripheral->subclient_id, packet, blob_length + long_characteristic_value_event_header_size);
727*3deb3ec6SMatthias Ringwald }
728*3deb3ec6SMatthias Ringwald 
729*3deb3ec6SMatthias Ringwald static void report_gatt_all_characteristic_descriptors(gatt_client_t * peripheral, uint8_t * packet, uint16_t size, uint16_t pair_size){
730*3deb3ec6SMatthias Ringwald     int i;
731*3deb3ec6SMatthias Ringwald     for (i = 0; i<size; i+=pair_size){
732*3deb3ec6SMatthias Ringwald         uint16_t descriptor_handle = READ_BT_16(packet,i);
733*3deb3ec6SMatthias Ringwald         uint8_t uuid128[16];
734*3deb3ec6SMatthias Ringwald         uint16_t uuid16 = 0;
735*3deb3ec6SMatthias Ringwald         if (pair_size == 4){
736*3deb3ec6SMatthias Ringwald             uuid16 = READ_BT_16(packet,i+2);
737*3deb3ec6SMatthias Ringwald             sdp_normalize_uuid(uuid128, uuid16);
738*3deb3ec6SMatthias Ringwald         } else {
739*3deb3ec6SMatthias Ringwald             swap128(&packet[i+2], uuid128);
740*3deb3ec6SMatthias Ringwald         }
741*3deb3ec6SMatthias Ringwald         emit_gatt_all_characteristic_descriptors_result_event(peripheral, descriptor_handle, uuid128);
742*3deb3ec6SMatthias Ringwald     }
743*3deb3ec6SMatthias Ringwald 
744*3deb3ec6SMatthias Ringwald }
745*3deb3ec6SMatthias Ringwald 
746*3deb3ec6SMatthias Ringwald static int is_query_done(gatt_client_t * peripheral, uint16_t last_result_handle){
747*3deb3ec6SMatthias Ringwald     return last_result_handle >= peripheral->end_group_handle;
748*3deb3ec6SMatthias Ringwald }
749*3deb3ec6SMatthias Ringwald 
750*3deb3ec6SMatthias Ringwald static void trigger_next_query(gatt_client_t * peripheral, uint16_t last_result_handle, gatt_client_state_t next_query_state){
751*3deb3ec6SMatthias Ringwald     if (is_query_done(peripheral, last_result_handle)){
752*3deb3ec6SMatthias Ringwald         gatt_client_handle_transaction_complete(peripheral);
753*3deb3ec6SMatthias Ringwald         emit_gatt_complete_event(peripheral, 0);
754*3deb3ec6SMatthias Ringwald         return;
755*3deb3ec6SMatthias Ringwald     }
756*3deb3ec6SMatthias Ringwald     // next
757*3deb3ec6SMatthias Ringwald     peripheral->start_group_handle = last_result_handle + 1;
758*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = next_query_state;
759*3deb3ec6SMatthias Ringwald }
760*3deb3ec6SMatthias Ringwald 
761*3deb3ec6SMatthias Ringwald static inline void trigger_next_included_service_query(gatt_client_t * peripheral, uint16_t last_result_handle){
762*3deb3ec6SMatthias Ringwald     trigger_next_query(peripheral, last_result_handle, P_W2_SEND_INCLUDED_SERVICE_QUERY);
763*3deb3ec6SMatthias Ringwald }
764*3deb3ec6SMatthias Ringwald 
765*3deb3ec6SMatthias Ringwald static inline void trigger_next_service_query(gatt_client_t * peripheral, uint16_t last_result_handle){
766*3deb3ec6SMatthias Ringwald     trigger_next_query(peripheral, last_result_handle, P_W2_SEND_SERVICE_QUERY);
767*3deb3ec6SMatthias Ringwald }
768*3deb3ec6SMatthias Ringwald 
769*3deb3ec6SMatthias Ringwald static inline void trigger_next_service_by_uuid_query(gatt_client_t * peripheral, uint16_t last_result_handle){
770*3deb3ec6SMatthias Ringwald     trigger_next_query(peripheral, last_result_handle, P_W2_SEND_SERVICE_WITH_UUID_QUERY);
771*3deb3ec6SMatthias Ringwald }
772*3deb3ec6SMatthias Ringwald 
773*3deb3ec6SMatthias Ringwald static inline void trigger_next_characteristic_query(gatt_client_t * peripheral, uint16_t last_result_handle){
774*3deb3ec6SMatthias Ringwald     if (is_query_done(peripheral, last_result_handle)){
775*3deb3ec6SMatthias Ringwald         // report last characteristic
776*3deb3ec6SMatthias Ringwald         characteristic_end_found(peripheral, peripheral->end_group_handle);
777*3deb3ec6SMatthias Ringwald     }
778*3deb3ec6SMatthias Ringwald     trigger_next_query(peripheral, last_result_handle, P_W2_SEND_ALL_CHARACTERISTICS_OF_SERVICE_QUERY);
779*3deb3ec6SMatthias Ringwald }
780*3deb3ec6SMatthias Ringwald 
781*3deb3ec6SMatthias Ringwald static inline void trigger_next_characteristic_descriptor_query(gatt_client_t * peripheral, uint16_t last_result_handle){
782*3deb3ec6SMatthias Ringwald     trigger_next_query(peripheral, last_result_handle, P_W2_SEND_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY);
783*3deb3ec6SMatthias Ringwald }
784*3deb3ec6SMatthias Ringwald 
785*3deb3ec6SMatthias Ringwald static inline void trigger_next_read_by_type_query(gatt_client_t * peripheral, uint16_t last_result_handle){
786*3deb3ec6SMatthias Ringwald     trigger_next_query(peripheral, last_result_handle, P_W2_SEND_READ_BY_TYPE_REQUEST);
787*3deb3ec6SMatthias Ringwald }
788*3deb3ec6SMatthias Ringwald 
789*3deb3ec6SMatthias Ringwald static inline void trigger_next_prepare_write_query(gatt_client_t * peripheral, gatt_client_state_t next_query_state, gatt_client_state_t done_state){
790*3deb3ec6SMatthias Ringwald     peripheral->attribute_offset += write_blob_length(peripheral);
791*3deb3ec6SMatthias Ringwald     uint16_t next_blob_length =  write_blob_length(peripheral);
792*3deb3ec6SMatthias Ringwald 
793*3deb3ec6SMatthias Ringwald     if (next_blob_length == 0){
794*3deb3ec6SMatthias Ringwald         peripheral->gatt_client_state = done_state;
795*3deb3ec6SMatthias Ringwald         return;
796*3deb3ec6SMatthias Ringwald     }
797*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = next_query_state;
798*3deb3ec6SMatthias Ringwald }
799*3deb3ec6SMatthias Ringwald 
800*3deb3ec6SMatthias Ringwald static inline void trigger_next_blob_query(gatt_client_t * peripheral, gatt_client_state_t next_query_state, uint16_t received_blob_length){
801*3deb3ec6SMatthias Ringwald 
802*3deb3ec6SMatthias Ringwald     uint16_t max_blob_length = peripheral_mtu(peripheral) - 1;
803*3deb3ec6SMatthias Ringwald     if (received_blob_length < max_blob_length){
804*3deb3ec6SMatthias Ringwald         gatt_client_handle_transaction_complete(peripheral);
805*3deb3ec6SMatthias Ringwald         emit_gatt_complete_event(peripheral, 0);
806*3deb3ec6SMatthias Ringwald         return;
807*3deb3ec6SMatthias Ringwald     }
808*3deb3ec6SMatthias Ringwald 
809*3deb3ec6SMatthias Ringwald     peripheral->attribute_offset += received_blob_length;
810*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = next_query_state;
811*3deb3ec6SMatthias Ringwald }
812*3deb3ec6SMatthias Ringwald 
813*3deb3ec6SMatthias Ringwald 
814*3deb3ec6SMatthias Ringwald static int is_value_valid(gatt_client_t *peripheral, uint8_t *packet, uint16_t size){
815*3deb3ec6SMatthias Ringwald     uint16_t attribute_handle = READ_BT_16(packet, 1);
816*3deb3ec6SMatthias Ringwald     uint16_t value_offset = READ_BT_16(packet, 3);
817*3deb3ec6SMatthias Ringwald 
818*3deb3ec6SMatthias Ringwald     if (peripheral->attribute_handle != attribute_handle) return 0;
819*3deb3ec6SMatthias Ringwald     if (peripheral->attribute_offset != value_offset) return 0;
820*3deb3ec6SMatthias Ringwald     return memcmp(&peripheral->attribute_value[peripheral->attribute_offset], &packet[5], size-5) == 0;
821*3deb3ec6SMatthias Ringwald }
822*3deb3ec6SMatthias Ringwald 
823*3deb3ec6SMatthias Ringwald 
824*3deb3ec6SMatthias Ringwald static void gatt_client_run(void){
825*3deb3ec6SMatthias Ringwald 
826*3deb3ec6SMatthias Ringwald     linked_item_t *it;
827*3deb3ec6SMatthias Ringwald     for (it = (linked_item_t *) gatt_client_connections; it ; it = it->next){
828*3deb3ec6SMatthias Ringwald 
829*3deb3ec6SMatthias Ringwald         gatt_client_t * peripheral = (gatt_client_t *) it;
830*3deb3ec6SMatthias Ringwald 
831*3deb3ec6SMatthias Ringwald         if (!l2cap_can_send_fixed_channel_packet_now(peripheral->handle)) return;
832*3deb3ec6SMatthias Ringwald 
833*3deb3ec6SMatthias Ringwald         // log_info("- handle_peripheral_list, mtu state %u, client state %u", peripheral->mtu_state, peripheral->gatt_client_state);
834*3deb3ec6SMatthias Ringwald 
835*3deb3ec6SMatthias Ringwald         switch (peripheral->mtu_state) {
836*3deb3ec6SMatthias Ringwald             case SEND_MTU_EXCHANGE:{
837*3deb3ec6SMatthias Ringwald                 peripheral->mtu_state = SENT_MTU_EXCHANGE;
838*3deb3ec6SMatthias Ringwald                 att_exchange_mtu_request(peripheral->handle);
839*3deb3ec6SMatthias Ringwald                 return;
840*3deb3ec6SMatthias Ringwald             }
841*3deb3ec6SMatthias Ringwald             case SENT_MTU_EXCHANGE:
842*3deb3ec6SMatthias Ringwald                 return;
843*3deb3ec6SMatthias Ringwald             default:
844*3deb3ec6SMatthias Ringwald                 break;
845*3deb3ec6SMatthias Ringwald         }
846*3deb3ec6SMatthias Ringwald 
847*3deb3ec6SMatthias Ringwald         if (peripheral->send_confirmation){
848*3deb3ec6SMatthias Ringwald             peripheral->send_confirmation = 0;
849*3deb3ec6SMatthias Ringwald             att_confirmation(peripheral->handle);
850*3deb3ec6SMatthias Ringwald             return;
851*3deb3ec6SMatthias Ringwald         }
852*3deb3ec6SMatthias Ringwald 
853*3deb3ec6SMatthias Ringwald         // check MTU for writes
854*3deb3ec6SMatthias Ringwald         switch (peripheral->gatt_client_state){
855*3deb3ec6SMatthias Ringwald             case P_W2_SEND_WRITE_CHARACTERISTIC_VALUE:
856*3deb3ec6SMatthias Ringwald             case P_W2_SEND_WRITE_CHARACTERISTIC_DESCRIPTOR:
857*3deb3ec6SMatthias Ringwald                 if (peripheral->attribute_length <= peripheral_mtu(peripheral) - 3) break;
858*3deb3ec6SMatthias Ringwald                 log_error("gatt_client_run: value len %u > MTU %u - 3\n", peripheral->attribute_length, peripheral_mtu(peripheral));
859*3deb3ec6SMatthias Ringwald                 gatt_client_handle_transaction_complete(peripheral);
860*3deb3ec6SMatthias Ringwald                 emit_gatt_complete_event(peripheral, ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH);
861*3deb3ec6SMatthias Ringwald                 return;
862*3deb3ec6SMatthias Ringwald             default:
863*3deb3ec6SMatthias Ringwald                 break;
864*3deb3ec6SMatthias Ringwald         }
865*3deb3ec6SMatthias Ringwald 
866*3deb3ec6SMatthias Ringwald         // log_info("gatt_client_state %u", peripheral->gatt_client_state);
867*3deb3ec6SMatthias Ringwald         switch (peripheral->gatt_client_state){
868*3deb3ec6SMatthias Ringwald             case P_W2_SEND_SERVICE_QUERY:
869*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_SERVICE_QUERY_RESULT;
870*3deb3ec6SMatthias Ringwald                 send_gatt_services_request(peripheral);
871*3deb3ec6SMatthias Ringwald                 return;
872*3deb3ec6SMatthias Ringwald 
873*3deb3ec6SMatthias Ringwald             case P_W2_SEND_SERVICE_WITH_UUID_QUERY:
874*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_SERVICE_WITH_UUID_RESULT;
875*3deb3ec6SMatthias Ringwald                 send_gatt_services_by_uuid_request(peripheral);
876*3deb3ec6SMatthias Ringwald                 return;
877*3deb3ec6SMatthias Ringwald 
878*3deb3ec6SMatthias Ringwald             case P_W2_SEND_ALL_CHARACTERISTICS_OF_SERVICE_QUERY:
879*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT;
880*3deb3ec6SMatthias Ringwald                 send_gatt_characteristic_request(peripheral);
881*3deb3ec6SMatthias Ringwald                 return;
882*3deb3ec6SMatthias Ringwald 
883*3deb3ec6SMatthias Ringwald             case P_W2_SEND_CHARACTERISTIC_WITH_UUID_QUERY:
884*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT;
885*3deb3ec6SMatthias Ringwald                 send_gatt_characteristic_request(peripheral);
886*3deb3ec6SMatthias Ringwald                 return;
887*3deb3ec6SMatthias Ringwald 
888*3deb3ec6SMatthias Ringwald             case P_W2_SEND_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY:
889*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT;
890*3deb3ec6SMatthias Ringwald                 send_gatt_characteristic_descriptor_request(peripheral);
891*3deb3ec6SMatthias Ringwald                 return;
892*3deb3ec6SMatthias Ringwald 
893*3deb3ec6SMatthias Ringwald             case P_W2_SEND_INCLUDED_SERVICE_QUERY:
894*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_INCLUDED_SERVICE_QUERY_RESULT;
895*3deb3ec6SMatthias Ringwald                 send_gatt_included_service_request(peripheral);
896*3deb3ec6SMatthias Ringwald                 return;
897*3deb3ec6SMatthias Ringwald 
898*3deb3ec6SMatthias Ringwald             case P_W2_SEND_INCLUDED_SERVICE_WITH_UUID_QUERY:
899*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_INCLUDED_SERVICE_UUID_WITH_QUERY_RESULT;
900*3deb3ec6SMatthias Ringwald                 send_gatt_included_service_uuid_request(peripheral);
901*3deb3ec6SMatthias Ringwald                 return;
902*3deb3ec6SMatthias Ringwald 
903*3deb3ec6SMatthias Ringwald             case P_W2_SEND_READ_CHARACTERISTIC_VALUE_QUERY:
904*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_READ_CHARACTERISTIC_VALUE_RESULT;
905*3deb3ec6SMatthias Ringwald                 send_gatt_read_characteristic_value_request(peripheral);
906*3deb3ec6SMatthias Ringwald                 return;
907*3deb3ec6SMatthias Ringwald 
908*3deb3ec6SMatthias Ringwald             case P_W2_SEND_READ_BLOB_QUERY:
909*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_READ_BLOB_RESULT;
910*3deb3ec6SMatthias Ringwald                 send_gatt_read_blob_request(peripheral);
911*3deb3ec6SMatthias Ringwald                 return;
912*3deb3ec6SMatthias Ringwald 
913*3deb3ec6SMatthias Ringwald             case P_W2_SEND_READ_BY_TYPE_REQUEST:
914*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_READ_BY_TYPE_RESPONSE;
915*3deb3ec6SMatthias Ringwald                 send_gatt_read_by_type_request(peripheral);
916*3deb3ec6SMatthias Ringwald                 break;
917*3deb3ec6SMatthias Ringwald 
918*3deb3ec6SMatthias Ringwald             case P_W2_SEND_READ_MULTIPLE_REQUEST:
919*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_READ_MULTIPLE_RESPONSE;
920*3deb3ec6SMatthias Ringwald                 send_gatt_read_multiple_request(peripheral);
921*3deb3ec6SMatthias Ringwald                 break;
922*3deb3ec6SMatthias Ringwald 
923*3deb3ec6SMatthias Ringwald             case P_W2_SEND_WRITE_CHARACTERISTIC_VALUE:
924*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_WRITE_CHARACTERISTIC_VALUE_RESULT;
925*3deb3ec6SMatthias Ringwald                 send_gatt_write_attribute_value_request(peripheral);
926*3deb3ec6SMatthias Ringwald                 return;
927*3deb3ec6SMatthias Ringwald 
928*3deb3ec6SMatthias Ringwald             case P_W2_PREPARE_WRITE:
929*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_PREPARE_WRITE_RESULT;
930*3deb3ec6SMatthias Ringwald                 send_gatt_prepare_write_request(peripheral);
931*3deb3ec6SMatthias Ringwald                 return;
932*3deb3ec6SMatthias Ringwald 
933*3deb3ec6SMatthias Ringwald             case P_W2_PREPARE_WRITE_SINGLE:
934*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_PREPARE_WRITE_SINGLE_RESULT;
935*3deb3ec6SMatthias Ringwald                 send_gatt_prepare_write_request(peripheral);
936*3deb3ec6SMatthias Ringwald                 return;
937*3deb3ec6SMatthias Ringwald 
938*3deb3ec6SMatthias Ringwald             case P_W2_PREPARE_RELIABLE_WRITE:
939*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_PREPARE_RELIABLE_WRITE_RESULT;
940*3deb3ec6SMatthias Ringwald                 send_gatt_prepare_write_request(peripheral);
941*3deb3ec6SMatthias Ringwald                 return;
942*3deb3ec6SMatthias Ringwald 
943*3deb3ec6SMatthias Ringwald             case P_W2_EXECUTE_PREPARED_WRITE:
944*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_EXECUTE_PREPARED_WRITE_RESULT;
945*3deb3ec6SMatthias Ringwald                 send_gatt_execute_write_request(peripheral);
946*3deb3ec6SMatthias Ringwald                 return;
947*3deb3ec6SMatthias Ringwald 
948*3deb3ec6SMatthias Ringwald             case P_W2_CANCEL_PREPARED_WRITE:
949*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_CANCEL_PREPARED_WRITE_RESULT;
950*3deb3ec6SMatthias Ringwald                 send_gatt_cancel_prepared_write_request(peripheral);
951*3deb3ec6SMatthias Ringwald                 return;
952*3deb3ec6SMatthias Ringwald 
953*3deb3ec6SMatthias Ringwald             case P_W2_CANCEL_PREPARED_WRITE_DATA_MISMATCH:
954*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_CANCEL_PREPARED_WRITE_DATA_MISMATCH_RESULT;
955*3deb3ec6SMatthias Ringwald                 send_gatt_cancel_prepared_write_request(peripheral);
956*3deb3ec6SMatthias Ringwald                 return;
957*3deb3ec6SMatthias Ringwald 
958*3deb3ec6SMatthias Ringwald             case P_W2_SEND_READ_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY:
959*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_READ_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY_RESULT;
960*3deb3ec6SMatthias Ringwald                 send_gatt_read_client_characteristic_configuration_request(peripheral);
961*3deb3ec6SMatthias Ringwald                 return;
962*3deb3ec6SMatthias Ringwald 
963*3deb3ec6SMatthias Ringwald             case P_W2_SEND_READ_CHARACTERISTIC_DESCRIPTOR_QUERY:
964*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_READ_CHARACTERISTIC_DESCRIPTOR_RESULT;
965*3deb3ec6SMatthias Ringwald                 send_gatt_read_characteristic_descriptor_request(peripheral);
966*3deb3ec6SMatthias Ringwald                 return;
967*3deb3ec6SMatthias Ringwald 
968*3deb3ec6SMatthias Ringwald             case P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY:
969*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_RESULT;
970*3deb3ec6SMatthias Ringwald                 send_gatt_read_blob_request(peripheral);
971*3deb3ec6SMatthias Ringwald                 return;
972*3deb3ec6SMatthias Ringwald 
973*3deb3ec6SMatthias Ringwald             case P_W2_SEND_WRITE_CHARACTERISTIC_DESCRIPTOR:
974*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT;
975*3deb3ec6SMatthias Ringwald                 send_gatt_write_attribute_value_request(peripheral);
976*3deb3ec6SMatthias Ringwald                 return;
977*3deb3ec6SMatthias Ringwald 
978*3deb3ec6SMatthias Ringwald             case P_W2_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION:
979*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_CLIENT_CHARACTERISTIC_CONFIGURATION_RESULT;
980*3deb3ec6SMatthias Ringwald                 send_gatt_write_client_characteristic_configuration_request(peripheral);
981*3deb3ec6SMatthias Ringwald                 return;
982*3deb3ec6SMatthias Ringwald 
983*3deb3ec6SMatthias Ringwald             case P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR:
984*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT;
985*3deb3ec6SMatthias Ringwald                 send_gatt_prepare_write_request(peripheral);
986*3deb3ec6SMatthias Ringwald                 return;
987*3deb3ec6SMatthias Ringwald 
988*3deb3ec6SMatthias Ringwald             case P_W2_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR:
989*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT;
990*3deb3ec6SMatthias Ringwald                 send_gatt_execute_write_request(peripheral);
991*3deb3ec6SMatthias Ringwald                 return;
992*3deb3ec6SMatthias Ringwald 
993*3deb3ec6SMatthias Ringwald             case P_W4_CMAC_READY:
994*3deb3ec6SMatthias Ringwald                 if (sm_cmac_ready()){
995*3deb3ec6SMatthias Ringwald                     sm_key_t csrk;
996*3deb3ec6SMatthias Ringwald                     le_device_db_local_csrk_get(peripheral->le_device_index, csrk);
997*3deb3ec6SMatthias Ringwald                     uint32_t sign_counter = le_device_db_local_counter_get(peripheral->le_device_index);
998*3deb3ec6SMatthias Ringwald                     peripheral->gatt_client_state = P_W4_CMAC_RESULT;
999*3deb3ec6SMatthias Ringwald                     sm_cmac_start(csrk, ATT_SIGNED_WRITE_COMMAND, peripheral->attribute_handle, peripheral->attribute_length, peripheral->attribute_value, sign_counter, att_signed_write_handle_cmac_result);
1000*3deb3ec6SMatthias Ringwald                 }
1001*3deb3ec6SMatthias Ringwald                 return;
1002*3deb3ec6SMatthias Ringwald 
1003*3deb3ec6SMatthias Ringwald             case P_W2_SEND_SIGNED_WRITE: {
1004*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_W4_SEND_SINGED_WRITE_DONE;
1005*3deb3ec6SMatthias Ringwald                 // bump local signing counter
1006*3deb3ec6SMatthias Ringwald                 uint32_t sign_counter = le_device_db_local_counter_get(peripheral->le_device_index);
1007*3deb3ec6SMatthias Ringwald                 le_device_db_local_counter_set(peripheral->le_device_index, sign_counter + 1);
1008*3deb3ec6SMatthias Ringwald 
1009*3deb3ec6SMatthias Ringwald                 send_gatt_signed_write_request(peripheral, sign_counter);
1010*3deb3ec6SMatthias Ringwald                 peripheral->gatt_client_state = P_READY;
1011*3deb3ec6SMatthias Ringwald                 // finally, notifiy client that write is complete
1012*3deb3ec6SMatthias Ringwald                 gatt_client_handle_transaction_complete(peripheral);
1013*3deb3ec6SMatthias Ringwald                 return;
1014*3deb3ec6SMatthias Ringwald             }
1015*3deb3ec6SMatthias Ringwald 
1016*3deb3ec6SMatthias Ringwald             default:
1017*3deb3ec6SMatthias Ringwald                 break;
1018*3deb3ec6SMatthias Ringwald         }
1019*3deb3ec6SMatthias Ringwald     }
1020*3deb3ec6SMatthias Ringwald 
1021*3deb3ec6SMatthias Ringwald }
1022*3deb3ec6SMatthias Ringwald 
1023*3deb3ec6SMatthias Ringwald static void gatt_client_report_error_if_pending(gatt_client_t *peripheral, uint8_t error_code) {
1024*3deb3ec6SMatthias Ringwald     if (is_ready(peripheral)) return;
1025*3deb3ec6SMatthias Ringwald     gatt_client_handle_transaction_complete(peripheral);
1026*3deb3ec6SMatthias Ringwald     emit_gatt_complete_event(peripheral, error_code);
1027*3deb3ec6SMatthias Ringwald }
1028*3deb3ec6SMatthias Ringwald 
1029*3deb3ec6SMatthias Ringwald static void gatt_client_hci_event_packet_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
1030*3deb3ec6SMatthias Ringwald     switch (packet[0]) {
1031*3deb3ec6SMatthias Ringwald         case HCI_EVENT_DISCONNECTION_COMPLETE:
1032*3deb3ec6SMatthias Ringwald         {
1033*3deb3ec6SMatthias Ringwald             log_info("GATT Client: HCI_EVENT_DISCONNECTION_COMPLETE");
1034*3deb3ec6SMatthias Ringwald             uint16_t con_handle = READ_BT_16(packet,3);
1035*3deb3ec6SMatthias Ringwald             gatt_client_t * peripheral = get_gatt_client_context_for_handle(con_handle);
1036*3deb3ec6SMatthias Ringwald             if (!peripheral) break;
1037*3deb3ec6SMatthias Ringwald             gatt_client_report_error_if_pending(peripheral, ATT_ERROR_HCI_DISCONNECT_RECEIVED);
1038*3deb3ec6SMatthias Ringwald 
1039*3deb3ec6SMatthias Ringwald             linked_list_remove(&gatt_client_connections, (linked_item_t *) peripheral);
1040*3deb3ec6SMatthias Ringwald             btstack_memory_gatt_client_free(peripheral);
1041*3deb3ec6SMatthias Ringwald             break;
1042*3deb3ec6SMatthias Ringwald         }
1043*3deb3ec6SMatthias Ringwald         default:
1044*3deb3ec6SMatthias Ringwald             break;
1045*3deb3ec6SMatthias Ringwald     }
1046*3deb3ec6SMatthias Ringwald 
1047*3deb3ec6SMatthias Ringwald     // forward all hci events
1048*3deb3ec6SMatthias Ringwald     emit_event_to_all_subclients_new(packet, size);
1049*3deb3ec6SMatthias Ringwald }
1050*3deb3ec6SMatthias Ringwald 
1051*3deb3ec6SMatthias Ringwald static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size){
1052*3deb3ec6SMatthias Ringwald 
1053*3deb3ec6SMatthias Ringwald     if (packet_type == HCI_EVENT_PACKET) {
1054*3deb3ec6SMatthias Ringwald         gatt_client_hci_event_packet_handler(packet_type, packet, size);
1055*3deb3ec6SMatthias Ringwald         gatt_client_run();
1056*3deb3ec6SMatthias Ringwald         return;
1057*3deb3ec6SMatthias Ringwald     }
1058*3deb3ec6SMatthias Ringwald 
1059*3deb3ec6SMatthias Ringwald     if (packet_type != ATT_DATA_PACKET) return;
1060*3deb3ec6SMatthias Ringwald 
1061*3deb3ec6SMatthias Ringwald     // special cases: notifications don't need a context while indications motivate creating one
1062*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral;
1063*3deb3ec6SMatthias Ringwald     switch (packet[0]){
1064*3deb3ec6SMatthias Ringwald         case ATT_HANDLE_VALUE_NOTIFICATION:
1065*3deb3ec6SMatthias Ringwald             report_gatt_notification(handle, READ_BT_16(packet,1), &packet[3], size-3);
1066*3deb3ec6SMatthias Ringwald             return;
1067*3deb3ec6SMatthias Ringwald         case ATT_HANDLE_VALUE_INDICATION:
1068*3deb3ec6SMatthias Ringwald             peripheral = provide_context_for_conn_handle(handle);
1069*3deb3ec6SMatthias Ringwald             break;
1070*3deb3ec6SMatthias Ringwald         default:
1071*3deb3ec6SMatthias Ringwald             peripheral = get_gatt_client_context_for_handle(handle);
1072*3deb3ec6SMatthias Ringwald             break;
1073*3deb3ec6SMatthias Ringwald     }
1074*3deb3ec6SMatthias Ringwald 
1075*3deb3ec6SMatthias Ringwald     if (!peripheral) return;
1076*3deb3ec6SMatthias Ringwald 
1077*3deb3ec6SMatthias Ringwald     switch (packet[0]){
1078*3deb3ec6SMatthias Ringwald         case ATT_EXCHANGE_MTU_RESPONSE:
1079*3deb3ec6SMatthias Ringwald         {
1080*3deb3ec6SMatthias Ringwald             uint16_t remote_rx_mtu = READ_BT_16(packet, 1);
1081*3deb3ec6SMatthias Ringwald             uint16_t local_rx_mtu = l2cap_max_le_mtu();
1082*3deb3ec6SMatthias Ringwald             peripheral->mtu = remote_rx_mtu < local_rx_mtu ? remote_rx_mtu : local_rx_mtu;
1083*3deb3ec6SMatthias Ringwald             peripheral->mtu_state = MTU_EXCHANGED;
1084*3deb3ec6SMatthias Ringwald 
1085*3deb3ec6SMatthias Ringwald             break;
1086*3deb3ec6SMatthias Ringwald         }
1087*3deb3ec6SMatthias Ringwald         case ATT_READ_BY_GROUP_TYPE_RESPONSE:
1088*3deb3ec6SMatthias Ringwald             switch(peripheral->gatt_client_state){
1089*3deb3ec6SMatthias Ringwald                 case P_W4_SERVICE_QUERY_RESULT:
1090*3deb3ec6SMatthias Ringwald                     report_gatt_services(peripheral, packet, size);
1091*3deb3ec6SMatthias Ringwald                     trigger_next_service_query(peripheral, get_last_result_handle_from_service_list(packet, size));
1092*3deb3ec6SMatthias Ringwald                     // GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
1093*3deb3ec6SMatthias Ringwald                     break;
1094*3deb3ec6SMatthias Ringwald                 default:
1095*3deb3ec6SMatthias Ringwald                     break;
1096*3deb3ec6SMatthias Ringwald             }
1097*3deb3ec6SMatthias Ringwald             break;
1098*3deb3ec6SMatthias Ringwald         case ATT_HANDLE_VALUE_INDICATION:
1099*3deb3ec6SMatthias Ringwald             report_gatt_indication(handle, READ_BT_16(packet,1), &packet[3], size-3);
1100*3deb3ec6SMatthias Ringwald             peripheral->send_confirmation = 1;
1101*3deb3ec6SMatthias Ringwald             break;
1102*3deb3ec6SMatthias Ringwald 
1103*3deb3ec6SMatthias Ringwald         case ATT_READ_BY_TYPE_RESPONSE:
1104*3deb3ec6SMatthias Ringwald             switch (peripheral->gatt_client_state){
1105*3deb3ec6SMatthias Ringwald                 case P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT:
1106*3deb3ec6SMatthias Ringwald                     report_gatt_characteristics(peripheral, packet, size);
1107*3deb3ec6SMatthias Ringwald                     trigger_next_characteristic_query(peripheral, get_last_result_handle_from_characteristics_list(packet, size));
1108*3deb3ec6SMatthias Ringwald                     // GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR
1109*3deb3ec6SMatthias Ringwald                     break;
1110*3deb3ec6SMatthias Ringwald                 case P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT:
1111*3deb3ec6SMatthias Ringwald                     report_gatt_characteristics(peripheral, packet, size);
1112*3deb3ec6SMatthias Ringwald                     trigger_next_characteristic_query(peripheral, get_last_result_handle_from_characteristics_list(packet, size));
1113*3deb3ec6SMatthias Ringwald                     // GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done, or by ATT_ERROR
1114*3deb3ec6SMatthias Ringwald                     break;
1115*3deb3ec6SMatthias Ringwald                 case P_W4_INCLUDED_SERVICE_QUERY_RESULT:
1116*3deb3ec6SMatthias Ringwald                 {
1117*3deb3ec6SMatthias Ringwald                     uint16_t uuid16 = 0;
1118*3deb3ec6SMatthias Ringwald                     uint16_t pair_size = packet[1];
1119*3deb3ec6SMatthias Ringwald 
1120*3deb3ec6SMatthias Ringwald                     if (pair_size < 7){
1121*3deb3ec6SMatthias Ringwald                         // UUIDs not available, query first included service
1122*3deb3ec6SMatthias Ringwald                         peripheral->start_group_handle = READ_BT_16(packet, 2); // ready for next query
1123*3deb3ec6SMatthias Ringwald                         peripheral->query_start_handle = READ_BT_16(packet, 4);
1124*3deb3ec6SMatthias Ringwald                         peripheral->query_end_handle = READ_BT_16(packet,6);
1125*3deb3ec6SMatthias Ringwald                         peripheral->gatt_client_state = P_W2_SEND_INCLUDED_SERVICE_WITH_UUID_QUERY;
1126*3deb3ec6SMatthias Ringwald                         break;
1127*3deb3ec6SMatthias Ringwald                     }
1128*3deb3ec6SMatthias Ringwald 
1129*3deb3ec6SMatthias Ringwald                     uint16_t offset;
1130*3deb3ec6SMatthias Ringwald                     for (offset = 2; offset < size; offset += pair_size){
1131*3deb3ec6SMatthias Ringwald                         uint16_t include_handle = READ_BT_16(packet, offset);
1132*3deb3ec6SMatthias Ringwald                         peripheral->query_start_handle = READ_BT_16(packet,offset+2);
1133*3deb3ec6SMatthias Ringwald                         peripheral->query_end_handle = READ_BT_16(packet,offset+4);
1134*3deb3ec6SMatthias Ringwald                         uuid16 = READ_BT_16(packet, offset+6);
1135*3deb3ec6SMatthias Ringwald                         report_gatt_included_service_uuid16(peripheral, include_handle, uuid16);
1136*3deb3ec6SMatthias Ringwald                     }
1137*3deb3ec6SMatthias Ringwald 
1138*3deb3ec6SMatthias Ringwald                     trigger_next_included_service_query(peripheral, get_last_result_handle_from_included_services_list(packet, size));
1139*3deb3ec6SMatthias Ringwald                     // GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
1140*3deb3ec6SMatthias Ringwald                     break;
1141*3deb3ec6SMatthias Ringwald                 }
1142*3deb3ec6SMatthias Ringwald                 case P_W4_READ_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY_RESULT:
1143*3deb3ec6SMatthias Ringwald                     peripheral->client_characteristic_configuration_handle = READ_BT_16(packet, 2);
1144*3deb3ec6SMatthias Ringwald                     peripheral->gatt_client_state = P_W2_WRITE_CLIENT_CHARACTERISTIC_CONFIGURATION;
1145*3deb3ec6SMatthias Ringwald                     break;
1146*3deb3ec6SMatthias Ringwald                 case P_W4_READ_BY_TYPE_RESPONSE: {
1147*3deb3ec6SMatthias Ringwald                     uint16_t pair_size = packet[1];
1148*3deb3ec6SMatthias Ringwald                     uint16_t offset;
1149*3deb3ec6SMatthias Ringwald                     uint16_t last_result_handle = 0;
1150*3deb3ec6SMatthias Ringwald                     for (offset = 2; offset < size ; offset += pair_size){
1151*3deb3ec6SMatthias Ringwald                         uint16_t value_handle = READ_BT_16(packet, offset);
1152*3deb3ec6SMatthias Ringwald                         report_gatt_characteristic_value(peripheral, value_handle, &packet[offset+2], pair_size-2);
1153*3deb3ec6SMatthias Ringwald                         last_result_handle = value_handle;
1154*3deb3ec6SMatthias Ringwald                     }
1155*3deb3ec6SMatthias Ringwald                     trigger_next_read_by_type_query(peripheral, last_result_handle);
1156*3deb3ec6SMatthias Ringwald                     break;
1157*3deb3ec6SMatthias Ringwald                 }
1158*3deb3ec6SMatthias Ringwald                 default:
1159*3deb3ec6SMatthias Ringwald                     break;
1160*3deb3ec6SMatthias Ringwald             }
1161*3deb3ec6SMatthias Ringwald             break;
1162*3deb3ec6SMatthias Ringwald         case ATT_READ_RESPONSE:
1163*3deb3ec6SMatthias Ringwald             switch (peripheral->gatt_client_state){
1164*3deb3ec6SMatthias Ringwald                 case P_W4_INCLUDED_SERVICE_UUID_WITH_QUERY_RESULT: {
1165*3deb3ec6SMatthias Ringwald                     uint8_t uuid128[16];
1166*3deb3ec6SMatthias Ringwald                     swap128(&packet[1], uuid128);
1167*3deb3ec6SMatthias Ringwald                     report_gatt_included_service_uuid128(peripheral, peripheral->start_group_handle, uuid128);
1168*3deb3ec6SMatthias Ringwald                     trigger_next_included_service_query(peripheral, peripheral->start_group_handle);
1169*3deb3ec6SMatthias Ringwald                     // GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
1170*3deb3ec6SMatthias Ringwald                     break;
1171*3deb3ec6SMatthias Ringwald                 }
1172*3deb3ec6SMatthias Ringwald                 case P_W4_READ_CHARACTERISTIC_VALUE_RESULT:
1173*3deb3ec6SMatthias Ringwald                     gatt_client_handle_transaction_complete(peripheral);
1174*3deb3ec6SMatthias Ringwald                     report_gatt_characteristic_value(peripheral, peripheral->attribute_handle, &packet[1], size-1);
1175*3deb3ec6SMatthias Ringwald                     emit_gatt_complete_event(peripheral, 0);
1176*3deb3ec6SMatthias Ringwald                     break;
1177*3deb3ec6SMatthias Ringwald 
1178*3deb3ec6SMatthias Ringwald                 case P_W4_READ_CHARACTERISTIC_DESCRIPTOR_RESULT:{
1179*3deb3ec6SMatthias Ringwald                     gatt_client_handle_transaction_complete(peripheral);
1180*3deb3ec6SMatthias Ringwald                     report_gatt_characteristic_descriptor(peripheral, peripheral->attribute_handle, &packet[1], size-1, 0);
1181*3deb3ec6SMatthias Ringwald                     emit_gatt_complete_event(peripheral, 0);
1182*3deb3ec6SMatthias Ringwald                     break;
1183*3deb3ec6SMatthias Ringwald                 }
1184*3deb3ec6SMatthias Ringwald                 default:
1185*3deb3ec6SMatthias Ringwald                     break;
1186*3deb3ec6SMatthias Ringwald             }
1187*3deb3ec6SMatthias Ringwald             break;
1188*3deb3ec6SMatthias Ringwald 
1189*3deb3ec6SMatthias Ringwald         case ATT_FIND_BY_TYPE_VALUE_RESPONSE:
1190*3deb3ec6SMatthias Ringwald         {
1191*3deb3ec6SMatthias Ringwald             uint8_t pair_size = 4;
1192*3deb3ec6SMatthias Ringwald             int i;
1193*3deb3ec6SMatthias Ringwald             uint16_t start_group_handle;
1194*3deb3ec6SMatthias Ringwald             uint16_t   end_group_handle= 0xffff; // asserts GATT_QUERY_COMPLETE is emitted if no results
1195*3deb3ec6SMatthias Ringwald             for (i = 1; i<size; i+=pair_size){
1196*3deb3ec6SMatthias Ringwald                 start_group_handle = READ_BT_16(packet,i);
1197*3deb3ec6SMatthias Ringwald                 end_group_handle = READ_BT_16(packet,i+2);
1198*3deb3ec6SMatthias Ringwald                 emit_gatt_service_query_result_event(peripheral, start_group_handle, end_group_handle, peripheral->uuid128);
1199*3deb3ec6SMatthias Ringwald             }
1200*3deb3ec6SMatthias Ringwald             trigger_next_service_by_uuid_query(peripheral, end_group_handle);
1201*3deb3ec6SMatthias Ringwald             // GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
1202*3deb3ec6SMatthias Ringwald             break;
1203*3deb3ec6SMatthias Ringwald         }
1204*3deb3ec6SMatthias Ringwald         case ATT_FIND_INFORMATION_REPLY:
1205*3deb3ec6SMatthias Ringwald         {
1206*3deb3ec6SMatthias Ringwald             uint8_t pair_size = 4;
1207*3deb3ec6SMatthias Ringwald             if (packet[1] == 2){
1208*3deb3ec6SMatthias Ringwald                 pair_size = 18;
1209*3deb3ec6SMatthias Ringwald             }
1210*3deb3ec6SMatthias Ringwald             uint16_t last_descriptor_handle = READ_BT_16(packet, size - pair_size);
1211*3deb3ec6SMatthias Ringwald 
1212*3deb3ec6SMatthias Ringwald             report_gatt_all_characteristic_descriptors(peripheral, &packet[2], size-2, pair_size);
1213*3deb3ec6SMatthias Ringwald             trigger_next_characteristic_descriptor_query(peripheral, last_descriptor_handle);
1214*3deb3ec6SMatthias Ringwald             // GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
1215*3deb3ec6SMatthias Ringwald             break;
1216*3deb3ec6SMatthias Ringwald         }
1217*3deb3ec6SMatthias Ringwald 
1218*3deb3ec6SMatthias Ringwald         case ATT_WRITE_RESPONSE:
1219*3deb3ec6SMatthias Ringwald             switch (peripheral->gatt_client_state){
1220*3deb3ec6SMatthias Ringwald                 case P_W4_WRITE_CHARACTERISTIC_VALUE_RESULT:
1221*3deb3ec6SMatthias Ringwald                     gatt_client_handle_transaction_complete(peripheral);
1222*3deb3ec6SMatthias Ringwald                     emit_gatt_complete_event(peripheral, 0);
1223*3deb3ec6SMatthias Ringwald                     break;
1224*3deb3ec6SMatthias Ringwald                 case P_W4_CLIENT_CHARACTERISTIC_CONFIGURATION_RESULT:
1225*3deb3ec6SMatthias Ringwald                     gatt_client_handle_transaction_complete(peripheral);
1226*3deb3ec6SMatthias Ringwald                     emit_gatt_complete_event(peripheral, 0);
1227*3deb3ec6SMatthias Ringwald                     break;
1228*3deb3ec6SMatthias Ringwald                 case P_W4_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT:
1229*3deb3ec6SMatthias Ringwald                     gatt_client_handle_transaction_complete(peripheral);
1230*3deb3ec6SMatthias Ringwald                     emit_gatt_complete_event(peripheral, 0);
1231*3deb3ec6SMatthias Ringwald                     break;
1232*3deb3ec6SMatthias Ringwald                 default:
1233*3deb3ec6SMatthias Ringwald                     break;
1234*3deb3ec6SMatthias Ringwald             }
1235*3deb3ec6SMatthias Ringwald             break;
1236*3deb3ec6SMatthias Ringwald 
1237*3deb3ec6SMatthias Ringwald         case ATT_READ_BLOB_RESPONSE:{
1238*3deb3ec6SMatthias Ringwald             uint16_t received_blob_length = size-1;
1239*3deb3ec6SMatthias Ringwald 
1240*3deb3ec6SMatthias Ringwald             switch(peripheral->gatt_client_state){
1241*3deb3ec6SMatthias Ringwald                 case P_W4_READ_BLOB_RESULT:
1242*3deb3ec6SMatthias Ringwald                     report_gatt_long_characteristic_value_blob(peripheral, peripheral->attribute_handle, &packet[1], received_blob_length, peripheral->attribute_offset);
1243*3deb3ec6SMatthias Ringwald                     trigger_next_blob_query(peripheral, P_W2_SEND_READ_BLOB_QUERY, received_blob_length);
1244*3deb3ec6SMatthias Ringwald                     // GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
1245*3deb3ec6SMatthias Ringwald                     break;
1246*3deb3ec6SMatthias Ringwald                 case P_W4_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_RESULT:
1247*3deb3ec6SMatthias Ringwald                     report_gatt_long_characteristic_descriptor(peripheral, peripheral->attribute_handle,
1248*3deb3ec6SMatthias Ringwald                                                           &packet[1], received_blob_length,
1249*3deb3ec6SMatthias Ringwald                                                           peripheral->attribute_offset);
1250*3deb3ec6SMatthias Ringwald                     trigger_next_blob_query(peripheral, P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY, received_blob_length);
1251*3deb3ec6SMatthias Ringwald                     // GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
1252*3deb3ec6SMatthias Ringwald                     break;
1253*3deb3ec6SMatthias Ringwald                 default:
1254*3deb3ec6SMatthias Ringwald                     break;
1255*3deb3ec6SMatthias Ringwald             }
1256*3deb3ec6SMatthias Ringwald             break;
1257*3deb3ec6SMatthias Ringwald         }
1258*3deb3ec6SMatthias Ringwald         case ATT_PREPARE_WRITE_RESPONSE:
1259*3deb3ec6SMatthias Ringwald             switch (peripheral->gatt_client_state){
1260*3deb3ec6SMatthias Ringwald                 case P_W4_PREPARE_WRITE_SINGLE_RESULT:
1261*3deb3ec6SMatthias Ringwald                     gatt_client_handle_transaction_complete(peripheral);
1262*3deb3ec6SMatthias Ringwald                     if (is_value_valid(peripheral, packet, size)){
1263*3deb3ec6SMatthias Ringwald                         emit_gatt_complete_event(peripheral, 0);
1264*3deb3ec6SMatthias Ringwald                     } else {
1265*3deb3ec6SMatthias Ringwald                         emit_gatt_complete_event(peripheral, ATT_ERROR_DATA_MISMATCH);
1266*3deb3ec6SMatthias Ringwald                     }
1267*3deb3ec6SMatthias Ringwald                     break;
1268*3deb3ec6SMatthias Ringwald 
1269*3deb3ec6SMatthias Ringwald                 case P_W4_PREPARE_WRITE_RESULT:{
1270*3deb3ec6SMatthias Ringwald                     peripheral->attribute_offset = READ_BT_16(packet, 3);
1271*3deb3ec6SMatthias Ringwald                     trigger_next_prepare_write_query(peripheral, P_W2_PREPARE_WRITE, P_W2_EXECUTE_PREPARED_WRITE);
1272*3deb3ec6SMatthias Ringwald                     // GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
1273*3deb3ec6SMatthias Ringwald                     break;
1274*3deb3ec6SMatthias Ringwald                 }
1275*3deb3ec6SMatthias Ringwald                 case P_W4_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT:{
1276*3deb3ec6SMatthias Ringwald                     peripheral->attribute_offset = READ_BT_16(packet, 3);
1277*3deb3ec6SMatthias Ringwald                     trigger_next_prepare_write_query(peripheral, P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR, P_W2_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR);
1278*3deb3ec6SMatthias Ringwald                     // GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
1279*3deb3ec6SMatthias Ringwald                     break;
1280*3deb3ec6SMatthias Ringwald                 }
1281*3deb3ec6SMatthias Ringwald                 case P_W4_PREPARE_RELIABLE_WRITE_RESULT:{
1282*3deb3ec6SMatthias Ringwald                     if (is_value_valid(peripheral, packet, size)){
1283*3deb3ec6SMatthias Ringwald                         peripheral->attribute_offset = READ_BT_16(packet, 3);
1284*3deb3ec6SMatthias Ringwald                         trigger_next_prepare_write_query(peripheral, P_W2_PREPARE_RELIABLE_WRITE, P_W2_EXECUTE_PREPARED_WRITE);
1285*3deb3ec6SMatthias Ringwald                         // GATT_QUERY_COMPLETE is emitted by trigger_next_xxx when done
1286*3deb3ec6SMatthias Ringwald                         break;
1287*3deb3ec6SMatthias Ringwald                     }
1288*3deb3ec6SMatthias Ringwald                     peripheral->gatt_client_state = P_W2_CANCEL_PREPARED_WRITE_DATA_MISMATCH;
1289*3deb3ec6SMatthias Ringwald                     break;
1290*3deb3ec6SMatthias Ringwald                 }
1291*3deb3ec6SMatthias Ringwald                 default:
1292*3deb3ec6SMatthias Ringwald                     break;
1293*3deb3ec6SMatthias Ringwald             }
1294*3deb3ec6SMatthias Ringwald             break;
1295*3deb3ec6SMatthias Ringwald 
1296*3deb3ec6SMatthias Ringwald         case ATT_EXECUTE_WRITE_RESPONSE:
1297*3deb3ec6SMatthias Ringwald             switch (peripheral->gatt_client_state){
1298*3deb3ec6SMatthias Ringwald                 case P_W4_EXECUTE_PREPARED_WRITE_RESULT:
1299*3deb3ec6SMatthias Ringwald                     gatt_client_handle_transaction_complete(peripheral);
1300*3deb3ec6SMatthias Ringwald                     emit_gatt_complete_event(peripheral, 0);
1301*3deb3ec6SMatthias Ringwald                     break;
1302*3deb3ec6SMatthias Ringwald                 case P_W4_CANCEL_PREPARED_WRITE_RESULT:
1303*3deb3ec6SMatthias Ringwald                     gatt_client_handle_transaction_complete(peripheral);
1304*3deb3ec6SMatthias Ringwald                     emit_gatt_complete_event(peripheral, 0);
1305*3deb3ec6SMatthias Ringwald                     break;
1306*3deb3ec6SMatthias Ringwald                 case P_W4_CANCEL_PREPARED_WRITE_DATA_MISMATCH_RESULT:
1307*3deb3ec6SMatthias Ringwald                     gatt_client_handle_transaction_complete(peripheral);
1308*3deb3ec6SMatthias Ringwald                     emit_gatt_complete_event(peripheral, ATT_ERROR_DATA_MISMATCH);
1309*3deb3ec6SMatthias Ringwald                     break;
1310*3deb3ec6SMatthias Ringwald                 case P_W4_EXECUTE_PREPARED_WRITE_CHARACTERISTIC_DESCRIPTOR_RESULT:
1311*3deb3ec6SMatthias Ringwald                     gatt_client_handle_transaction_complete(peripheral);
1312*3deb3ec6SMatthias Ringwald                     emit_gatt_complete_event(peripheral, 0);
1313*3deb3ec6SMatthias Ringwald                     break;
1314*3deb3ec6SMatthias Ringwald                 default:
1315*3deb3ec6SMatthias Ringwald                     break;
1316*3deb3ec6SMatthias Ringwald 
1317*3deb3ec6SMatthias Ringwald             }
1318*3deb3ec6SMatthias Ringwald             break;
1319*3deb3ec6SMatthias Ringwald 
1320*3deb3ec6SMatthias Ringwald         case ATT_READ_MULTIPLE_RESPONSE:
1321*3deb3ec6SMatthias Ringwald             switch(peripheral->gatt_client_state){
1322*3deb3ec6SMatthias Ringwald                 case P_W4_READ_MULTIPLE_RESPONSE:
1323*3deb3ec6SMatthias Ringwald                     report_gatt_characteristic_value(peripheral, 0, &packet[1], size-1);
1324*3deb3ec6SMatthias Ringwald                     gatt_client_handle_transaction_complete(peripheral);
1325*3deb3ec6SMatthias Ringwald                     emit_gatt_complete_event(peripheral, 0);
1326*3deb3ec6SMatthias Ringwald                     break;
1327*3deb3ec6SMatthias Ringwald                 default:
1328*3deb3ec6SMatthias Ringwald                     break;
1329*3deb3ec6SMatthias Ringwald             }
1330*3deb3ec6SMatthias Ringwald             break;
1331*3deb3ec6SMatthias Ringwald 
1332*3deb3ec6SMatthias Ringwald         case ATT_ERROR_RESPONSE:
1333*3deb3ec6SMatthias Ringwald 
1334*3deb3ec6SMatthias Ringwald             switch (packet[4]){
1335*3deb3ec6SMatthias Ringwald                 case ATT_ERROR_ATTRIBUTE_NOT_FOUND: {
1336*3deb3ec6SMatthias Ringwald                     switch(peripheral->gatt_client_state){
1337*3deb3ec6SMatthias Ringwald                         case P_W4_SERVICE_QUERY_RESULT:
1338*3deb3ec6SMatthias Ringwald                         case P_W4_SERVICE_WITH_UUID_RESULT:
1339*3deb3ec6SMatthias Ringwald                         case P_W4_INCLUDED_SERVICE_QUERY_RESULT:
1340*3deb3ec6SMatthias Ringwald                         case P_W4_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT:
1341*3deb3ec6SMatthias Ringwald                             gatt_client_handle_transaction_complete(peripheral);
1342*3deb3ec6SMatthias Ringwald                             emit_gatt_complete_event(peripheral, 0);
1343*3deb3ec6SMatthias Ringwald                             break;
1344*3deb3ec6SMatthias Ringwald                         case P_W4_ALL_CHARACTERISTICS_OF_SERVICE_QUERY_RESULT:
1345*3deb3ec6SMatthias Ringwald                         case P_W4_CHARACTERISTIC_WITH_UUID_QUERY_RESULT:
1346*3deb3ec6SMatthias Ringwald                             characteristic_end_found(peripheral, peripheral->end_group_handle);
1347*3deb3ec6SMatthias Ringwald                             gatt_client_handle_transaction_complete(peripheral);
1348*3deb3ec6SMatthias Ringwald                             emit_gatt_complete_event(peripheral, 0);
1349*3deb3ec6SMatthias Ringwald                             break;
1350*3deb3ec6SMatthias Ringwald                         case P_W4_READ_BY_TYPE_RESPONSE:
1351*3deb3ec6SMatthias Ringwald                             gatt_client_handle_transaction_complete(peripheral);
1352*3deb3ec6SMatthias Ringwald                             if (peripheral->start_group_handle == peripheral->query_start_handle){
1353*3deb3ec6SMatthias Ringwald                                 emit_gatt_complete_event(peripheral, ATT_ERROR_ATTRIBUTE_NOT_FOUND);
1354*3deb3ec6SMatthias Ringwald                             } else {
1355*3deb3ec6SMatthias Ringwald                                 emit_gatt_complete_event(peripheral, 0);
1356*3deb3ec6SMatthias Ringwald                             }
1357*3deb3ec6SMatthias Ringwald                             break;
1358*3deb3ec6SMatthias Ringwald                         default:
1359*3deb3ec6SMatthias Ringwald                             gatt_client_report_error_if_pending(peripheral, packet[4]);
1360*3deb3ec6SMatthias Ringwald                             break;
1361*3deb3ec6SMatthias Ringwald                     }
1362*3deb3ec6SMatthias Ringwald                     break;
1363*3deb3ec6SMatthias Ringwald                 }
1364*3deb3ec6SMatthias Ringwald                 default:
1365*3deb3ec6SMatthias Ringwald                     gatt_client_report_error_if_pending(peripheral, packet[4]);
1366*3deb3ec6SMatthias Ringwald                     break;
1367*3deb3ec6SMatthias Ringwald             }
1368*3deb3ec6SMatthias Ringwald             break;
1369*3deb3ec6SMatthias Ringwald 
1370*3deb3ec6SMatthias Ringwald         default:
1371*3deb3ec6SMatthias Ringwald             log_info("ATT Handler, unhandled response type 0x%02x", packet[0]);
1372*3deb3ec6SMatthias Ringwald             break;
1373*3deb3ec6SMatthias Ringwald     }
1374*3deb3ec6SMatthias Ringwald     gatt_client_run();
1375*3deb3ec6SMatthias Ringwald }
1376*3deb3ec6SMatthias Ringwald 
1377*3deb3ec6SMatthias Ringwald static void att_signed_write_handle_cmac_result(uint8_t hash[8]){
1378*3deb3ec6SMatthias Ringwald     linked_list_iterator_t it;
1379*3deb3ec6SMatthias Ringwald     linked_list_iterator_init(&it, &gatt_client_connections);
1380*3deb3ec6SMatthias Ringwald     while (linked_list_iterator_has_next(&it)){
1381*3deb3ec6SMatthias Ringwald         gatt_client_t * peripheral = (gatt_client_t *) linked_list_iterator_next(&it);
1382*3deb3ec6SMatthias Ringwald         if (peripheral->gatt_client_state == P_W4_CMAC_RESULT){
1383*3deb3ec6SMatthias Ringwald             // store result
1384*3deb3ec6SMatthias Ringwald             memcpy(peripheral->cmac, hash, 8);
1385*3deb3ec6SMatthias Ringwald             // swap64(hash, peripheral->cmac);
1386*3deb3ec6SMatthias Ringwald             peripheral->gatt_client_state = P_W2_SEND_SIGNED_WRITE;
1387*3deb3ec6SMatthias Ringwald             gatt_client_run();
1388*3deb3ec6SMatthias Ringwald             return;
1389*3deb3ec6SMatthias Ringwald         }
1390*3deb3ec6SMatthias Ringwald     }
1391*3deb3ec6SMatthias Ringwald }
1392*3deb3ec6SMatthias Ringwald 
1393*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_signed_write_without_response(uint16_t gatt_client_id, uint16_t con_handle, uint16_t handle, uint16_t message_len, uint8_t * message){
1394*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
1395*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1396*3deb3ec6SMatthias Ringwald     peripheral->le_device_index = sm_le_device_index(con_handle);
1397*3deb3ec6SMatthias Ringwald     if (peripheral->le_device_index < 0) return BLE_PERIPHERAL_IN_WRONG_STATE; // device lookup not done / no stored bonding information
1398*3deb3ec6SMatthias Ringwald 
1399*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1400*3deb3ec6SMatthias Ringwald     peripheral->attribute_handle = handle;
1401*3deb3ec6SMatthias Ringwald     peripheral->attribute_length = message_len;
1402*3deb3ec6SMatthias Ringwald     peripheral->attribute_value = message;
1403*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W4_CMAC_READY;
1404*3deb3ec6SMatthias Ringwald 
1405*3deb3ec6SMatthias Ringwald     gatt_client_run();
1406*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1407*3deb3ec6SMatthias Ringwald }
1408*3deb3ec6SMatthias Ringwald 
1409*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_discover_primary_services(uint16_t gatt_client_id, uint16_t con_handle){
1410*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1411*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1412*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1413*3deb3ec6SMatthias Ringwald 
1414*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1415*3deb3ec6SMatthias Ringwald     peripheral->start_group_handle = 0x0001;
1416*3deb3ec6SMatthias Ringwald     peripheral->end_group_handle   = 0xffff;
1417*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_SERVICE_QUERY;
1418*3deb3ec6SMatthias Ringwald     peripheral->uuid16 = 0;
1419*3deb3ec6SMatthias Ringwald     gatt_client_run();
1420*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1421*3deb3ec6SMatthias Ringwald }
1422*3deb3ec6SMatthias Ringwald 
1423*3deb3ec6SMatthias Ringwald 
1424*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_discover_primary_services_by_uuid16(uint16_t gatt_client_id, uint16_t con_handle, uint16_t uuid16){
1425*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1426*3deb3ec6SMatthias Ringwald 
1427*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1428*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1429*3deb3ec6SMatthias Ringwald 
1430*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1431*3deb3ec6SMatthias Ringwald     peripheral->start_group_handle = 0x0001;
1432*3deb3ec6SMatthias Ringwald     peripheral->end_group_handle   = 0xffff;
1433*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_SERVICE_WITH_UUID_QUERY;
1434*3deb3ec6SMatthias Ringwald     peripheral->uuid16 = uuid16;
1435*3deb3ec6SMatthias Ringwald     sdp_normalize_uuid((uint8_t*) &(peripheral->uuid128), peripheral->uuid16);
1436*3deb3ec6SMatthias Ringwald     gatt_client_run();
1437*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1438*3deb3ec6SMatthias Ringwald }
1439*3deb3ec6SMatthias Ringwald 
1440*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_discover_primary_services_by_uuid128(uint16_t gatt_client_id, uint16_t con_handle, const uint8_t * uuid128){
1441*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1442*3deb3ec6SMatthias Ringwald 
1443*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1444*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1445*3deb3ec6SMatthias Ringwald 
1446*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1447*3deb3ec6SMatthias Ringwald     peripheral->start_group_handle = 0x0001;
1448*3deb3ec6SMatthias Ringwald     peripheral->end_group_handle   = 0xffff;
1449*3deb3ec6SMatthias Ringwald     peripheral->uuid16 = 0;
1450*3deb3ec6SMatthias Ringwald     memcpy(peripheral->uuid128, uuid128, 16);
1451*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_SERVICE_WITH_UUID_QUERY;
1452*3deb3ec6SMatthias Ringwald     gatt_client_run();
1453*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1454*3deb3ec6SMatthias Ringwald }
1455*3deb3ec6SMatthias Ringwald 
1456*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_discover_characteristics_for_service(uint16_t gatt_client_id, uint16_t con_handle, le_service_t *service){
1457*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1458*3deb3ec6SMatthias Ringwald 
1459*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1460*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1461*3deb3ec6SMatthias Ringwald 
1462*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1463*3deb3ec6SMatthias Ringwald     peripheral->start_group_handle = service->start_group_handle;
1464*3deb3ec6SMatthias Ringwald     peripheral->end_group_handle   = service->end_group_handle;
1465*3deb3ec6SMatthias Ringwald     peripheral->filter_with_uuid = 0;
1466*3deb3ec6SMatthias Ringwald     peripheral->characteristic_start_handle = 0;
1467*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_ALL_CHARACTERISTICS_OF_SERVICE_QUERY;
1468*3deb3ec6SMatthias Ringwald     gatt_client_run();
1469*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1470*3deb3ec6SMatthias Ringwald }
1471*3deb3ec6SMatthias Ringwald 
1472*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_find_included_services_for_service(uint16_t gatt_client_id, uint16_t con_handle, le_service_t *service){
1473*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1474*3deb3ec6SMatthias Ringwald 
1475*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1476*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1477*3deb3ec6SMatthias Ringwald 
1478*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1479*3deb3ec6SMatthias Ringwald     peripheral->start_group_handle = service->start_group_handle;
1480*3deb3ec6SMatthias Ringwald     peripheral->end_group_handle   = service->end_group_handle;
1481*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_INCLUDED_SERVICE_QUERY;
1482*3deb3ec6SMatthias Ringwald 
1483*3deb3ec6SMatthias Ringwald     gatt_client_run();
1484*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1485*3deb3ec6SMatthias Ringwald }
1486*3deb3ec6SMatthias Ringwald 
1487*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_discover_characteristics_for_handle_range_by_uuid16(uint16_t gatt_client_id, uint16_t con_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){
1488*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1489*3deb3ec6SMatthias Ringwald 
1490*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1491*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1492*3deb3ec6SMatthias Ringwald 
1493*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1494*3deb3ec6SMatthias Ringwald     peripheral->start_group_handle = start_handle;
1495*3deb3ec6SMatthias Ringwald     peripheral->end_group_handle   = end_handle;
1496*3deb3ec6SMatthias Ringwald     peripheral->filter_with_uuid = 1;
1497*3deb3ec6SMatthias Ringwald     peripheral->uuid16 = uuid16;
1498*3deb3ec6SMatthias Ringwald     sdp_normalize_uuid((uint8_t*) &(peripheral->uuid128), uuid16);
1499*3deb3ec6SMatthias Ringwald     peripheral->characteristic_start_handle = 0;
1500*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_CHARACTERISTIC_WITH_UUID_QUERY;
1501*3deb3ec6SMatthias Ringwald 
1502*3deb3ec6SMatthias Ringwald     gatt_client_run();
1503*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1504*3deb3ec6SMatthias Ringwald }
1505*3deb3ec6SMatthias Ringwald 
1506*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_discover_characteristics_for_handle_range_by_uuid128(uint16_t gatt_client_id, uint16_t con_handle, uint16_t start_handle, uint16_t end_handle, uint8_t * uuid128){
1507*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1508*3deb3ec6SMatthias Ringwald 
1509*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1510*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1511*3deb3ec6SMatthias Ringwald 
1512*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1513*3deb3ec6SMatthias Ringwald     peripheral->start_group_handle = start_handle;
1514*3deb3ec6SMatthias Ringwald     peripheral->end_group_handle   = end_handle;
1515*3deb3ec6SMatthias Ringwald     peripheral->filter_with_uuid = 1;
1516*3deb3ec6SMatthias Ringwald     peripheral->uuid16 = 0;
1517*3deb3ec6SMatthias Ringwald     memcpy(peripheral->uuid128, uuid128, 16);
1518*3deb3ec6SMatthias Ringwald     peripheral->characteristic_start_handle = 0;
1519*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_CHARACTERISTIC_WITH_UUID_QUERY;
1520*3deb3ec6SMatthias Ringwald 
1521*3deb3ec6SMatthias Ringwald     gatt_client_run();
1522*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1523*3deb3ec6SMatthias Ringwald }
1524*3deb3ec6SMatthias Ringwald 
1525*3deb3ec6SMatthias Ringwald 
1526*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_discover_characteristics_for_service_by_uuid16(uint16_t gatt_client_id, uint16_t handle, le_service_t *service, uint16_t  uuid16){
1527*3deb3ec6SMatthias Ringwald     return gatt_client_discover_characteristics_for_handle_range_by_uuid16(gatt_client_id, handle, service->start_group_handle, service->end_group_handle, uuid16);
1528*3deb3ec6SMatthias Ringwald }
1529*3deb3ec6SMatthias Ringwald 
1530*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_discover_characteristics_for_service_by_uuid128(uint16_t gatt_client_id, uint16_t handle, le_service_t *service, uint8_t * uuid128){
1531*3deb3ec6SMatthias Ringwald     return gatt_client_discover_characteristics_for_handle_range_by_uuid128(gatt_client_id, handle, service->start_group_handle, service->end_group_handle, uuid128);
1532*3deb3ec6SMatthias Ringwald }
1533*3deb3ec6SMatthias Ringwald 
1534*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_discover_characteristic_descriptors(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_t *characteristic){
1535*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1536*3deb3ec6SMatthias Ringwald 
1537*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1538*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1539*3deb3ec6SMatthias Ringwald 
1540*3deb3ec6SMatthias Ringwald     if (characteristic->value_handle == characteristic->end_handle){
1541*3deb3ec6SMatthias Ringwald         emit_gatt_complete_event(peripheral, 0);
1542*3deb3ec6SMatthias Ringwald         return BLE_PERIPHERAL_OK;
1543*3deb3ec6SMatthias Ringwald     }
1544*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1545*3deb3ec6SMatthias Ringwald     peripheral->start_group_handle = characteristic->value_handle + 1;
1546*3deb3ec6SMatthias Ringwald     peripheral->end_group_handle   = characteristic->end_handle;
1547*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY;
1548*3deb3ec6SMatthias Ringwald 
1549*3deb3ec6SMatthias Ringwald     gatt_client_run();
1550*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1551*3deb3ec6SMatthias Ringwald }
1552*3deb3ec6SMatthias Ringwald 
1553*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_read_value_of_characteristic_using_value_handle(uint16_t gatt_client_id, uint16_t con_handle, uint16_t value_handle){
1554*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1555*3deb3ec6SMatthias Ringwald 
1556*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1557*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1558*3deb3ec6SMatthias Ringwald 
1559*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1560*3deb3ec6SMatthias Ringwald     peripheral->attribute_handle = value_handle;
1561*3deb3ec6SMatthias Ringwald     peripheral->attribute_offset = 0;
1562*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_READ_CHARACTERISTIC_VALUE_QUERY;
1563*3deb3ec6SMatthias Ringwald     gatt_client_run();
1564*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1565*3deb3ec6SMatthias Ringwald }
1566*3deb3ec6SMatthias Ringwald 
1567*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_read_value_of_characteristics_by_uuid16(uint16_t gatt_client_id, uint16_t con_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid16){
1568*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1569*3deb3ec6SMatthias Ringwald 
1570*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1571*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1572*3deb3ec6SMatthias Ringwald 
1573*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1574*3deb3ec6SMatthias Ringwald     peripheral->start_group_handle = start_handle;
1575*3deb3ec6SMatthias Ringwald     peripheral->end_group_handle = end_handle;
1576*3deb3ec6SMatthias Ringwald     peripheral->query_start_handle = start_handle;
1577*3deb3ec6SMatthias Ringwald     peripheral->query_end_handle = end_handle;
1578*3deb3ec6SMatthias Ringwald     peripheral->uuid16 = uuid16;
1579*3deb3ec6SMatthias Ringwald     sdp_normalize_uuid((uint8_t*) &(peripheral->uuid128), uuid16);
1580*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_READ_BY_TYPE_REQUEST;
1581*3deb3ec6SMatthias Ringwald     gatt_client_run();
1582*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1583*3deb3ec6SMatthias Ringwald }
1584*3deb3ec6SMatthias Ringwald 
1585*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_read_value_of_characteristics_by_uuid128(uint16_t gatt_client_id, uint16_t con_handle, uint16_t start_handle, uint16_t end_handle, uint8_t * uuid128){
1586*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1587*3deb3ec6SMatthias Ringwald 
1588*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1589*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1590*3deb3ec6SMatthias Ringwald 
1591*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1592*3deb3ec6SMatthias Ringwald     peripheral->start_group_handle = start_handle;
1593*3deb3ec6SMatthias Ringwald     peripheral->end_group_handle = end_handle;
1594*3deb3ec6SMatthias Ringwald     peripheral->query_start_handle = start_handle;
1595*3deb3ec6SMatthias Ringwald     peripheral->query_end_handle = end_handle;
1596*3deb3ec6SMatthias Ringwald     peripheral->uuid16 = 0;
1597*3deb3ec6SMatthias Ringwald     memcpy(peripheral->uuid128, uuid128, 16);
1598*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_READ_BY_TYPE_REQUEST;
1599*3deb3ec6SMatthias Ringwald     gatt_client_run();
1600*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1601*3deb3ec6SMatthias Ringwald }
1602*3deb3ec6SMatthias Ringwald 
1603*3deb3ec6SMatthias Ringwald 
1604*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_read_value_of_characteristic(uint16_t gatt_client_id, uint16_t handle, le_characteristic_t *characteristic){
1605*3deb3ec6SMatthias Ringwald     return gatt_client_read_value_of_characteristic_using_value_handle(gatt_client_id, handle, characteristic->value_handle);
1606*3deb3ec6SMatthias Ringwald }
1607*3deb3ec6SMatthias Ringwald 
1608*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_read_long_value_of_characteristic_using_value_handle_with_offset(uint16_t gatt_client_id, uint16_t con_handle, uint16_t characteristic_value_handle, uint16_t offset){
1609*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1610*3deb3ec6SMatthias Ringwald 
1611*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1612*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1613*3deb3ec6SMatthias Ringwald 
1614*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1615*3deb3ec6SMatthias Ringwald     peripheral->attribute_handle = characteristic_value_handle;
1616*3deb3ec6SMatthias Ringwald     peripheral->attribute_offset = offset;
1617*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_READ_BLOB_QUERY;
1618*3deb3ec6SMatthias Ringwald     gatt_client_run();
1619*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1620*3deb3ec6SMatthias Ringwald }
1621*3deb3ec6SMatthias Ringwald 
1622*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_read_long_value_of_characteristic_using_value_handle(uint16_t gatt_client_id, uint16_t con_handle, uint16_t characteristic_value_handle){
1623*3deb3ec6SMatthias Ringwald     return gatt_client_read_long_value_of_characteristic_using_value_handle_with_offset(gatt_client_id, con_handle, characteristic_value_handle, 0);
1624*3deb3ec6SMatthias Ringwald }
1625*3deb3ec6SMatthias Ringwald 
1626*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_read_long_value_of_characteristic(uint16_t gatt_client_id, uint16_t handle, le_characteristic_t *characteristic){
1627*3deb3ec6SMatthias Ringwald     return gatt_client_read_long_value_of_characteristic_using_value_handle(gatt_client_id, handle, characteristic->value_handle);
1628*3deb3ec6SMatthias Ringwald }
1629*3deb3ec6SMatthias Ringwald 
1630*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_read_multiple_characteristic_values(uint16_t gatt_client_id, uint16_t con_handle, int num_value_handles, uint16_t * value_handles){
1631*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1632*3deb3ec6SMatthias Ringwald 
1633*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1634*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1635*3deb3ec6SMatthias Ringwald 
1636*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1637*3deb3ec6SMatthias Ringwald     peripheral->read_multiple_handle_count = num_value_handles;
1638*3deb3ec6SMatthias Ringwald     peripheral->read_multiple_handles = value_handles;
1639*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_READ_MULTIPLE_REQUEST;
1640*3deb3ec6SMatthias Ringwald     gatt_client_run();
1641*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1642*3deb3ec6SMatthias Ringwald }
1643*3deb3ec6SMatthias Ringwald 
1644*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_write_value_of_characteristic_without_response(uint16_t gatt_client_id, uint16_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){
1645*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle(con_handle);
1646*3deb3ec6SMatthias Ringwald 
1647*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1648*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1649*3deb3ec6SMatthias Ringwald 
1650*3deb3ec6SMatthias Ringwald     if (value_length > peripheral_mtu(peripheral) - 3) return BLE_VALUE_TOO_LONG;
1651*3deb3ec6SMatthias Ringwald     if (!l2cap_can_send_fixed_channel_packet_now(peripheral->handle)) return BLE_PERIPHERAL_BUSY;
1652*3deb3ec6SMatthias Ringwald 
1653*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1654*3deb3ec6SMatthias Ringwald     att_write_request(ATT_WRITE_COMMAND, peripheral->handle, value_handle, value_length, value);
1655*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1656*3deb3ec6SMatthias Ringwald }
1657*3deb3ec6SMatthias Ringwald 
1658*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_write_value_of_characteristic(uint16_t gatt_client_id, uint16_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * data){
1659*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1660*3deb3ec6SMatthias Ringwald 
1661*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1662*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1663*3deb3ec6SMatthias Ringwald 
1664*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1665*3deb3ec6SMatthias Ringwald     peripheral->attribute_handle = value_handle;
1666*3deb3ec6SMatthias Ringwald     peripheral->attribute_length = value_length;
1667*3deb3ec6SMatthias Ringwald     peripheral->attribute_value = data;
1668*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_WRITE_CHARACTERISTIC_VALUE;
1669*3deb3ec6SMatthias Ringwald     gatt_client_run();
1670*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1671*3deb3ec6SMatthias Ringwald }
1672*3deb3ec6SMatthias Ringwald 
1673*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_write_long_value_of_characteristic_with_offset(uint16_t gatt_client_id, uint16_t con_handle, uint16_t value_handle, uint16_t offset, uint16_t value_length, uint8_t  * data){
1674*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1675*3deb3ec6SMatthias Ringwald 
1676*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1677*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1678*3deb3ec6SMatthias Ringwald 
1679*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1680*3deb3ec6SMatthias Ringwald     peripheral->attribute_handle = value_handle;
1681*3deb3ec6SMatthias Ringwald     peripheral->attribute_length = value_length;
1682*3deb3ec6SMatthias Ringwald     peripheral->attribute_offset = offset;
1683*3deb3ec6SMatthias Ringwald     peripheral->attribute_value = data;
1684*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_PREPARE_WRITE;
1685*3deb3ec6SMatthias Ringwald     gatt_client_run();
1686*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1687*3deb3ec6SMatthias Ringwald }
1688*3deb3ec6SMatthias Ringwald 
1689*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_write_long_value_of_characteristic(uint16_t gatt_client_id, uint16_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){
1690*3deb3ec6SMatthias Ringwald     return gatt_client_write_long_value_of_characteristic_with_offset(gatt_client_id, con_handle, value_handle, 0, value_length, value);
1691*3deb3ec6SMatthias Ringwald }
1692*3deb3ec6SMatthias Ringwald 
1693*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_reliable_write_long_value_of_characteristic(uint16_t gatt_client_id, uint16_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t * value){
1694*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1695*3deb3ec6SMatthias Ringwald 
1696*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1697*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1698*3deb3ec6SMatthias Ringwald 
1699*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1700*3deb3ec6SMatthias Ringwald     peripheral->attribute_handle = value_handle;
1701*3deb3ec6SMatthias Ringwald     peripheral->attribute_length = value_length;
1702*3deb3ec6SMatthias Ringwald     peripheral->attribute_offset = 0;
1703*3deb3ec6SMatthias Ringwald     peripheral->attribute_value = value;
1704*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_PREPARE_RELIABLE_WRITE;
1705*3deb3ec6SMatthias Ringwald     gatt_client_run();
1706*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1707*3deb3ec6SMatthias Ringwald }
1708*3deb3ec6SMatthias Ringwald 
1709*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_write_client_characteristic_configuration(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_t * characteristic, uint16_t configuration){
1710*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1711*3deb3ec6SMatthias Ringwald 
1712*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1713*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1714*3deb3ec6SMatthias Ringwald 
1715*3deb3ec6SMatthias Ringwald     if ( (configuration & GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION) &&
1716*3deb3ec6SMatthias Ringwald         (characteristic->properties & ATT_PROPERTY_NOTIFY) == 0) {
1717*3deb3ec6SMatthias Ringwald         log_info("le_central_write_client_characteristic_configuration: BLE_CHARACTERISTIC_NOTIFICATION_NOT_SUPPORTED");
1718*3deb3ec6SMatthias Ringwald         return BLE_CHARACTERISTIC_NOTIFICATION_NOT_SUPPORTED;
1719*3deb3ec6SMatthias Ringwald     } else if ( (configuration & GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_INDICATION) &&
1720*3deb3ec6SMatthias Ringwald                (characteristic->properties & ATT_PROPERTY_INDICATE) == 0){
1721*3deb3ec6SMatthias Ringwald         log_info("le_central_write_client_characteristic_configuration: BLE_CHARACTERISTIC_INDICATION_NOT_SUPPORTED");
1722*3deb3ec6SMatthias Ringwald         return BLE_CHARACTERISTIC_INDICATION_NOT_SUPPORTED;
1723*3deb3ec6SMatthias Ringwald     }
1724*3deb3ec6SMatthias Ringwald 
1725*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1726*3deb3ec6SMatthias Ringwald     peripheral->start_group_handle = characteristic->value_handle;
1727*3deb3ec6SMatthias Ringwald     peripheral->end_group_handle = characteristic->end_handle;
1728*3deb3ec6SMatthias Ringwald     bt_store_16(peripheral->client_characteristic_configuration_value, 0, configuration);
1729*3deb3ec6SMatthias Ringwald 
1730*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_READ_CLIENT_CHARACTERISTIC_CONFIGURATION_QUERY;
1731*3deb3ec6SMatthias Ringwald     gatt_client_run();
1732*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1733*3deb3ec6SMatthias Ringwald }
1734*3deb3ec6SMatthias Ringwald 
1735*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_read_characteristic_descriptor_using_descriptor_handle(uint16_t gatt_client_id, uint16_t con_handle, uint16_t descriptor_handle){
1736*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1737*3deb3ec6SMatthias Ringwald 
1738*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1739*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1740*3deb3ec6SMatthias Ringwald 
1741*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1742*3deb3ec6SMatthias Ringwald     peripheral->attribute_handle = descriptor_handle;
1743*3deb3ec6SMatthias Ringwald 
1744*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_READ_CHARACTERISTIC_DESCRIPTOR_QUERY;
1745*3deb3ec6SMatthias Ringwald     gatt_client_run();
1746*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1747*3deb3ec6SMatthias Ringwald }
1748*3deb3ec6SMatthias Ringwald 
1749*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_read_characteristic_descriptor(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_descriptor_t * descriptor){
1750*3deb3ec6SMatthias Ringwald     return gatt_client_read_characteristic_descriptor_using_descriptor_handle(gatt_client_id, con_handle, descriptor->handle);
1751*3deb3ec6SMatthias Ringwald }
1752*3deb3ec6SMatthias Ringwald 
1753*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_read_long_characteristic_descriptor_using_descriptor_handle_with_offset(uint16_t gatt_client_id, uint16_t con_handle, uint16_t descriptor_handle, uint16_t offset){
1754*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1755*3deb3ec6SMatthias Ringwald 
1756*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1757*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1758*3deb3ec6SMatthias Ringwald 
1759*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1760*3deb3ec6SMatthias Ringwald     peripheral->attribute_handle = descriptor_handle;
1761*3deb3ec6SMatthias Ringwald     peripheral->attribute_offset = offset;
1762*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_READ_BLOB_CHARACTERISTIC_DESCRIPTOR_QUERY;
1763*3deb3ec6SMatthias Ringwald     gatt_client_run();
1764*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1765*3deb3ec6SMatthias Ringwald }
1766*3deb3ec6SMatthias Ringwald 
1767*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_read_long_characteristic_descriptor_using_descriptor_handle(uint16_t gatt_client_id, uint16_t con_handle, uint16_t descriptor_handle){
1768*3deb3ec6SMatthias Ringwald     return gatt_client_read_long_characteristic_descriptor_using_descriptor_handle_with_offset(gatt_client_id, con_handle, descriptor_handle, 0);
1769*3deb3ec6SMatthias Ringwald }
1770*3deb3ec6SMatthias Ringwald 
1771*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_read_long_characteristic_descriptor(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_descriptor_t * descriptor){
1772*3deb3ec6SMatthias Ringwald     return gatt_client_read_long_characteristic_descriptor_using_descriptor_handle(gatt_client_id, con_handle, descriptor->handle);
1773*3deb3ec6SMatthias Ringwald }
1774*3deb3ec6SMatthias Ringwald 
1775*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_write_characteristic_descriptor_using_descriptor_handle(uint16_t gatt_client_id, uint16_t con_handle, uint16_t descriptor_handle, uint16_t length, uint8_t  * data){
1776*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1777*3deb3ec6SMatthias Ringwald 
1778*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1779*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1780*3deb3ec6SMatthias Ringwald 
1781*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1782*3deb3ec6SMatthias Ringwald     peripheral->attribute_handle = descriptor_handle;
1783*3deb3ec6SMatthias Ringwald     peripheral->attribute_length = length;
1784*3deb3ec6SMatthias Ringwald     peripheral->attribute_offset = 0;
1785*3deb3ec6SMatthias Ringwald     peripheral->attribute_value = data;
1786*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_SEND_WRITE_CHARACTERISTIC_DESCRIPTOR;
1787*3deb3ec6SMatthias Ringwald     gatt_client_run();
1788*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1789*3deb3ec6SMatthias Ringwald }
1790*3deb3ec6SMatthias Ringwald 
1791*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_write_characteristic_descriptor(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_descriptor_t * descriptor, uint16_t length, uint8_t * value){
1792*3deb3ec6SMatthias Ringwald     return gatt_client_write_characteristic_descriptor_using_descriptor_handle(gatt_client_id, con_handle, descriptor->handle, length, value);
1793*3deb3ec6SMatthias Ringwald }
1794*3deb3ec6SMatthias Ringwald 
1795*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_write_long_characteristic_descriptor_using_descriptor_handle_with_offset(uint16_t gatt_client_id, uint16_t con_handle, uint16_t descriptor_handle, uint16_t offset, uint16_t length, uint8_t  * data){
1796*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1797*3deb3ec6SMatthias Ringwald 
1798*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1799*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1800*3deb3ec6SMatthias Ringwald 
1801*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1802*3deb3ec6SMatthias Ringwald     peripheral->attribute_handle = descriptor_handle;
1803*3deb3ec6SMatthias Ringwald     peripheral->attribute_length = length;
1804*3deb3ec6SMatthias Ringwald     peripheral->attribute_offset = offset;
1805*3deb3ec6SMatthias Ringwald     peripheral->attribute_value = data;
1806*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_PREPARE_WRITE_CHARACTERISTIC_DESCRIPTOR;
1807*3deb3ec6SMatthias Ringwald     gatt_client_run();
1808*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1809*3deb3ec6SMatthias Ringwald }
1810*3deb3ec6SMatthias Ringwald 
1811*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_write_long_characteristic_descriptor_using_descriptor_handle(uint16_t gatt_client_id, uint16_t con_handle, uint16_t descriptor_handle, uint16_t length, uint8_t * data){
1812*3deb3ec6SMatthias Ringwald     return gatt_client_write_long_characteristic_descriptor_using_descriptor_handle_with_offset(gatt_client_id, con_handle, descriptor_handle, 0, length, data );
1813*3deb3ec6SMatthias Ringwald }
1814*3deb3ec6SMatthias Ringwald 
1815*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_write_long_characteristic_descriptor(uint16_t gatt_client_id, uint16_t con_handle, le_characteristic_descriptor_t * descriptor, uint16_t length, uint8_t * value){
1816*3deb3ec6SMatthias Ringwald     return gatt_client_write_long_characteristic_descriptor_using_descriptor_handle(gatt_client_id, con_handle, descriptor->handle, length, value);
1817*3deb3ec6SMatthias Ringwald }
1818*3deb3ec6SMatthias Ringwald 
1819*3deb3ec6SMatthias Ringwald /**
1820*3deb3ec6SMatthias Ringwald  * @brief -> gatt complete event
1821*3deb3ec6SMatthias Ringwald  */
1822*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_prepare_write(uint16_t gatt_client_id, uint16_t con_handle, uint16_t attribute_handle, uint16_t offset, uint16_t length, uint8_t * data){
1823*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1824*3deb3ec6SMatthias Ringwald 
1825*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1826*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1827*3deb3ec6SMatthias Ringwald 
1828*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1829*3deb3ec6SMatthias Ringwald     peripheral->attribute_handle = attribute_handle;
1830*3deb3ec6SMatthias Ringwald     peripheral->attribute_length = length;
1831*3deb3ec6SMatthias Ringwald     peripheral->attribute_offset = offset;
1832*3deb3ec6SMatthias Ringwald     peripheral->attribute_value = data;
1833*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_PREPARE_WRITE_SINGLE;
1834*3deb3ec6SMatthias Ringwald     gatt_client_run();
1835*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1836*3deb3ec6SMatthias Ringwald }
1837*3deb3ec6SMatthias Ringwald 
1838*3deb3ec6SMatthias Ringwald /**
1839*3deb3ec6SMatthias Ringwald  * @brief -> gatt complete event
1840*3deb3ec6SMatthias Ringwald  */
1841*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_execute_write(uint16_t gatt_client_id, uint16_t con_handle){
1842*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1843*3deb3ec6SMatthias Ringwald 
1844*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1845*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1846*3deb3ec6SMatthias Ringwald 
1847*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1848*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_EXECUTE_PREPARED_WRITE;
1849*3deb3ec6SMatthias Ringwald     gatt_client_run();
1850*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1851*3deb3ec6SMatthias Ringwald }
1852*3deb3ec6SMatthias Ringwald 
1853*3deb3ec6SMatthias Ringwald /**
1854*3deb3ec6SMatthias Ringwald  * @brief -> gatt complete event
1855*3deb3ec6SMatthias Ringwald  */
1856*3deb3ec6SMatthias Ringwald le_command_status_t gatt_client_cancel_write(uint16_t gatt_client_id, uint16_t con_handle){
1857*3deb3ec6SMatthias Ringwald     gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle);
1858*3deb3ec6SMatthias Ringwald 
1859*3deb3ec6SMatthias Ringwald     if (!peripheral) return (le_command_status_t) BTSTACK_MEMORY_ALLOC_FAILED;
1860*3deb3ec6SMatthias Ringwald     if (!is_ready(peripheral)) return BLE_PERIPHERAL_IN_WRONG_STATE;
1861*3deb3ec6SMatthias Ringwald 
1862*3deb3ec6SMatthias Ringwald     peripheral->subclient_id = gatt_client_id;
1863*3deb3ec6SMatthias Ringwald     peripheral->gatt_client_state = P_W2_CANCEL_PREPARED_WRITE;
1864*3deb3ec6SMatthias Ringwald     gatt_client_run();
1865*3deb3ec6SMatthias Ringwald     return BLE_PERIPHERAL_OK;
1866*3deb3ec6SMatthias Ringwald }
1867*3deb3ec6SMatthias Ringwald 
1868*3deb3ec6SMatthias Ringwald void gatt_client_pts_suppress_mtu_exchange(void){
1869*3deb3ec6SMatthias Ringwald     pts_suppress_mtu_exchange = 1;
1870*3deb3ec6SMatthias Ringwald }
1871*3deb3ec6SMatthias Ringwald 
1872