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