xref: /btstack/src/classic/sdp_client.c (revision b28dc8004dd8d4fb9020a6dcd2bc81f05d36a008)
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_state->de_size = de_get_data_size(&eventByte);
143             if (de_state->de_size == 0) {
144                 log_error("  ERROR: ID size is zero");
145             }
146             // log_info("Data element payload is %d bytes.", de_state->de_size);
147             return 1;
148         }
149         de_state->in_state_GET_DE_HEADER_LENGTH = 0;
150         return 0;
151     }
152 
153     if (de_state->addon_header_bytes > 0){
154         de_state->de_size = (de_state->de_size << 8) | eventByte;
155         de_state->addon_header_bytes--;
156     }
157     if (de_state->addon_header_bytes > 0) return 0;
158     // log_info("Data element payload is %d bytes.", de_state->de_size);
159     de_state->in_state_GET_DE_HEADER_LENGTH = 1;
160     return 1;
161 }
162 
163 // SDP Parser
164 static void sdp_parser_emit_value_byte(uint8_t event_byte){
165     uint8_t event[11];
166     event[0] = SDP_EVENT_QUERY_ATTRIBUTE_VALUE;
167     event[1] = 9;
168     little_endian_store_16(event, 2, sdp_parser_record_counter);
169     little_endian_store_16(event, 4, sdp_parser_attribute_id);
170     little_endian_store_16(event, 6, sdp_parser_attribute_value_size);
171     little_endian_store_16(event, 8, sdp_parser_attribute_bytes_delivered);
172     event[10] = event_byte;
173     (*sdp_parser_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
174 }
175 
176 static void sdp_parser_process_byte(uint8_t eventByte){
177     // count all bytes
178     sdp_parser_list_offset++;
179     sdp_parser_record_offset++;
180 
181     // log_info(" parse BYTE_RECEIVED %02x", eventByte);
182     switch(sdp_parser_state){
183         case GET_LIST_LENGTH:
184             if (!de_state_size(eventByte, &des_parser_de_header_state)) break;
185             sdp_parser_list_offset = des_parser_de_header_state.de_offset;
186             sdp_parser_list_size = des_parser_de_header_state.de_size;
187             // log_info("parser: List offset %u, list size %u", list_offset, list_size);
188 
189             sdp_parser_record_counter = 0;
190             sdp_parser_state = GET_RECORD_LENGTH;
191             break;
192 
193         case GET_RECORD_LENGTH:
194             // check size
195             if (!de_state_size(eventByte, &des_parser_de_header_state)) break;
196             // log_info("parser: Record payload is %d bytes.", de_header_state.de_size);
197             sdp_parser_record_offset = des_parser_de_header_state.de_offset;
198             sdp_parser_record_size = des_parser_de_header_state.de_size;
199             sdp_parser_state = GET_ATTRIBUTE_ID_HEADER_LENGTH;
200             break;
201 
202         case GET_ATTRIBUTE_ID_HEADER_LENGTH:
203             if (!de_state_size(eventByte, &des_parser_de_header_state)) break;
204             sdp_parser_attribute_id = 0;
205             log_debug("ID data is stored in %d bytes.", (int) des_parser_de_header_state.de_size);
206             sdp_parser_state = GET_ATTRIBUTE_ID;
207             break;
208 
209         case GET_ATTRIBUTE_ID:
210             sdp_parser_attribute_id = (sdp_parser_attribute_id << 8) | eventByte;
211             des_parser_de_header_state.de_size--;
212             if (des_parser_de_header_state.de_size > 0) break;
213             log_debug("parser: Attribute ID: %04x.", sdp_parser_attribute_id);
214 
215             sdp_parser_state = GET_ATTRIBUTE_VALUE_LENGTH;
216             sdp_parser_attribute_bytes_received  = 0;
217             sdp_parser_attribute_bytes_delivered = 0;
218             sdp_parser_attribute_value_size      = 0;
219             de_state_init(&des_parser_de_header_state);
220             break;
221 
222         case GET_ATTRIBUTE_VALUE_LENGTH:
223             sdp_parser_attribute_bytes_received++;
224             sdp_parser_emit_value_byte(eventByte);
225             sdp_parser_attribute_bytes_delivered++;
226             if (!de_state_size(eventByte, &des_parser_de_header_state)) break;
227 
228             sdp_parser_attribute_value_size = des_parser_de_header_state.de_size + sdp_parser_attribute_bytes_received;
229 
230             sdp_parser_state = GET_ATTRIBUTE_VALUE;
231             break;
232 
233         case GET_ATTRIBUTE_VALUE:
234             sdp_parser_attribute_bytes_received++;
235             sdp_parser_emit_value_byte(eventByte);
236             sdp_parser_attribute_bytes_delivered++;
237             // log_debug("paser: attribute_bytes_received %u, attribute_value_size %u", attribute_bytes_received, attribute_value_size);
238 
239             if (sdp_parser_attribute_bytes_received < sdp_parser_attribute_value_size) break;
240             // log_debug("parser: Record offset %u, record size %u", record_offset, record_size);
241             if (sdp_parser_record_offset != sdp_parser_record_size){
242                 sdp_parser_state = GET_ATTRIBUTE_ID_HEADER_LENGTH;
243                 // log_debug("Get next attribute");
244                 break;
245             }
246             sdp_parser_record_offset = 0;
247             // log_debug("parser: List offset %u, list size %u", list_offset, list_size);
248 
249             if ((sdp_parser_list_size > 0) && (sdp_parser_list_offset != sdp_parser_list_size)){
250                 sdp_parser_record_counter++;
251                 sdp_parser_state = GET_RECORD_LENGTH;
252                 log_debug("parser: END_OF_RECORD");
253                 break;
254             }
255             sdp_parser_list_offset = 0;
256             de_state_init(&des_parser_de_header_state);
257             sdp_parser_state = GET_LIST_LENGTH;
258             sdp_parser_record_counter = 0;
259             log_debug("parser: END_OF_RECORD & DONE");
260             break;
261         default:
262             break;
263     }
264 }
265 
266 void sdp_parser_init(btstack_packet_handler_t callback){
267     // init
268     sdp_parser_callback = callback;
269     de_state_init(&des_parser_de_header_state);
270     sdp_parser_state = GET_LIST_LENGTH;
271     sdp_parser_list_offset = 0;
272     sdp_parser_list_size = 0;
273     sdp_parser_record_offset = 0;
274     sdp_parser_record_counter = 0;
275     sdp_parser_record_size = 0;
276     sdp_parser_attribute_id = 0;
277     sdp_parser_attribute_bytes_received = 0;
278     sdp_parser_attribute_bytes_delivered = 0;
279 }
280 
281 static void sdp_parser_deinit(void) {
282     sdp_parser_callback = NULL;
283     sdp_parser_attribute_value_size = 0;
284     sdp_parser_record_counter = 0;
285 }
286 
287 void sdp_client_init(void){
288 }
289 
290 void sdp_client_deinit(void){
291     sdp_parser_deinit();
292     sdp_client_state = INIT;
293     sdp_client_sdp_cid = 0x40;
294     sdp_client_service_search_pattern = NULL;
295     sdp_client_attribute_id_list = NULL;
296     sdp_client_transaction_id = 0;
297     sdp_client_continuation_state_len = 0;
298     sdp_client_state = INIT;
299     sdp_client_pdu_id = SDP_Invalid;
300 #ifdef ENABLE_SDP_EXTRA_QUERIES
301     sdp_client_service_record_handle = 0;
302     sdp_client_record_handle = 0;
303 #endif
304 }
305 
306 // for testing only
307 void sdp_client_reset(void){
308     sdp_client_deinit();
309 }
310 
311 void sdp_parser_handle_chunk(uint8_t * data, uint16_t size){
312     int i;
313     for (i=0;i<size;i++){
314         sdp_parser_process_byte(data[i]);
315     }
316 }
317 
318 #ifdef ENABLE_SDP_EXTRA_QUERIES
319 void sdp_parser_init_service_attribute_search(void){
320     // init
321     de_state_init(&des_parser_de_header_state);
322     sdp_parser_state = GET_RECORD_LENGTH;
323     sdp_parser_list_offset = 0;
324     sdp_parser_record_offset = 0;
325     sdp_parser_record_counter = 0;
326 }
327 
328 void sdp_parser_init_service_search(void){
329     sdp_parser_record_offset = 0;
330 }
331 
332 void sdp_parser_handle_service_search(uint8_t * data, uint16_t total_count, uint16_t record_handle_count){
333     int i;
334     for (i=0;i<record_handle_count;i++){
335         sdp_client_record_handle = big_endian_read_32(data, i * 4);
336         sdp_parser_record_counter++;
337         uint8_t event[10];
338         event[0] = SDP_EVENT_QUERY_SERVICE_RECORD_HANDLE;
339         event[1] = 8;
340         little_endian_store_16(event, 2, total_count);
341         little_endian_store_16(event, 4, sdp_parser_record_counter);
342         little_endian_store_32(event, 6, sdp_client_record_handle);
343         (*sdp_parser_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
344     }
345 }
346 #endif
347 
348 static void sdp_client_notify_callbacks(void){
349     if (sdp_client_ready() == false) {
350         return;
351     }
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         return;
355     }
356     (*callback->callback)(callback->context);
357 }
358 
359 void sdp_parser_handle_done(uint8_t status){
360     // reset state
361     sdp_client_state = INIT;
362 
363     // emit query complete event
364     uint8_t event[3];
365     event[0] = SDP_EVENT_QUERY_COMPLETE;
366     event[1] = 1;
367     event[2] = status;
368     (*sdp_parser_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
369 
370     // trigger next query if pending
371     sdp_client_notify_callbacks();
372 }
373 
374 // SDP Client
375 
376 // TODO: inline if not needed (des(des))
377 
378 static void sdp_client_parse_attribute_lists(uint8_t* packet, uint16_t length){
379     sdp_parser_handle_chunk(packet, length);
380 }
381 
382 
383 static void sdp_client_send_request(uint16_t channel){
384 
385     if (sdp_client_state != W2_SEND) return;
386 
387     l2cap_reserve_packet_buffer();
388     uint8_t * data = l2cap_get_outgoing_buffer();
389     uint16_t request_len = 0;
390 
391     switch (sdp_client_pdu_id){
392 #ifdef ENABLE_SDP_EXTRA_QUERIES
393         case SDP_ServiceSearchResponse:
394             request_len = sdp_client_setup_service_search_request(data);
395             break;
396         case SDP_ServiceAttributeResponse:
397             request_len = sdp_client_setup_service_attribute_request(data);
398             break;
399 #endif
400         case SDP_ServiceSearchAttributeResponse:
401             request_len = sdp_client_setup_service_search_attribute_request(data);
402             break;
403         default:
404             log_error("SDP Client sdp_client_send_request :: PDU ID invalid. %u", sdp_client_pdu_id);
405             return;
406     }
407 
408     // prevent re-entrance
409     sdp_client_state = W4_RESPONSE;
410     sdp_client_pdu_id = SDP_Invalid;
411     l2cap_send_prepared(channel, request_len);
412 }
413 
414 
415 static void sdp_client_parse_service_search_attribute_response(uint8_t* packet, uint16_t size){
416 
417     uint16_t offset = 3;
418     if ((offset + 2 + 2) > size) return;  // parameterLength + attributeListByteCount
419     uint16_t parameterLength = big_endian_read_16(packet,offset);
420     offset+=2;
421     if ((offset + parameterLength) > size) return;
422 
423     // AttributeListByteCount <= mtu
424     uint16_t attributeListByteCount = big_endian_read_16(packet,offset);
425     offset+=2;
426     if (attributeListByteCount > sdp_client_mtu){
427         log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in found attribute list is larger then the MaximumAttributeByteCount.");
428         return;
429     }
430 
431     // AttributeLists
432     if ((offset + attributeListByteCount) > size) return;
433     sdp_client_parse_attribute_lists(packet+offset, attributeListByteCount);
434     offset+=attributeListByteCount;
435 
436     // continuation state len
437     if ((offset + 1) > size) return;
438     sdp_client_continuation_state_len = packet[offset];
439     offset++;
440     if (sdp_client_continuation_state_len > 16){
441         sdp_client_continuation_state_len = 0;
442         log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in continuation state exceedes 16.");
443         return;
444     }
445 
446     // continuation state
447     if ((offset + sdp_client_continuation_state_len) > size) return;
448     (void)memcpy(sdp_client_continuation_state, packet + offset, sdp_client_continuation_state_len);
449     // offset+=continuationStateLen;
450 }
451 
452 void sdp_client_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
453 
454     // uint16_t handle;
455     if (packet_type == L2CAP_DATA_PACKET){
456         if (size < 3) return;
457         uint16_t responseTransactionID = big_endian_read_16(packet,1);
458         if (responseTransactionID != sdp_client_transaction_id){
459             log_error("Mismatching transaction ID, expected %u, found %u.", sdp_client_transaction_id, responseTransactionID);
460             return;
461         }
462 
463         sdp_client_pdu_id = (sdp_pdu_id_t)packet[0];
464         switch (sdp_client_pdu_id){
465             case SDP_ErrorResponse:
466                 log_error("Received error response with code %u, disconnecting", packet[2]);
467                 l2cap_disconnect(sdp_client_sdp_cid, 0);
468                 return;
469 #ifdef ENABLE_SDP_EXTRA_QUERIES
470             case SDP_ServiceSearchResponse:
471                 sdp_client_parse_service_search_response(packet, size);
472                 break;
473             case SDP_ServiceAttributeResponse:
474                 sdp_client_parse_service_attribute_response(packet, size);
475                 break;
476 #endif
477             case SDP_ServiceSearchAttributeResponse:
478                 sdp_client_parse_service_search_attribute_response(packet, size);
479                 break;
480             default:
481                 log_error("PDU ID %u unexpected/invalid", sdp_client_pdu_id);
482                 return;
483         }
484 
485         // continuation set or DONE?
486         if (sdp_client_continuation_state_len == 0){
487             log_debug("SDP Client Query DONE! ");
488             sdp_client_state = QUERY_COMPLETE;
489             l2cap_disconnect(sdp_client_sdp_cid, 0);
490             return;
491         }
492         // prepare next request and send
493         sdp_client_state = W2_SEND;
494         l2cap_request_can_send_now_event(sdp_client_sdp_cid);
495         return;
496     }
497 
498     if (packet_type != HCI_EVENT_PACKET) return;
499 
500     switch(hci_event_packet_get_type(packet)){
501         case L2CAP_EVENT_CHANNEL_OPENED:
502             if (sdp_client_state != W4_CONNECT) break;
503             // 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)
504             if (packet[2]) {
505                 log_info("SDP Client Connection failed, status 0x%02x.", packet[2]);
506                 sdp_parser_handle_done(packet[2]);
507                 break;
508             }
509             sdp_client_sdp_cid = channel;
510             sdp_client_mtu = little_endian_read_16(packet, 17);
511             // handle = little_endian_read_16(packet, 9);
512             log_debug("SDP Client Connected, cid %x, mtu %u.", sdp_client_sdp_cid, sdp_client_mtu);
513 
514             sdp_client_state = W2_SEND;
515             l2cap_request_can_send_now_event(sdp_client_sdp_cid);
516             break;
517 
518         case L2CAP_EVENT_CAN_SEND_NOW:
519             if(l2cap_event_can_send_now_get_local_cid(packet) == sdp_client_sdp_cid){
520                 sdp_client_send_request(sdp_client_sdp_cid);
521             }
522             break;
523         case L2CAP_EVENT_CHANNEL_CLOSED: {
524             if (sdp_client_sdp_cid != little_endian_read_16(packet, 2)) {
525                 // log_info("Received L2CAP_EVENT_CHANNEL_CLOSED for cid %x, current cid %x\n",  little_endian_read_16(packet, 2),sdp_cid);
526                 break;
527             }
528             log_info("SDP Client disconnected.");
529             uint8_t status = (sdp_client_state == QUERY_COMPLETE) ? 0 : SDP_QUERY_INCOMPLETE;
530             sdp_parser_handle_done(status);
531             break;
532         }
533         default:
534             break;
535     }
536 }
537 
538 
539 static uint16_t sdp_client_setup_service_search_attribute_request(uint8_t * data){
540 
541     uint16_t offset = 0;
542     sdp_client_transaction_id++;
543     // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest;
544     data[offset++] = SDP_ServiceSearchAttributeRequest;
545     // uint16_t transactionID
546     big_endian_store_16(data, offset, sdp_client_transaction_id);
547     offset += 2;
548 
549     // param legnth
550     offset += 2;
551 
552     // parameters:
553     //     Service_search_pattern - DES (min 1 UUID, max 12)
554     uint16_t service_search_pattern_len = de_get_len(sdp_client_service_search_pattern);
555     (void)memcpy(data + offset, sdp_client_service_search_pattern,
556                  service_search_pattern_len);
557     offset += service_search_pattern_len;
558 
559     //     MaximumAttributeByteCount - uint16_t  0x0007 - 0xffff -> mtu
560     big_endian_store_16(data, offset, sdp_client_mtu);
561     offset += 2;
562 
563     //     AttibuteIDList
564     uint16_t attribute_id_list_len = de_get_len(sdp_client_attribute_id_list);
565     (void)memcpy(data + offset, sdp_client_attribute_id_list, attribute_id_list_len);
566     offset += attribute_id_list_len;
567 
568     //     ContinuationState - uint8_t number of cont. bytes N<=16
569     data[offset++] = sdp_client_continuation_state_len;
570     //                       - N-bytes previous response from server
571     (void)memcpy(data + offset, sdp_client_continuation_state, sdp_client_continuation_state_len);
572     offset += sdp_client_continuation_state_len;
573 
574     // uint16_t paramLength
575     big_endian_store_16(data, 3, offset - 5);
576 
577     return offset;
578 }
579 
580 #ifdef ENABLE_SDP_EXTRA_QUERIES
581 void sdp_client_parse_service_record_handle_list(uint8_t* packet, uint16_t total_count, uint16_t current_count){
582     sdp_parser_handle_service_search(packet, total_count, current_count);
583 }
584 
585 static uint16_t sdp_client_setup_service_search_request(uint8_t * data){
586     uint16_t offset = 0;
587     sdp_client_transaction_id++;
588     // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest;
589     data[offset++] = SDP_ServiceSearchRequest;
590     // uint16_t transactionID
591     big_endian_store_16(data, offset, sdp_client_transaction_id);
592     offset += 2;
593 
594     // param legnth
595     offset += 2;
596 
597     // parameters:
598     //     Service_search_pattern - DES (min 1 UUID, max 12)
599     uint16_t service_search_pattern_len = de_get_len(sdp_client_service_search_pattern);
600     (void)memcpy(data + offset, sdp_client_service_search_pattern,
601                  service_search_pattern_len);
602     offset += service_search_pattern_len;
603 
604     //     MaximumAttributeByteCount - uint16_t  0x0007 - 0xffff -> mtu
605     big_endian_store_16(data, offset, sdp_client_mtu);
606     offset += 2;
607 
608     //     ContinuationState - uint8_t number of cont. bytes N<=16
609     data[offset++] = sdp_client_continuation_state_len;
610     //                       - N-bytes previous response from server
611     (void)memcpy(data + offset, sdp_client_continuation_state, sdp_client_continuation_state_len);
612     offset += sdp_client_continuation_state_len;
613 
614     // uint16_t paramLength
615     big_endian_store_16(data, 3, offset - 5);
616 
617     return offset;
618 }
619 
620 
621 static uint16_t sdp_client_setup_service_attribute_request(uint8_t * data){
622 
623     uint16_t offset = 0;
624     sdp_client_transaction_id++;
625     // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest;
626     data[offset++] = SDP_ServiceAttributeRequest;
627     // uint16_t transactionID
628     big_endian_store_16(data, offset, sdp_client_transaction_id);
629     offset += 2;
630 
631     // param legnth
632     offset += 2;
633 
634     // parameters:
635     //     ServiceRecordHandle
636     big_endian_store_32(data, offset, sdp_client_service_record_handle);
637     offset += 4;
638 
639     //     MaximumAttributeByteCount - uint16_t  0x0007 - 0xffff -> mtu
640     big_endian_store_16(data, offset, sdp_client_mtu);
641     offset += 2;
642 
643     //     AttibuteIDList
644     uint16_t attribute_id_list_len = de_get_len(sdp_client_attribute_id_list);
645     (void)memcpy(data + offset, sdp_client_attribute_id_list, attribute_id_list_len);
646     offset += attribute_id_list_len;
647 
648     //     sdp_client_continuation_state - uint8_t number of cont. bytes N<=16
649     data[offset++] = sdp_client_continuation_state_len;
650     //                       - N-bytes previous response from server
651     (void)memcpy(data + offset, sdp_client_continuation_state, sdp_client_continuation_state_len);
652     offset += sdp_client_continuation_state_len;
653 
654     // uint16_t paramLength
655     big_endian_store_16(data, 3, offset - 5);
656 
657     return offset;
658 }
659 
660 static void sdp_client_parse_service_search_response(uint8_t* packet, uint16_t size){
661 
662     uint16_t offset = 3;
663     if (offset + 2 + 2 + 2 > size) return;  // parameterLength, totalServiceRecordCount, currentServiceRecordCount
664 
665     uint16_t parameterLength = big_endian_read_16(packet,offset);
666     offset+=2;
667     if (offset + parameterLength > size) return;
668 
669     uint16_t totalServiceRecordCount = big_endian_read_16(packet,offset);
670     offset+=2;
671 
672     uint16_t currentServiceRecordCount = big_endian_read_16(packet,offset);
673     offset+=2;
674     if (currentServiceRecordCount > totalServiceRecordCount){
675         log_error("CurrentServiceRecordCount is larger then TotalServiceRecordCount.");
676         return;
677     }
678 
679     if (offset + currentServiceRecordCount * 4 > size) return;
680     sdp_client_parse_service_record_handle_list(packet+offset, totalServiceRecordCount, currentServiceRecordCount);
681     offset+= currentServiceRecordCount * 4;
682 
683     if (offset + 1 > size) return;
684     sdp_client_continuation_state_len = packet[offset];
685     offset++;
686     if (sdp_client_continuation_state_len > 16){
687         sdp_client_continuation_state_len = 0;
688         log_error("Error parsing ServiceSearchResponse: Number of bytes in continuation state exceedes 16.");
689         return;
690     }
691     if (offset + sdp_client_continuation_state_len > size) return;
692     (void)memcpy(sdp_client_continuation_state, packet + offset, sdp_client_continuation_state_len);
693     // offset+=sdp_client_continuation_state_len;
694 }
695 
696 static void sdp_client_parse_service_attribute_response(uint8_t* packet, uint16_t size){
697 
698     uint16_t offset = 3;
699     if (offset + 2 + 2 > size) return;  // parameterLength, attributeListByteCount
700     uint16_t parameterLength = big_endian_read_16(packet,offset);
701     offset+=2;
702     if (offset+parameterLength > size) return;
703 
704     // AttributeListByteCount <= mtu
705     uint16_t attributeListByteCount = big_endian_read_16(packet,offset);
706     offset+=2;
707     if (attributeListByteCount > sdp_client_mtu){
708         log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in found attribute list is larger then the MaximumAttributeByteCount.");
709         return;
710     }
711 
712     // AttributeLists
713     if (offset+attributeListByteCount > size) return;
714     sdp_client_parse_attribute_lists(packet+offset, attributeListByteCount);
715     offset+=attributeListByteCount;
716 
717     // sdp_client_continuation_state_len
718     if (offset + 1 > size) return;
719     sdp_client_continuation_state_len = packet[offset];
720     offset++;
721     if (sdp_client_continuation_state_len > 16){
722         sdp_client_continuation_state_len = 0;
723         log_error("Error parsing ServiceAttributeResponse: Number of bytes in continuation state exceedes 16.");
724         return;
725     }
726     if (offset + sdp_client_continuation_state_len > size) return;
727     (void)memcpy(sdp_client_continuation_state, packet + offset, sdp_client_continuation_state_len);
728     // offset+=sdp_client_continuation_state_len;
729 }
730 #endif
731 
732 // Public API
733 
734 bool sdp_client_ready(void){
735     return sdp_client_state == INIT;
736 }
737 
738 uint8_t sdp_client_register_query_callback(btstack_context_callback_registration_t * callback_registration){
739     bool added = btstack_linked_list_add_tail(&sdp_client_query_requests, (btstack_linked_item_t*) callback_registration);
740     if (!added) return ERROR_CODE_COMMAND_DISALLOWED;
741     sdp_client_notify_callbacks();
742     return ERROR_CODE_SUCCESS;
743 }
744 
745 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){
746     if (!sdp_client_ready()) return SDP_QUERY_BUSY;
747 
748     sdp_parser_init(callback);
749     sdp_client_service_search_pattern = des_service_search_pattern;
750     sdp_client_attribute_id_list = des_attribute_id_list;
751     sdp_client_continuation_state_len = 0;
752     sdp_client_pdu_id = SDP_ServiceSearchAttributeResponse;
753 
754     sdp_client_state = W4_CONNECT;
755     return l2cap_create_channel(sdp_client_packet_handler, remote, BLUETOOTH_PSM_SDP, l2cap_max_mtu(), NULL);
756 }
757 
758 uint8_t sdp_client_query_uuid16(btstack_packet_handler_t callback, bd_addr_t remote, uint16_t uuid){
759     if (!sdp_client_ready()) return SDP_QUERY_BUSY;
760     return sdp_client_query(callback, remote, sdp_service_search_pattern_for_uuid16(uuid), sdp_client_des_attribute_id_list);
761 }
762 
763 uint8_t sdp_client_query_uuid128(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t* uuid){
764     if (!sdp_client_ready()) return SDP_QUERY_BUSY;
765     return sdp_client_query(callback, remote, sdp_service_search_pattern_for_uuid128(uuid), sdp_client_des_attribute_id_list);
766 }
767 
768 #ifdef ENABLE_SDP_EXTRA_QUERIES
769 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){
770     if (!sdp_client_ready()) return SDP_QUERY_BUSY;
771 
772     sdp_parser_init(callback);
773     sdp_client_service_record_handle = search_service_record_handle;
774     sdp_client_attribute_id_list = des_attribute_id_list;
775     sdp_client_continuation_state_len = 0;
776     sdp_client_pdu_id = SDP_ServiceAttributeResponse;
777 
778     sdp_client_state = W4_CONNECT;
779     l2cap_create_channel(sdp_client_packet_handler, remote, BLUETOOTH_PSM_SDP, l2cap_max_mtu(), NULL);
780     return 0;
781 }
782 
783 uint8_t sdp_client_service_search(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t * des_service_search_pattern){
784 
785     if (!sdp_client_ready()) return SDP_QUERY_BUSY;
786 
787     sdp_parser_init(callback);
788     sdp_client_service_search_pattern = des_service_search_pattern;
789     sdp_client_continuation_state_len = 0;
790     sdp_client_pdu_id = SDP_ServiceSearchResponse;
791 
792     sdp_client_state = W4_CONNECT;
793     l2cap_create_channel(sdp_client_packet_handler, remote, BLUETOOTH_PSM_SDP, l2cap_max_mtu(), NULL);
794     return 0;
795 }
796 #endif
797 
798