1 /* 2 * Copyright (C) 2014 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define BTSTACK_FILE__ "sdp_client.c" 39 40 /* 41 * sdp_client.c 42 */ 43 #include "btstack_config.h" 44 45 #include "bluetooth_psm.h" 46 #include "bluetooth_sdp.h" 47 #include "btstack_debug.h" 48 #include "btstack_event.h" 49 #include "classic/core.h" 50 #include "classic/sdp_client.h" 51 #include "classic/sdp_server.h" 52 #include "classic/sdp_util.h" 53 #include "hci_cmd.h" 54 #include "l2cap.h" 55 56 // Types SDP Parser - Data Element stream helper 57 typedef enum { 58 GET_LIST_LENGTH = 1, 59 GET_RECORD_LENGTH, 60 GET_ATTRIBUTE_ID_HEADER_LENGTH, 61 GET_ATTRIBUTE_ID, 62 GET_ATTRIBUTE_VALUE_LENGTH, 63 GET_ATTRIBUTE_VALUE 64 } sdp_parser_state_t; 65 66 // Types SDP Client 67 typedef enum { 68 INIT, W4_CONNECT, W2_SEND, W4_RESPONSE, QUERY_COMPLETE 69 } sdp_client_state_t; 70 71 72 // Prototypes SDP Parser 73 void sdp_parser_init(btstack_packet_handler_t callback); 74 void sdp_parser_handle_chunk(uint8_t * data, uint16_t size); 75 void sdp_parser_handle_done(uint8_t status); 76 void sdp_parser_init_service_attribute_search(void); 77 void sdp_parser_init_service_search(void); 78 void sdp_parser_handle_service_search(uint8_t * data, uint16_t total_count, uint16_t record_handle_count); 79 80 // Prototypes SDP Client 81 void sdp_client_reset(void); 82 void sdp_client_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 83 static uint16_t sdp_client_setup_service_search_attribute_request(uint8_t * data); 84 #ifdef ENABLE_SDP_EXTRA_QUERIES 85 static uint16_t sdp_client_setup_service_search_request(uint8_t * data); 86 static uint16_t sdp_client_setup_service_attribute_request(uint8_t * data); 87 static void sdp_client_parse_service_search_response(uint8_t* packet, uint16_t size); 88 static void sdp_client_parse_service_attribute_response(uint8_t* packet, uint16_t size); 89 #endif 90 91 static uint8_t des_attributeIDList[] = { 0x35, 0x05, 0x0A, 0x00, 0x00, 0xff, 0xff}; // Attribute: 0x0000 - 0xffff 92 93 // State DES Parser 94 static de_state_t de_header_state; 95 96 // State SDP Parser 97 static sdp_parser_state_t state; 98 static uint16_t attribute_id = 0; 99 static uint16_t attribute_bytes_received; 100 static uint16_t attribute_bytes_delivered; 101 static uint16_t list_offset; 102 static uint16_t list_size; 103 static uint16_t record_offset; 104 static uint16_t record_size; 105 static uint16_t attribute_value_size; 106 static int record_counter; 107 static btstack_packet_handler_t sdp_parser_callback; 108 109 // State SDP Client 110 static uint16_t mtu; 111 static uint16_t sdp_cid = 0x40; 112 static const uint8_t * service_search_pattern; 113 static const uint8_t * attribute_id_list; 114 static uint16_t transactionID; 115 static uint8_t continuationState[16]; 116 static uint8_t continuationStateLen; 117 static sdp_client_state_t sdp_client_state = INIT; 118 static SDP_PDU_ID_t PDU_ID = SDP_Invalid; 119 120 // Query registration 121 static btstack_linked_list_t sdp_client_query_requests; 122 123 #ifdef ENABLE_SDP_EXTRA_QUERIES 124 static uint32_t serviceRecordHandle; 125 static uint32_t record_handle; 126 #endif 127 128 // DES Parser 129 void de_state_init(de_state_t * de_state){ 130 de_state->in_state_GET_DE_HEADER_LENGTH = 1; 131 de_state->addon_header_bytes = 0; 132 de_state->de_size = 0; 133 de_state->de_offset = 0; 134 } 135 136 int de_state_size(uint8_t eventByte, de_state_t *de_state){ 137 if (de_state->in_state_GET_DE_HEADER_LENGTH){ 138 de_state->addon_header_bytes = de_get_header_size(&eventByte) - 1; 139 de_state->de_size = 0; 140 de_state->de_offset = 0; 141 142 if (de_state->addon_header_bytes == 0){ 143 de_state->de_size = de_get_data_size(&eventByte); 144 if (de_state->de_size == 0) { 145 log_error(" ERROR: ID size is zero"); 146 } 147 // log_info("Data element payload is %d bytes.", de_state->de_size); 148 return 1; 149 } 150 de_state->in_state_GET_DE_HEADER_LENGTH = 0; 151 return 0; 152 } 153 154 if (de_state->addon_header_bytes > 0){ 155 de_state->de_size = (de_state->de_size << 8) | eventByte; 156 de_state->addon_header_bytes--; 157 } 158 if (de_state->addon_header_bytes > 0) return 0; 159 // log_info("Data element payload is %d bytes.", de_state->de_size); 160 de_state->in_state_GET_DE_HEADER_LENGTH = 1; 161 return 1; 162 } 163 164 // SDP Parser 165 static void sdp_parser_emit_value_byte(uint8_t event_byte){ 166 uint8_t event[11]; 167 event[0] = SDP_EVENT_QUERY_ATTRIBUTE_VALUE; 168 event[1] = 9; 169 little_endian_store_16(event, 2, record_counter); 170 little_endian_store_16(event, 4, attribute_id); 171 little_endian_store_16(event, 6, attribute_value_size); 172 little_endian_store_16(event, 8, attribute_bytes_delivered); 173 event[10] = event_byte; 174 (*sdp_parser_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 175 } 176 177 static void sdp_parser_process_byte(uint8_t eventByte){ 178 // count all bytes 179 list_offset++; 180 record_offset++; 181 182 // log_info(" parse BYTE_RECEIVED %02x", eventByte); 183 switch(state){ 184 case GET_LIST_LENGTH: 185 if (!de_state_size(eventByte, &de_header_state)) break; 186 list_offset = de_header_state.de_offset; 187 list_size = de_header_state.de_size; 188 // log_info("parser: List offset %u, list size %u", list_offset, list_size); 189 190 record_counter = 0; 191 state = GET_RECORD_LENGTH; 192 break; 193 194 case GET_RECORD_LENGTH: 195 // check size 196 if (!de_state_size(eventByte, &de_header_state)) break; 197 // log_info("parser: Record payload is %d bytes.", de_header_state.de_size); 198 record_offset = de_header_state.de_offset; 199 record_size = de_header_state.de_size; 200 state = GET_ATTRIBUTE_ID_HEADER_LENGTH; 201 break; 202 203 case GET_ATTRIBUTE_ID_HEADER_LENGTH: 204 if (!de_state_size(eventByte, &de_header_state)) break; 205 attribute_id = 0; 206 log_debug("ID data is stored in %d bytes.", (int) de_header_state.de_size); 207 state = GET_ATTRIBUTE_ID; 208 break; 209 210 case GET_ATTRIBUTE_ID: 211 attribute_id = (attribute_id << 8) | eventByte; 212 de_header_state.de_size--; 213 if (de_header_state.de_size > 0) break; 214 log_debug("parser: Attribute ID: %04x.", attribute_id); 215 216 state = GET_ATTRIBUTE_VALUE_LENGTH; 217 attribute_bytes_received = 0; 218 attribute_bytes_delivered = 0; 219 attribute_value_size = 0; 220 de_state_init(&de_header_state); 221 break; 222 223 case GET_ATTRIBUTE_VALUE_LENGTH: 224 attribute_bytes_received++; 225 sdp_parser_emit_value_byte(eventByte); 226 attribute_bytes_delivered++; 227 if (!de_state_size(eventByte, &de_header_state)) break; 228 229 attribute_value_size = de_header_state.de_size + attribute_bytes_received; 230 231 state = GET_ATTRIBUTE_VALUE; 232 break; 233 234 case GET_ATTRIBUTE_VALUE: 235 attribute_bytes_received++; 236 sdp_parser_emit_value_byte(eventByte); 237 attribute_bytes_delivered++; 238 // log_debug("paser: attribute_bytes_received %u, attribute_value_size %u", attribute_bytes_received, attribute_value_size); 239 240 if (attribute_bytes_received < attribute_value_size) break; 241 // log_debug("parser: Record offset %u, record size %u", record_offset, record_size); 242 if (record_offset != record_size){ 243 state = GET_ATTRIBUTE_ID_HEADER_LENGTH; 244 // log_debug("Get next attribute"); 245 break; 246 } 247 record_offset = 0; 248 // log_debug("parser: List offset %u, list size %u", list_offset, list_size); 249 250 if ((list_size > 0) && (list_offset != list_size)){ 251 record_counter++; 252 state = GET_RECORD_LENGTH; 253 log_debug("parser: END_OF_RECORD"); 254 break; 255 } 256 list_offset = 0; 257 de_state_init(&de_header_state); 258 state = GET_LIST_LENGTH; 259 record_counter = 0; 260 log_debug("parser: END_OF_RECORD & DONE"); 261 break; 262 default: 263 break; 264 } 265 } 266 267 void sdp_parser_init(btstack_packet_handler_t callback){ 268 // init 269 sdp_parser_callback = callback; 270 de_state_init(&de_header_state); 271 state = GET_LIST_LENGTH; 272 list_offset = 0; 273 list_size = 0; 274 record_offset = 0; 275 record_counter = 0; 276 record_size = 0; 277 attribute_id = 0; 278 attribute_bytes_received = 0; 279 attribute_bytes_delivered = 0; 280 } 281 282 static void sdp_parser_deinit(void) { 283 sdp_parser_callback = NULL; 284 attribute_value_size = 0; 285 record_counter = 0; 286 } 287 288 void sdp_client_init(void){ 289 } 290 291 void sdp_client_deinit(void){ 292 sdp_parser_deinit(); 293 sdp_client_state = INIT; 294 sdp_cid = 0x40; 295 service_search_pattern = NULL; 296 attribute_id_list = NULL; 297 transactionID = 0; 298 continuationStateLen = 0; 299 sdp_client_state = INIT; 300 PDU_ID = SDP_Invalid; 301 #ifdef ENABLE_SDP_EXTRA_QUERIES 302 serviceRecordHandle = 0; 303 record_handle = 0; 304 #endif 305 } 306 307 // for testing only 308 void sdp_client_reset(void){ 309 sdp_client_deinit(); 310 } 311 312 void sdp_parser_handle_chunk(uint8_t * data, uint16_t size){ 313 int i; 314 for (i=0;i<size;i++){ 315 sdp_parser_process_byte(data[i]); 316 } 317 } 318 319 #ifdef ENABLE_SDP_EXTRA_QUERIES 320 void sdp_parser_init_service_attribute_search(void){ 321 // init 322 de_state_init(&de_header_state); 323 state = GET_RECORD_LENGTH; 324 list_offset = 0; 325 record_offset = 0; 326 record_counter = 0; 327 } 328 329 void sdp_parser_init_service_search(void){ 330 record_offset = 0; 331 } 332 333 void sdp_parser_handle_service_search(uint8_t * data, uint16_t total_count, uint16_t record_handle_count){ 334 int i; 335 for (i=0;i<record_handle_count;i++){ 336 record_handle = big_endian_read_32(data, i*4); 337 record_counter++; 338 uint8_t event[10]; 339 event[0] = SDP_EVENT_QUERY_SERVICE_RECORD_HANDLE; 340 event[1] = 8; 341 little_endian_store_16(event, 2, total_count); 342 little_endian_store_16(event, 4, record_counter); 343 little_endian_store_32(event, 6, record_handle); 344 (*sdp_parser_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 345 } 346 } 347 #endif 348 349 static void sdp_client_notify_callbacks(void){ 350 if (sdp_client_ready() == false) { 351 return; 352 } 353 btstack_context_callback_registration_t * callback = (btstack_context_callback_registration_t*) btstack_linked_list_pop(&sdp_client_query_requests); 354 if (callback == NULL) { 355 return; 356 } 357 (*callback->callback)(callback->context); 358 } 359 360 void sdp_parser_handle_done(uint8_t status){ 361 // reset state 362 sdp_client_state = INIT; 363 364 // emit query complete event 365 uint8_t event[3]; 366 event[0] = SDP_EVENT_QUERY_COMPLETE; 367 event[1] = 1; 368 event[2] = status; 369 (*sdp_parser_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event)); 370 371 // trigger next query if pending 372 sdp_client_notify_callbacks(); 373 } 374 375 // SDP Client 376 377 // TODO: inline if not needed (des(des)) 378 379 static void sdp_client_parse_attribute_lists(uint8_t* packet, uint16_t length){ 380 sdp_parser_handle_chunk(packet, length); 381 } 382 383 384 static void sdp_client_send_request(uint16_t channel){ 385 386 if (sdp_client_state != W2_SEND) return; 387 388 l2cap_reserve_packet_buffer(); 389 uint8_t * data = l2cap_get_outgoing_buffer(); 390 uint16_t request_len = 0; 391 392 switch (PDU_ID){ 393 #ifdef ENABLE_SDP_EXTRA_QUERIES 394 case SDP_ServiceSearchResponse: 395 request_len = sdp_client_setup_service_search_request(data); 396 break; 397 case SDP_ServiceAttributeResponse: 398 request_len = sdp_client_setup_service_attribute_request(data); 399 break; 400 #endif 401 case SDP_ServiceSearchAttributeResponse: 402 request_len = sdp_client_setup_service_search_attribute_request(data); 403 break; 404 default: 405 log_error("SDP Client sdp_client_send_request :: PDU ID invalid. %u", PDU_ID); 406 return; 407 } 408 409 // prevent re-entrance 410 sdp_client_state = W4_RESPONSE; 411 PDU_ID = SDP_Invalid; 412 l2cap_send_prepared(channel, request_len); 413 } 414 415 416 static void sdp_client_parse_service_search_attribute_response(uint8_t* packet, uint16_t size){ 417 418 uint16_t offset = 3; 419 if ((offset + 2 + 2) > size) return; // parameterLength + attributeListByteCount 420 uint16_t parameterLength = big_endian_read_16(packet,offset); 421 offset+=2; 422 if ((offset + parameterLength) > size) return; 423 424 // AttributeListByteCount <= mtu 425 uint16_t attributeListByteCount = big_endian_read_16(packet,offset); 426 offset+=2; 427 if (attributeListByteCount > mtu){ 428 log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in found attribute list is larger then the MaximumAttributeByteCount."); 429 return; 430 } 431 432 // AttributeLists 433 if ((offset + attributeListByteCount) > size) return; 434 sdp_client_parse_attribute_lists(packet+offset, attributeListByteCount); 435 offset+=attributeListByteCount; 436 437 // continuation state len 438 if ((offset + 1) > size) return; 439 continuationStateLen = packet[offset]; 440 offset++; 441 if (continuationStateLen > 16){ 442 continuationStateLen = 0; 443 log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in continuation state exceedes 16."); 444 return; 445 } 446 447 // continuation state 448 if ((offset + continuationStateLen) > size) return; 449 (void)memcpy(continuationState, packet + offset, continuationStateLen); 450 // offset+=continuationStateLen; 451 } 452 453 void sdp_client_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 454 455 // uint16_t handle; 456 if (packet_type == L2CAP_DATA_PACKET){ 457 if (size < 3) return; 458 uint16_t responseTransactionID = big_endian_read_16(packet,1); 459 if (responseTransactionID != transactionID){ 460 log_error("Mismatching transaction ID, expected %u, found %u.", transactionID, responseTransactionID); 461 return; 462 } 463 464 PDU_ID = (SDP_PDU_ID_t)packet[0]; 465 switch (PDU_ID){ 466 case SDP_ErrorResponse: 467 log_error("Received error response with code %u, disconnecting", packet[2]); 468 l2cap_disconnect(sdp_cid, 0); 469 return; 470 #ifdef ENABLE_SDP_EXTRA_QUERIES 471 case SDP_ServiceSearchResponse: 472 sdp_client_parse_service_search_response(packet, size); 473 break; 474 case SDP_ServiceAttributeResponse: 475 sdp_client_parse_service_attribute_response(packet, size); 476 break; 477 #endif 478 case SDP_ServiceSearchAttributeResponse: 479 sdp_client_parse_service_search_attribute_response(packet, size); 480 break; 481 default: 482 log_error("PDU ID %u unexpected/invalid", PDU_ID); 483 return; 484 } 485 486 // continuation set or DONE? 487 if (continuationStateLen == 0){ 488 log_debug("SDP Client Query DONE! "); 489 sdp_client_state = QUERY_COMPLETE; 490 l2cap_disconnect(sdp_cid, 0); 491 return; 492 } 493 // prepare next request and send 494 sdp_client_state = W2_SEND; 495 l2cap_request_can_send_now_event(sdp_cid); 496 return; 497 } 498 499 if (packet_type != HCI_EVENT_PACKET) return; 500 501 switch(hci_event_packet_get_type(packet)){ 502 case L2CAP_EVENT_CHANNEL_OPENED: 503 if (sdp_client_state != W4_CONNECT) break; 504 // data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16), local_mtu(16), remote_mtu(16) 505 if (packet[2]) { 506 log_info("SDP Client Connection failed, status 0x%02x.", packet[2]); 507 sdp_parser_handle_done(packet[2]); 508 break; 509 } 510 sdp_cid = channel; 511 mtu = little_endian_read_16(packet, 17); 512 // handle = little_endian_read_16(packet, 9); 513 log_debug("SDP Client Connected, cid %x, mtu %u.", sdp_cid, mtu); 514 515 sdp_client_state = W2_SEND; 516 l2cap_request_can_send_now_event(sdp_cid); 517 break; 518 519 case L2CAP_EVENT_CAN_SEND_NOW: 520 if(l2cap_event_can_send_now_get_local_cid(packet) == sdp_cid){ 521 sdp_client_send_request(sdp_cid); 522 } 523 break; 524 case L2CAP_EVENT_CHANNEL_CLOSED: { 525 if (sdp_cid != little_endian_read_16(packet, 2)) { 526 // log_info("Received L2CAP_EVENT_CHANNEL_CLOSED for cid %x, current cid %x\n", little_endian_read_16(packet, 2),sdp_cid); 527 break; 528 } 529 log_info("SDP Client disconnected."); 530 uint8_t status = (sdp_client_state == QUERY_COMPLETE) ? 0 : SDP_QUERY_INCOMPLETE; 531 sdp_parser_handle_done(status); 532 break; 533 } 534 default: 535 break; 536 } 537 } 538 539 540 static uint16_t sdp_client_setup_service_search_attribute_request(uint8_t * data){ 541 542 uint16_t offset = 0; 543 transactionID++; 544 // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest; 545 data[offset++] = SDP_ServiceSearchAttributeRequest; 546 // uint16_t transactionID 547 big_endian_store_16(data, offset, transactionID); 548 offset += 2; 549 550 // param legnth 551 offset += 2; 552 553 // parameters: 554 // Service_search_pattern - DES (min 1 UUID, max 12) 555 uint16_t service_search_pattern_len = de_get_len(service_search_pattern); 556 (void)memcpy(data + offset, service_search_pattern, 557 service_search_pattern_len); 558 offset += service_search_pattern_len; 559 560 // MaximumAttributeByteCount - uint16_t 0x0007 - 0xffff -> mtu 561 big_endian_store_16(data, offset, mtu); 562 offset += 2; 563 564 // AttibuteIDList 565 uint16_t attribute_id_list_len = de_get_len(attribute_id_list); 566 (void)memcpy(data + offset, attribute_id_list, attribute_id_list_len); 567 offset += attribute_id_list_len; 568 569 // ContinuationState - uint8_t number of cont. bytes N<=16 570 data[offset++] = continuationStateLen; 571 // - N-bytes previous response from server 572 (void)memcpy(data + offset, continuationState, continuationStateLen); 573 offset += continuationStateLen; 574 575 // uint16_t paramLength 576 big_endian_store_16(data, 3, offset - 5); 577 578 return offset; 579 } 580 581 #ifdef ENABLE_SDP_EXTRA_QUERIES 582 void sdp_client_parse_service_record_handle_list(uint8_t* packet, uint16_t total_count, uint16_t current_count){ 583 sdp_parser_handle_service_search(packet, total_count, current_count); 584 } 585 586 static uint16_t sdp_client_setup_service_search_request(uint8_t * data){ 587 uint16_t offset = 0; 588 transactionID++; 589 // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest; 590 data[offset++] = SDP_ServiceSearchRequest; 591 // uint16_t transactionID 592 big_endian_store_16(data, offset, transactionID); 593 offset += 2; 594 595 // param legnth 596 offset += 2; 597 598 // parameters: 599 // Service_search_pattern - DES (min 1 UUID, max 12) 600 uint16_t service_search_pattern_len = de_get_len(service_search_pattern); 601 (void)memcpy(data + offset, service_search_pattern, 602 service_search_pattern_len); 603 offset += service_search_pattern_len; 604 605 // MaximumAttributeByteCount - uint16_t 0x0007 - 0xffff -> mtu 606 big_endian_store_16(data, offset, mtu); 607 offset += 2; 608 609 // ContinuationState - uint8_t number of cont. bytes N<=16 610 data[offset++] = continuationStateLen; 611 // - N-bytes previous response from server 612 (void)memcpy(data + offset, continuationState, continuationStateLen); 613 offset += continuationStateLen; 614 615 // uint16_t paramLength 616 big_endian_store_16(data, 3, offset - 5); 617 618 return offset; 619 } 620 621 622 static uint16_t sdp_client_setup_service_attribute_request(uint8_t * data){ 623 624 uint16_t offset = 0; 625 transactionID++; 626 // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest; 627 data[offset++] = SDP_ServiceAttributeRequest; 628 // uint16_t transactionID 629 big_endian_store_16(data, offset, transactionID); 630 offset += 2; 631 632 // param legnth 633 offset += 2; 634 635 // parameters: 636 // ServiceRecordHandle 637 big_endian_store_32(data, offset, serviceRecordHandle); 638 offset += 4; 639 640 // MaximumAttributeByteCount - uint16_t 0x0007 - 0xffff -> mtu 641 big_endian_store_16(data, offset, mtu); 642 offset += 2; 643 644 // AttibuteIDList 645 uint16_t attribute_id_list_len = de_get_len(attribute_id_list); 646 (void)memcpy(data + offset, attribute_id_list, attribute_id_list_len); 647 offset += attribute_id_list_len; 648 649 // ContinuationState - uint8_t number of cont. bytes N<=16 650 data[offset++] = continuationStateLen; 651 // - N-bytes previous response from server 652 (void)memcpy(data + offset, continuationState, continuationStateLen); 653 offset += continuationStateLen; 654 655 // uint16_t paramLength 656 big_endian_store_16(data, 3, offset - 5); 657 658 return offset; 659 } 660 661 static void sdp_client_parse_service_search_response(uint8_t* packet, uint16_t size){ 662 663 uint16_t offset = 3; 664 if (offset + 2 + 2 + 2 > size) return; // parameterLength, totalServiceRecordCount, currentServiceRecordCount 665 666 uint16_t parameterLength = big_endian_read_16(packet,offset); 667 offset+=2; 668 if (offset + parameterLength > size) return; 669 670 uint16_t totalServiceRecordCount = big_endian_read_16(packet,offset); 671 offset+=2; 672 673 uint16_t currentServiceRecordCount = big_endian_read_16(packet,offset); 674 offset+=2; 675 if (currentServiceRecordCount > totalServiceRecordCount){ 676 log_error("CurrentServiceRecordCount is larger then TotalServiceRecordCount."); 677 return; 678 } 679 680 if (offset + currentServiceRecordCount * 4 > size) return; 681 sdp_client_parse_service_record_handle_list(packet+offset, totalServiceRecordCount, currentServiceRecordCount); 682 offset+= currentServiceRecordCount * 4; 683 684 if (offset + 1 > size) return; 685 continuationStateLen = packet[offset]; 686 offset++; 687 if (continuationStateLen > 16){ 688 continuationStateLen = 0; 689 log_error("Error parsing ServiceSearchResponse: Number of bytes in continuation state exceedes 16."); 690 return; 691 } 692 if (offset + continuationStateLen > size) return; 693 (void)memcpy(continuationState, packet + offset, continuationStateLen); 694 // offset+=continuationStateLen; 695 } 696 697 static void sdp_client_parse_service_attribute_response(uint8_t* packet, uint16_t size){ 698 699 uint16_t offset = 3; 700 if (offset + 2 + 2 > size) return; // parameterLength, attributeListByteCount 701 uint16_t parameterLength = big_endian_read_16(packet,offset); 702 offset+=2; 703 if (offset+parameterLength > size) return; 704 705 // AttributeListByteCount <= mtu 706 uint16_t attributeListByteCount = big_endian_read_16(packet,offset); 707 offset+=2; 708 if (attributeListByteCount > mtu){ 709 log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in found attribute list is larger then the MaximumAttributeByteCount."); 710 return; 711 } 712 713 // AttributeLists 714 if (offset+attributeListByteCount > size) return; 715 sdp_client_parse_attribute_lists(packet+offset, attributeListByteCount); 716 offset+=attributeListByteCount; 717 718 // continuationStateLen 719 if (offset + 1 > size) return; 720 continuationStateLen = packet[offset]; 721 offset++; 722 if (continuationStateLen > 16){ 723 continuationStateLen = 0; 724 log_error("Error parsing ServiceAttributeResponse: Number of bytes in continuation state exceedes 16."); 725 return; 726 } 727 if (offset + continuationStateLen > size) return; 728 (void)memcpy(continuationState, packet + offset, continuationStateLen); 729 // offset+=continuationStateLen; 730 } 731 #endif 732 733 // Public API 734 735 bool sdp_client_ready(void){ 736 return sdp_client_state == INIT; 737 } 738 739 uint8_t sdp_client_register_query_callback(btstack_context_callback_registration_t * callback_registration){ 740 bool added = btstack_linked_list_add_tail(&sdp_client_query_requests, (btstack_linked_item_t*) callback_registration); 741 if (!added) return ERROR_CODE_COMMAND_DISALLOWED; 742 sdp_client_notify_callbacks(); 743 return ERROR_CODE_SUCCESS; 744 } 745 746 uint8_t sdp_client_query(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t * des_service_search_pattern, const uint8_t * des_attribute_id_list){ 747 if (!sdp_client_ready()) return SDP_QUERY_BUSY; 748 749 sdp_parser_init(callback); 750 service_search_pattern = des_service_search_pattern; 751 attribute_id_list = des_attribute_id_list; 752 continuationStateLen = 0; 753 PDU_ID = SDP_ServiceSearchAttributeResponse; 754 755 sdp_client_state = W4_CONNECT; 756 return l2cap_create_channel(sdp_client_packet_handler, remote, BLUETOOTH_PSM_SDP, l2cap_max_mtu(), NULL); 757 } 758 759 uint8_t sdp_client_query_uuid16(btstack_packet_handler_t callback, bd_addr_t remote, uint16_t uuid){ 760 if (!sdp_client_ready()) return SDP_QUERY_BUSY; 761 return sdp_client_query(callback, remote, sdp_service_search_pattern_for_uuid16(uuid), des_attributeIDList); 762 } 763 764 uint8_t sdp_client_query_uuid128(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t* uuid){ 765 if (!sdp_client_ready()) return SDP_QUERY_BUSY; 766 return sdp_client_query(callback, remote, sdp_service_search_pattern_for_uuid128(uuid), des_attributeIDList); 767 } 768 769 #ifdef ENABLE_SDP_EXTRA_QUERIES 770 uint8_t sdp_client_service_attribute_search(btstack_packet_handler_t callback, bd_addr_t remote, uint32_t search_service_record_handle, const uint8_t * des_attribute_id_list){ 771 if (!sdp_client_ready()) return SDP_QUERY_BUSY; 772 773 sdp_parser_init(callback); 774 serviceRecordHandle = search_service_record_handle; 775 attribute_id_list = des_attribute_id_list; 776 continuationStateLen = 0; 777 PDU_ID = SDP_ServiceAttributeResponse; 778 779 sdp_client_state = W4_CONNECT; 780 l2cap_create_channel(sdp_client_packet_handler, remote, BLUETOOTH_PSM_SDP, l2cap_max_mtu(), NULL); 781 return 0; 782 } 783 784 uint8_t sdp_client_service_search(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t * des_service_search_pattern){ 785 786 if (!sdp_client_ready()) return SDP_QUERY_BUSY; 787 788 sdp_parser_init(callback); 789 service_search_pattern = des_service_search_pattern; 790 continuationStateLen = 0; 791 PDU_ID = SDP_ServiceSearchResponse; 792 793 sdp_client_state = W4_CONNECT; 794 l2cap_create_channel(sdp_client_packet_handler, remote, BLUETOOTH_PSM_SDP, l2cap_max_mtu(), NULL); 795 return 0; 796 } 797 #endif 798 799