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