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