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