xref: /btstack/src/classic/sdp_client.c (revision ceed67ffe68ea5103bbc5647a2e000ed0e08b747)
1 /*
2  * Copyright (C) 2014 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #define BTSTACK_FILE__ "sdp_client.c"
39 
40 /*
41  *  sdp_client.c
42  */
43 #include "btstack_config.h"
44 
45 #include "bluetooth_psm.h"
46 #include "bluetooth_sdp.h"
47 #include "btstack_debug.h"
48 #include "btstack_event.h"
49 #include "classic/core.h"
50 #include "classic/sdp_client.h"
51 #include "classic/sdp_server.h"
52 #include "classic/sdp_util.h"
53 #include "hci_cmd.h"
54 #include "l2cap.h"
55 
56 // Types SDP Parser - Data Element stream helper
57 typedef enum {
58     GET_LIST_LENGTH = 1,
59     GET_RECORD_LENGTH,
60     GET_ATTRIBUTE_ID_HEADER_LENGTH,
61     GET_ATTRIBUTE_ID,
62     GET_ATTRIBUTE_VALUE_LENGTH,
63     GET_ATTRIBUTE_VALUE
64 } sdp_parser_state_t;
65 
66 // Types SDP Client
67 typedef enum {
68     INIT, W4_CONNECT, W2_SEND, W4_RESPONSE, QUERY_COMPLETE
69 } sdp_client_state_t;
70 
71 static uint8_t sdp_client_des_attribute_id_list[] = {0x35, 0x05, 0x0A, 0x00, 0x00, 0xff, 0xff};  // Attribute: 0x0000 - 0xffff
72 
73 // Prototypes SDP Parser
74 void sdp_parser_init(btstack_packet_handler_t callback);
75 void sdp_parser_handle_chunk(uint8_t * data, uint16_t size);
76 void sdp_parser_handle_done(uint8_t status);
77 void sdp_parser_init_service_attribute_search(void);
78 void sdp_parser_init_service_search(void);
79 void sdp_parser_handle_service_search(uint8_t * data, uint16_t total_count, uint16_t record_handle_count);
80 
81 // Prototypes SDP Client
82 void sdp_client_reset(void);
83 void sdp_client_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
84 static uint16_t sdp_client_setup_service_search_attribute_request(uint8_t * data);
85 #ifdef ENABLE_SDP_EXTRA_QUERIES
86 static uint16_t sdp_client_setup_service_search_request(uint8_t * data);
87 static uint16_t sdp_client_setup_service_attribute_request(uint8_t * data);
88 static void     sdp_client_parse_service_search_response(uint8_t* packet, uint16_t size);
89 static void     sdp_client_parse_service_attribute_response(uint8_t* packet, uint16_t size);
90 #endif
91 
92 // State DES Parser
93 static de_state_t des_parser_de_header_state;
94 
95 // State SDP Parser
96 static sdp_parser_state_t sdp_parser_state;
97 static uint16_t sdp_parser_attribute_id = 0;
98 static uint16_t sdp_parser_attribute_bytes_received;
99 static uint16_t sdp_parser_attribute_bytes_delivered;
100 static uint16_t sdp_parser_list_offset;
101 static uint16_t sdp_parser_list_size;
102 static uint16_t sdp_parser_record_offset;
103 static uint16_t sdp_parser_record_size;
104 static uint16_t sdp_parser_attribute_value_size;
105 static int      sdp_parser_record_counter;
106 static btstack_packet_handler_t sdp_parser_callback;
107 
108 // State SDP Client
109 static uint16_t  sdp_client_mtu;
110 static uint16_t  sdp_client_sdp_cid = 0x40;
111 static const uint8_t * sdp_client_service_search_pattern;
112 static const uint8_t * sdp_client_attribute_id_list;
113 static uint16_t  sdp_client_transaction_id;
114 static uint8_t   sdp_client_continuation_state[16];
115 static uint8_t   sdp_client_continuation_state_len;
116 static sdp_client_state_t sdp_client_state = INIT;
117 static sdp_pdu_id_t sdp_client_pdu_id = SDP_Invalid;
118 
119 // Query registration
120 static btstack_linked_list_t sdp_client_query_requests;
121 
122 #ifdef ENABLE_SDP_EXTRA_QUERIES
123 static uint32_t sdp_client_service_record_handle;
124 static uint32_t sdp_client_record_handle;
125 #endif
126 
127 // DES Parser
128 void de_state_init(de_state_t * de_state){
129     de_state->in_state_GET_DE_HEADER_LENGTH = 1;
130     de_state->addon_header_bytes = 0;
131     de_state->de_size = 0;
132     de_state->de_offset = 0;
133 }
134 
135 int de_state_size(uint8_t eventByte, de_state_t *de_state){
136     if (de_state->in_state_GET_DE_HEADER_LENGTH){
137         de_state->addon_header_bytes = de_get_header_size(&eventByte) - 1;
138         de_state->de_size = 0;
139         de_state->de_offset = 0;
140 
141         if (de_state->addon_header_bytes == 0){
142             // de_nil has no size
143             de_type_t de_type = (de_type_t) (eventByte >> 3);
144             if (de_type == DE_NIL){
145                 return 1;
146             }
147             // addon_header_bytes == 0 <-> de_size_type in [DE_SIZE_8, ..., DE_SIZE_128]
148             de_state->de_size = 1 << (eventByte & 7);
149             return 1;
150         }
151         de_state->in_state_GET_DE_HEADER_LENGTH = 0;
152         return 0;
153     }
154 
155     if (de_state->addon_header_bytes > 0){
156         de_state->de_size = (de_state->de_size << 8) | eventByte;
157         de_state->addon_header_bytes--;
158     }
159     if (de_state->addon_header_bytes > 0) return 0;
160     // log_info("Data element payload is %d bytes.", de_state->de_size);
161     de_state->in_state_GET_DE_HEADER_LENGTH = 1;
162     return 1;
163 }
164 
165 // SDP Parser
166 static void sdp_parser_emit_value_byte(uint8_t event_byte){
167     uint8_t event[11];
168     event[0] = SDP_EVENT_QUERY_ATTRIBUTE_VALUE;
169     event[1] = 9;
170     little_endian_store_16(event, 2, sdp_parser_record_counter);
171     little_endian_store_16(event, 4, sdp_parser_attribute_id);
172     little_endian_store_16(event, 6, sdp_parser_attribute_value_size);
173     little_endian_store_16(event, 8, sdp_parser_attribute_bytes_delivered);
174     event[10] = event_byte;
175     (*sdp_parser_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
176 }
177 
178 static void sdp_parser_process_byte(uint8_t eventByte){
179     // count all bytes
180     sdp_parser_list_offset++;
181     sdp_parser_record_offset++;
182 
183     // log_info(" parse BYTE_RECEIVED %02x", eventByte);
184     switch(sdp_parser_state){
185         case GET_LIST_LENGTH:
186             if (!de_state_size(eventByte, &des_parser_de_header_state)) break;
187             sdp_parser_list_offset = des_parser_de_header_state.de_offset;
188             sdp_parser_list_size = des_parser_de_header_state.de_size;
189             // log_info("parser: List offset %u, list size %u", list_offset, list_size);
190 
191             sdp_parser_record_counter = 0;
192             sdp_parser_state = GET_RECORD_LENGTH;
193             break;
194 
195         case GET_RECORD_LENGTH:
196             // check size
197             if (!de_state_size(eventByte, &des_parser_de_header_state)) break;
198             // log_info("parser: Record payload is %d bytes.", de_header_state.de_size);
199             sdp_parser_record_offset = des_parser_de_header_state.de_offset;
200             sdp_parser_record_size = des_parser_de_header_state.de_size;
201             sdp_parser_state = GET_ATTRIBUTE_ID_HEADER_LENGTH;
202             break;
203 
204         case GET_ATTRIBUTE_ID_HEADER_LENGTH:
205             if (!de_state_size(eventByte, &des_parser_de_header_state)) break;
206             sdp_parser_attribute_id = 0;
207             log_debug("ID data is stored in %d bytes.", (int) des_parser_de_header_state.de_size);
208             sdp_parser_state = GET_ATTRIBUTE_ID;
209             break;
210 
211         case GET_ATTRIBUTE_ID:
212             sdp_parser_attribute_id = (sdp_parser_attribute_id << 8) | eventByte;
213             des_parser_de_header_state.de_size--;
214             if (des_parser_de_header_state.de_size > 0) break;
215             log_debug("parser: Attribute ID: %04x.", sdp_parser_attribute_id);
216 
217             sdp_parser_state = GET_ATTRIBUTE_VALUE_LENGTH;
218             sdp_parser_attribute_bytes_received  = 0;
219             sdp_parser_attribute_bytes_delivered = 0;
220             sdp_parser_attribute_value_size      = 0;
221             de_state_init(&des_parser_de_header_state);
222             break;
223 
224         case GET_ATTRIBUTE_VALUE_LENGTH:
225             sdp_parser_attribute_bytes_received++;
226             sdp_parser_emit_value_byte(eventByte);
227             sdp_parser_attribute_bytes_delivered++;
228             if (!de_state_size(eventByte, &des_parser_de_header_state)) break;
229 
230             sdp_parser_attribute_value_size = des_parser_de_header_state.de_size + sdp_parser_attribute_bytes_received;
231 
232             sdp_parser_state = GET_ATTRIBUTE_VALUE;
233             break;
234 
235         case GET_ATTRIBUTE_VALUE:
236             sdp_parser_attribute_bytes_received++;
237             sdp_parser_emit_value_byte(eventByte);
238             sdp_parser_attribute_bytes_delivered++;
239             // log_debug("paser: attribute_bytes_received %u, attribute_value_size %u", attribute_bytes_received, attribute_value_size);
240 
241             if (sdp_parser_attribute_bytes_received < sdp_parser_attribute_value_size) break;
242             // log_debug("parser: Record offset %u, record size %u", record_offset, record_size);
243             if (sdp_parser_record_offset != sdp_parser_record_size){
244                 sdp_parser_state = GET_ATTRIBUTE_ID_HEADER_LENGTH;
245                 // log_debug("Get next attribute");
246                 break;
247             }
248             sdp_parser_record_offset = 0;
249             // log_debug("parser: List offset %u, list size %u", list_offset, list_size);
250 
251             if ((sdp_parser_list_size > 0) && (sdp_parser_list_offset != sdp_parser_list_size)){
252                 sdp_parser_record_counter++;
253                 sdp_parser_state = GET_RECORD_LENGTH;
254                 log_debug("parser: END_OF_RECORD");
255                 break;
256             }
257             sdp_parser_list_offset = 0;
258             de_state_init(&des_parser_de_header_state);
259             sdp_parser_state = GET_LIST_LENGTH;
260             sdp_parser_record_counter = 0;
261             log_debug("parser: END_OF_RECORD & DONE");
262             break;
263         default:
264             break;
265     }
266 }
267 
268 void sdp_parser_init(btstack_packet_handler_t callback){
269     // init
270     sdp_parser_callback = callback;
271     de_state_init(&des_parser_de_header_state);
272     sdp_parser_state = GET_LIST_LENGTH;
273     sdp_parser_list_offset = 0;
274     sdp_parser_list_size = 0;
275     sdp_parser_record_offset = 0;
276     sdp_parser_record_counter = 0;
277     sdp_parser_record_size = 0;
278     sdp_parser_attribute_id = 0;
279     sdp_parser_attribute_bytes_received = 0;
280     sdp_parser_attribute_bytes_delivered = 0;
281 }
282 
283 static void sdp_parser_deinit(void) {
284     sdp_parser_callback = NULL;
285     sdp_parser_attribute_value_size = 0;
286     sdp_parser_record_counter = 0;
287 }
288 
289 void sdp_client_init(void){
290 }
291 
292 void sdp_client_deinit(void){
293     sdp_parser_deinit();
294     sdp_client_state = INIT;
295     sdp_client_sdp_cid = 0x40;
296     sdp_client_service_search_pattern = NULL;
297     sdp_client_attribute_id_list = NULL;
298     sdp_client_transaction_id = 0;
299     sdp_client_continuation_state_len = 0;
300     sdp_client_state = INIT;
301     sdp_client_pdu_id = SDP_Invalid;
302 #ifdef ENABLE_SDP_EXTRA_QUERIES
303     sdp_client_service_record_handle = 0;
304     sdp_client_record_handle = 0;
305 #endif
306 }
307 
308 // for testing only
309 void sdp_client_reset(void){
310     sdp_client_deinit();
311 }
312 
313 void sdp_parser_handle_chunk(uint8_t * data, uint16_t size){
314     int i;
315     for (i=0;i<size;i++){
316         sdp_parser_process_byte(data[i]);
317     }
318 }
319 
320 #ifdef ENABLE_SDP_EXTRA_QUERIES
321 void sdp_parser_init_service_attribute_search(void){
322     // init
323     de_state_init(&des_parser_de_header_state);
324     sdp_parser_state = GET_RECORD_LENGTH;
325     sdp_parser_list_offset = 0;
326     sdp_parser_record_offset = 0;
327     sdp_parser_record_counter = 0;
328 }
329 
330 void sdp_parser_init_service_search(void){
331     sdp_parser_record_offset = 0;
332 }
333 
334 void sdp_parser_handle_service_search(uint8_t * data, uint16_t total_count, uint16_t record_handle_count){
335     int i;
336     for (i=0;i<record_handle_count;i++){
337         sdp_client_record_handle = big_endian_read_32(data, i * 4);
338         sdp_parser_record_counter++;
339         uint8_t event[10];
340         event[0] = SDP_EVENT_QUERY_SERVICE_RECORD_HANDLE;
341         event[1] = 8;
342         little_endian_store_16(event, 2, total_count);
343         little_endian_store_16(event, 4, sdp_parser_record_counter);
344         little_endian_store_32(event, 6, sdp_client_record_handle);
345         (*sdp_parser_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
346     }
347 }
348 #endif
349 
350 static void sdp_client_notify_callbacks(void){
351     while (sdp_client_ready()) {
352         btstack_context_callback_registration_t *callback = (btstack_context_callback_registration_t *) btstack_linked_list_pop(&sdp_client_query_requests);
353         if (callback != NULL) {
354             (*callback->callback)(callback->context);
355         } else {
356             return;
357         }
358     }
359 }
360 
361 void sdp_parser_handle_done(uint8_t status){
362     // reset state
363     sdp_client_state = INIT;
364 
365     // emit query complete event
366     uint8_t event[3];
367     event[0] = SDP_EVENT_QUERY_COMPLETE;
368     event[1] = 1;
369     event[2] = status;
370     (*sdp_parser_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
371 
372     // trigger next query if pending
373     sdp_client_notify_callbacks();
374 }
375 
376 // SDP Client
377 
378 // TODO: inline if not needed (des(des))
379 
380 static void sdp_client_parse_attribute_lists(uint8_t* packet, uint16_t length){
381     sdp_parser_handle_chunk(packet, length);
382 }
383 
384 
385 static void sdp_client_send_request(uint16_t channel){
386 
387     if (sdp_client_state != W2_SEND) return;
388 
389     l2cap_reserve_packet_buffer();
390     uint8_t * data = l2cap_get_outgoing_buffer();
391     uint16_t request_len = 0;
392 
393     switch (sdp_client_pdu_id){
394 #ifdef ENABLE_SDP_EXTRA_QUERIES
395         case SDP_ServiceSearchResponse:
396             request_len = sdp_client_setup_service_search_request(data);
397             break;
398         case SDP_ServiceAttributeResponse:
399             request_len = sdp_client_setup_service_attribute_request(data);
400             break;
401 #endif
402         case SDP_ServiceSearchAttributeResponse:
403             request_len = sdp_client_setup_service_search_attribute_request(data);
404             break;
405         default:
406             log_error("SDP Client sdp_client_send_request :: PDU ID invalid. %u", sdp_client_pdu_id);
407             return;
408     }
409 
410     // prevent re-entrance
411     sdp_client_state = W4_RESPONSE;
412     sdp_client_pdu_id = SDP_Invalid;
413     l2cap_send_prepared(channel, request_len);
414 }
415 
416 
417 static void sdp_client_parse_service_search_attribute_response(uint8_t* packet, uint16_t size){
418 
419     uint16_t offset = 3;
420     if ((offset + 2 + 2) > size) return;  // parameterLength + attributeListByteCount
421     uint16_t parameterLength = big_endian_read_16(packet,offset);
422     offset+=2;
423     if ((offset + parameterLength) > size) return;
424 
425     // AttributeListByteCount <= mtu
426     uint16_t attributeListByteCount = big_endian_read_16(packet,offset);
427     offset+=2;
428     if (attributeListByteCount > sdp_client_mtu){
429         log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in found attribute list is larger then the MaximumAttributeByteCount.");
430         return;
431     }
432 
433     // AttributeLists
434     if ((offset + attributeListByteCount) > size) return;
435     sdp_client_parse_attribute_lists(packet+offset, attributeListByteCount);
436     offset+=attributeListByteCount;
437 
438     // continuation state len
439     if ((offset + 1) > size) return;
440     sdp_client_continuation_state_len = packet[offset];
441     offset++;
442     if (sdp_client_continuation_state_len > 16){
443         sdp_client_continuation_state_len = 0;
444         log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in continuation state exceedes 16.");
445         return;
446     }
447 
448     // continuation state
449     if ((offset + sdp_client_continuation_state_len) > size) return;
450     (void)memcpy(sdp_client_continuation_state, packet + offset, sdp_client_continuation_state_len);
451     // offset+=continuationStateLen;
452 }
453 
454 void sdp_client_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
455 
456     // uint16_t handle;
457     if (packet_type == L2CAP_DATA_PACKET){
458         if (size < 3) return;
459         uint16_t responseTransactionID = big_endian_read_16(packet,1);
460         if (responseTransactionID != sdp_client_transaction_id){
461             log_error("Mismatching transaction ID, expected %u, found %u.", sdp_client_transaction_id, responseTransactionID);
462             return;
463         }
464 
465         sdp_client_pdu_id = (sdp_pdu_id_t)packet[0];
466         switch (sdp_client_pdu_id){
467             case SDP_ErrorResponse:
468                 log_error("Received error response with code %u, disconnecting", packet[2]);
469                 l2cap_disconnect(sdp_client_sdp_cid);
470                 return;
471 #ifdef ENABLE_SDP_EXTRA_QUERIES
472             case SDP_ServiceSearchResponse:
473                 sdp_client_parse_service_search_response(packet, size);
474                 break;
475             case SDP_ServiceAttributeResponse:
476                 sdp_client_parse_service_attribute_response(packet, size);
477                 break;
478 #endif
479             case SDP_ServiceSearchAttributeResponse:
480                 sdp_client_parse_service_search_attribute_response(packet, size);
481                 break;
482             default:
483                 log_error("PDU ID %u unexpected/invalid", sdp_client_pdu_id);
484                 return;
485         }
486 
487         // continuation set or DONE?
488         if (sdp_client_continuation_state_len == 0){
489             log_debug("SDP Client Query DONE! ");
490             sdp_client_state = QUERY_COMPLETE;
491             l2cap_disconnect(sdp_client_sdp_cid);
492             return;
493         }
494         // prepare next request and send
495         sdp_client_state = W2_SEND;
496         l2cap_request_can_send_now_event(sdp_client_sdp_cid);
497         return;
498     }
499 
500     if (packet_type != HCI_EVENT_PACKET) return;
501 
502     switch(hci_event_packet_get_type(packet)){
503         case L2CAP_EVENT_CHANNEL_OPENED:
504             if (sdp_client_state != W4_CONNECT) break;
505             // data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16), local_mtu(16), remote_mtu(16)
506             if (packet[2]) {
507                 log_info("SDP Client Connection failed, status 0x%02x.", packet[2]);
508                 sdp_parser_handle_done(packet[2]);
509                 break;
510             }
511             sdp_client_sdp_cid = channel;
512             sdp_client_mtu = little_endian_read_16(packet, 17);
513             // handle = little_endian_read_16(packet, 9);
514             log_debug("SDP Client Connected, cid %x, mtu %u.", sdp_client_sdp_cid, sdp_client_mtu);
515 
516             sdp_client_state = W2_SEND;
517             l2cap_request_can_send_now_event(sdp_client_sdp_cid);
518             break;
519 
520         case L2CAP_EVENT_CAN_SEND_NOW:
521             if(l2cap_event_can_send_now_get_local_cid(packet) == sdp_client_sdp_cid){
522                 sdp_client_send_request(sdp_client_sdp_cid);
523             }
524             break;
525         case L2CAP_EVENT_CHANNEL_CLOSED: {
526             if (sdp_client_sdp_cid != little_endian_read_16(packet, 2)) {
527                 // log_info("Received L2CAP_EVENT_CHANNEL_CLOSED for cid %x, current cid %x\n",  little_endian_read_16(packet, 2),sdp_cid);
528                 break;
529             }
530             log_info("SDP Client disconnected.");
531             uint8_t status = (sdp_client_state == QUERY_COMPLETE) ? 0 : SDP_QUERY_INCOMPLETE;
532             sdp_parser_handle_done(status);
533             break;
534         }
535         default:
536             break;
537     }
538 }
539 
540 
541 static uint16_t sdp_client_setup_service_search_attribute_request(uint8_t * data){
542 
543     uint16_t offset = 0;
544     sdp_client_transaction_id++;
545     // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest;
546     data[offset++] = SDP_ServiceSearchAttributeRequest;
547     // uint16_t transactionID
548     big_endian_store_16(data, offset, sdp_client_transaction_id);
549     offset += 2;
550 
551     // param legnth
552     offset += 2;
553 
554     // parameters:
555     //     Service_search_pattern - DES (min 1 UUID, max 12)
556     uint16_t service_search_pattern_len = de_get_len(sdp_client_service_search_pattern);
557     (void)memcpy(data + offset, sdp_client_service_search_pattern,
558                  service_search_pattern_len);
559     offset += service_search_pattern_len;
560 
561     //     MaximumAttributeByteCount - uint16_t  0x0007 - 0xffff -> mtu
562     big_endian_store_16(data, offset, sdp_client_mtu);
563     offset += 2;
564 
565     //     AttibuteIDList
566     uint16_t attribute_id_list_len = de_get_len(sdp_client_attribute_id_list);
567     (void)memcpy(data + offset, sdp_client_attribute_id_list, attribute_id_list_len);
568     offset += attribute_id_list_len;
569 
570     //     ContinuationState - uint8_t number of cont. bytes N<=16
571     data[offset++] = sdp_client_continuation_state_len;
572     //                       - N-bytes previous response from server
573     (void)memcpy(data + offset, sdp_client_continuation_state, sdp_client_continuation_state_len);
574     offset += sdp_client_continuation_state_len;
575 
576     // uint16_t paramLength
577     big_endian_store_16(data, 3, offset - 5);
578 
579     return offset;
580 }
581 
582 #ifdef ENABLE_SDP_EXTRA_QUERIES
583 void sdp_client_parse_service_record_handle_list(uint8_t* packet, uint16_t total_count, uint16_t current_count){
584     sdp_parser_handle_service_search(packet, total_count, current_count);
585 }
586 
587 static uint16_t sdp_client_setup_service_search_request(uint8_t * data){
588     uint16_t offset = 0;
589     sdp_client_transaction_id++;
590     // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest;
591     data[offset++] = SDP_ServiceSearchRequest;
592     // uint16_t transactionID
593     big_endian_store_16(data, offset, sdp_client_transaction_id);
594     offset += 2;
595 
596     // param legnth
597     offset += 2;
598 
599     // parameters:
600     //     Service_search_pattern - DES (min 1 UUID, max 12)
601     uint16_t service_search_pattern_len = de_get_len(sdp_client_service_search_pattern);
602     (void)memcpy(data + offset, sdp_client_service_search_pattern,
603                  service_search_pattern_len);
604     offset += service_search_pattern_len;
605 
606     //     MaximumAttributeByteCount - uint16_t  0x0007 - 0xffff -> mtu
607     big_endian_store_16(data, offset, sdp_client_mtu);
608     offset += 2;
609 
610     //     ContinuationState - uint8_t number of cont. bytes N<=16
611     data[offset++] = sdp_client_continuation_state_len;
612     //                       - N-bytes previous response from server
613     (void)memcpy(data + offset, sdp_client_continuation_state, sdp_client_continuation_state_len);
614     offset += sdp_client_continuation_state_len;
615 
616     // uint16_t paramLength
617     big_endian_store_16(data, 3, offset - 5);
618 
619     return offset;
620 }
621 
622 
623 static uint16_t sdp_client_setup_service_attribute_request(uint8_t * data){
624 
625     uint16_t offset = 0;
626     sdp_client_transaction_id++;
627     // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest;
628     data[offset++] = SDP_ServiceAttributeRequest;
629     // uint16_t transactionID
630     big_endian_store_16(data, offset, sdp_client_transaction_id);
631     offset += 2;
632 
633     // param legnth
634     offset += 2;
635 
636     // parameters:
637     //     ServiceRecordHandle
638     big_endian_store_32(data, offset, sdp_client_service_record_handle);
639     offset += 4;
640 
641     //     MaximumAttributeByteCount - uint16_t  0x0007 - 0xffff -> mtu
642     big_endian_store_16(data, offset, sdp_client_mtu);
643     offset += 2;
644 
645     //     AttibuteIDList
646     uint16_t attribute_id_list_len = de_get_len(sdp_client_attribute_id_list);
647     (void)memcpy(data + offset, sdp_client_attribute_id_list, attribute_id_list_len);
648     offset += attribute_id_list_len;
649 
650     //     sdp_client_continuation_state - uint8_t number of cont. bytes N<=16
651     data[offset++] = sdp_client_continuation_state_len;
652     //                       - N-bytes previous response from server
653     (void)memcpy(data + offset, sdp_client_continuation_state, sdp_client_continuation_state_len);
654     offset += sdp_client_continuation_state_len;
655 
656     // uint16_t paramLength
657     big_endian_store_16(data, 3, offset - 5);
658 
659     return offset;
660 }
661 
662 static void sdp_client_parse_service_search_response(uint8_t* packet, uint16_t size){
663 
664     uint16_t offset = 3;
665     if (offset + 2 + 2 + 2 > size) return;  // parameterLength, totalServiceRecordCount, currentServiceRecordCount
666 
667     uint16_t parameterLength = big_endian_read_16(packet,offset);
668     offset+=2;
669     if (offset + parameterLength > size) return;
670 
671     uint16_t totalServiceRecordCount = big_endian_read_16(packet,offset);
672     offset+=2;
673 
674     uint16_t currentServiceRecordCount = big_endian_read_16(packet,offset);
675     offset+=2;
676     if (currentServiceRecordCount > totalServiceRecordCount){
677         log_error("CurrentServiceRecordCount is larger then TotalServiceRecordCount.");
678         return;
679     }
680 
681     if (offset + currentServiceRecordCount * 4 > size) return;
682     sdp_client_parse_service_record_handle_list(packet+offset, totalServiceRecordCount, currentServiceRecordCount);
683     offset+= currentServiceRecordCount * 4;
684 
685     if (offset + 1 > size) return;
686     sdp_client_continuation_state_len = packet[offset];
687     offset++;
688     if (sdp_client_continuation_state_len > 16){
689         sdp_client_continuation_state_len = 0;
690         log_error("Error parsing ServiceSearchResponse: Number of bytes in continuation state exceedes 16.");
691         return;
692     }
693     if (offset + sdp_client_continuation_state_len > size) return;
694     (void)memcpy(sdp_client_continuation_state, packet + offset, sdp_client_continuation_state_len);
695     // offset+=sdp_client_continuation_state_len;
696 }
697 
698 static void sdp_client_parse_service_attribute_response(uint8_t* packet, uint16_t size){
699 
700     uint16_t offset = 3;
701     if (offset + 2 + 2 > size) return;  // parameterLength, attributeListByteCount
702     uint16_t parameterLength = big_endian_read_16(packet,offset);
703     offset+=2;
704     if (offset+parameterLength > size) return;
705 
706     // AttributeListByteCount <= mtu
707     uint16_t attributeListByteCount = big_endian_read_16(packet,offset);
708     offset+=2;
709     if (attributeListByteCount > sdp_client_mtu){
710         log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in found attribute list is larger then the MaximumAttributeByteCount.");
711         return;
712     }
713 
714     // AttributeLists
715     if (offset+attributeListByteCount > size) return;
716     sdp_client_parse_attribute_lists(packet+offset, attributeListByteCount);
717     offset+=attributeListByteCount;
718 
719     // sdp_client_continuation_state_len
720     if (offset + 1 > size) return;
721     sdp_client_continuation_state_len = packet[offset];
722     offset++;
723     if (sdp_client_continuation_state_len > 16){
724         sdp_client_continuation_state_len = 0;
725         log_error("Error parsing ServiceAttributeResponse: Number of bytes in continuation state exceedes 16.");
726         return;
727     }
728     if (offset + sdp_client_continuation_state_len > size) return;
729     (void)memcpy(sdp_client_continuation_state, packet + offset, sdp_client_continuation_state_len);
730     // offset+=sdp_client_continuation_state_len;
731 }
732 #endif
733 
734 // Public API
735 
736 bool sdp_client_ready(void){
737     return sdp_client_state == INIT;
738 }
739 
740 uint8_t sdp_client_register_query_callback(btstack_context_callback_registration_t * callback_registration){
741     bool added = btstack_linked_list_add_tail(&sdp_client_query_requests, (btstack_linked_item_t*) callback_registration);
742     if (!added) return ERROR_CODE_COMMAND_DISALLOWED;
743     sdp_client_notify_callbacks();
744     return ERROR_CODE_SUCCESS;
745 }
746 
747 uint8_t sdp_client_query(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t * des_service_search_pattern, const uint8_t * des_attribute_id_list){
748     if (!sdp_client_ready()) return SDP_QUERY_BUSY;
749 
750     sdp_parser_init(callback);
751     sdp_client_service_search_pattern = des_service_search_pattern;
752     sdp_client_attribute_id_list = des_attribute_id_list;
753     sdp_client_continuation_state_len = 0;
754     sdp_client_pdu_id = SDP_ServiceSearchAttributeResponse;
755 
756     sdp_client_state = W4_CONNECT;
757     return l2cap_create_channel(sdp_client_packet_handler, remote, BLUETOOTH_PSM_SDP, l2cap_max_mtu(), NULL);
758 }
759 
760 uint8_t sdp_client_query_uuid16(btstack_packet_handler_t callback, bd_addr_t remote, uint16_t uuid){
761     if (!sdp_client_ready()) return SDP_QUERY_BUSY;
762     return sdp_client_query(callback, remote, sdp_service_search_pattern_for_uuid16(uuid), sdp_client_des_attribute_id_list);
763 }
764 
765 uint8_t sdp_client_query_uuid128(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t* uuid){
766     if (!sdp_client_ready()) return SDP_QUERY_BUSY;
767     return sdp_client_query(callback, remote, sdp_service_search_pattern_for_uuid128(uuid), sdp_client_des_attribute_id_list);
768 }
769 
770 #ifdef ENABLE_SDP_EXTRA_QUERIES
771 uint8_t sdp_client_service_attribute_search(btstack_packet_handler_t callback, bd_addr_t remote, uint32_t search_service_record_handle, const uint8_t * des_attribute_id_list){
772     if (!sdp_client_ready()) return SDP_QUERY_BUSY;
773 
774     sdp_parser_init(callback);
775     sdp_client_service_record_handle = search_service_record_handle;
776     sdp_client_attribute_id_list = des_attribute_id_list;
777     sdp_client_continuation_state_len = 0;
778     sdp_client_pdu_id = SDP_ServiceAttributeResponse;
779 
780     sdp_client_state = W4_CONNECT;
781     l2cap_create_channel(sdp_client_packet_handler, remote, BLUETOOTH_PSM_SDP, l2cap_max_mtu(), NULL);
782     return 0;
783 }
784 
785 uint8_t sdp_client_service_search(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t * des_service_search_pattern){
786 
787     if (!sdp_client_ready()) return SDP_QUERY_BUSY;
788 
789     sdp_parser_init(callback);
790     sdp_client_service_search_pattern = des_service_search_pattern;
791     sdp_client_continuation_state_len = 0;
792     sdp_client_pdu_id = SDP_ServiceSearchResponse;
793 
794     sdp_client_state = W4_CONNECT;
795     l2cap_create_channel(sdp_client_packet_handler, remote, BLUETOOTH_PSM_SDP, l2cap_max_mtu(), NULL);
796     return 0;
797 }
798 #endif
799 
800