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