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