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