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