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