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