1/****************************************************************************** 2 * 3 * Copyright (C) 1999-2012 Broadcom Corporation 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19/****************************************************************************** 20 * 21 * this file contains SDP discovery functions 22 * 23 ******************************************************************************/ 24 25#include <stdio.h> 26#include <stdlib.h> 27#include <string.h> 28 29#include "bt_common.h" 30#include "bt_target.h" 31#include "btm_api.h" 32#include "btu.h" 33#include "hcidefs.h" 34#include "hcimsgs.h" 35#include "l2cdefs.h" 36#include "sdp_api.h" 37#include "sdpint.h" 38 39#ifndef SDP_DEBUG_RAW 40#define SDP_DEBUG_RAW false 41#endif 42 43/******************************************************************************/ 44/* L O C A L F U N C T I O N P R O T O T Y P E S */ 45/******************************************************************************/ 46static void process_service_search_rsp(tCONN_CB* p_ccb, uint8_t* p_reply); 47static void process_service_attr_rsp(tCONN_CB* p_ccb, uint8_t* p_reply); 48static void process_service_search_attr_rsp(tCONN_CB* p_ccb, uint8_t* p_reply); 49static uint8_t* save_attr_seq(tCONN_CB* p_ccb, uint8_t* p, uint8_t* p_msg_end); 50static tSDP_DISC_REC* add_record(tSDP_DISCOVERY_DB* p_db, BD_ADDR p_bda); 51static uint8_t* add_attr(uint8_t* p, tSDP_DISCOVERY_DB* p_db, 52 tSDP_DISC_REC* p_rec, uint16_t attr_id, 53 tSDP_DISC_ATTR* p_parent_attr, uint8_t nest_level); 54 55/* Safety check in case we go crazy */ 56#define MAX_NEST_LEVELS 5 57 58extern fixed_queue_t* btu_general_alarm_queue; 59 60/******************************************************************************* 61 * 62 * Function sdpu_build_uuid_seq 63 * 64 * Description This function builds a UUID sequence from the list of 65 * passed UUIDs. It is also passed the address of the output 66 * buffer. 67 * 68 * Returns Pointer to next byte in the output buffer. 69 * 70 ******************************************************************************/ 71static uint8_t* sdpu_build_uuid_seq(uint8_t* p_out, uint16_t num_uuids, 72 tSDP_UUID* p_uuid_list) { 73 uint16_t xx; 74 uint8_t* p_len; 75 76 /* First thing is the data element header */ 77 UINT8_TO_BE_STREAM(p_out, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); 78 79 /* Remember where the length goes. Leave space for it. */ 80 p_len = p_out; 81 p_out += 1; 82 83 /* Now, loop through and put in all the UUID(s) */ 84 for (xx = 0; xx < num_uuids; xx++, p_uuid_list++) { 85 if (p_uuid_list->len == 2) { 86 UINT8_TO_BE_STREAM(p_out, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES); 87 UINT16_TO_BE_STREAM(p_out, p_uuid_list->uu.uuid16); 88 } else if (p_uuid_list->len == 4) { 89 UINT8_TO_BE_STREAM(p_out, (UUID_DESC_TYPE << 3) | SIZE_FOUR_BYTES); 90 UINT32_TO_BE_STREAM(p_out, p_uuid_list->uu.uuid32); 91 } else { 92 UINT8_TO_BE_STREAM(p_out, (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES); 93 ARRAY_TO_BE_STREAM(p_out, p_uuid_list->uu.uuid128, p_uuid_list->len); 94 } 95 } 96 97 /* Now, put in the length */ 98 xx = (uint16_t)(p_out - p_len - 1); 99 UINT8_TO_BE_STREAM(p_len, xx); 100 101 return (p_out); 102} 103 104/******************************************************************************* 105 * 106 * Function sdp_snd_service_search_req 107 * 108 * Description Send a service search request to the SDP server. 109 * 110 * Returns void 111 * 112 ******************************************************************************/ 113static void sdp_snd_service_search_req(tCONN_CB* p_ccb, uint8_t cont_len, 114 uint8_t* p_cont) { 115 uint8_t *p, *p_start, *p_param_len; 116 BT_HDR* p_cmd = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE); 117 uint16_t param_len; 118 119 /* Prepare the buffer for sending the packet to L2CAP */ 120 p_cmd->offset = L2CAP_MIN_OFFSET; 121 p = p_start = (uint8_t*)(p_cmd + 1) + L2CAP_MIN_OFFSET; 122 123 /* Build a service search request packet */ 124 UINT8_TO_BE_STREAM(p, SDP_PDU_SERVICE_SEARCH_REQ); 125 UINT16_TO_BE_STREAM(p, p_ccb->transaction_id); 126 p_ccb->transaction_id++; 127 128 /* Skip the length, we need to add it at the end */ 129 p_param_len = p; 130 p += 2; 131 132/* Build the UID sequence. */ 133#if (SDP_BROWSE_PLUS == TRUE) 134 p = sdpu_build_uuid_seq(p, 1, 135 &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx]); 136#else 137 p = sdpu_build_uuid_seq(p, p_ccb->p_db->num_uuid_filters, 138 p_ccb->p_db->uuid_filters); 139#endif 140 141 /* Set max service record count */ 142 UINT16_TO_BE_STREAM(p, sdp_cb.max_recs_per_search); 143 144 /* Set continuation state */ 145 UINT8_TO_BE_STREAM(p, cont_len); 146 147 /* if this is not the first request */ 148 if (cont_len && p_cont) { 149 memcpy(p, p_cont, cont_len); 150 p += cont_len; 151 } 152 153 /* Go back and put the parameter length into the buffer */ 154 param_len = (uint16_t)(p - p_param_len - 2); 155 UINT16_TO_BE_STREAM(p_param_len, param_len); 156 157 p_ccb->disc_state = SDP_DISC_WAIT_HANDLES; 158 159 /* Set the length of the SDP data in the buffer */ 160 p_cmd->len = (uint16_t)(p - p_start); 161 162#if (SDP_DEBUG_RAW == TRUE) 163 SDP_TRACE_WARNING("sdp_snd_service_search_req cont_len :%d disc_state:%d", 164 cont_len, p_ccb->disc_state); 165#endif 166 167 L2CA_DataWrite(p_ccb->connection_id, p_cmd); 168 169 /* Start inactivity timer */ 170 alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS, 171 sdp_conn_timer_timeout, p_ccb, btu_general_alarm_queue); 172} 173 174/******************************************************************************* 175 * 176 * Function sdp_disc_connected 177 * 178 * Description This function is called when an SDP discovery attempt is 179 * connected. 180 * 181 * Returns void 182 * 183 ******************************************************************************/ 184void sdp_disc_connected(tCONN_CB* p_ccb) { 185 if (p_ccb->is_attr_search) { 186 p_ccb->disc_state = SDP_DISC_WAIT_SEARCH_ATTR; 187 188 process_service_search_attr_rsp(p_ccb, NULL); 189 } else { 190 /* First step is to get a list of the handles from the server. */ 191 /* We are not searching for a specific attribute, so we will */ 192 /* first search for the service, then get all attributes of it */ 193 194 p_ccb->num_handles = 0; 195 sdp_snd_service_search_req(p_ccb, 0, NULL); 196 } 197} 198 199/******************************************************************************* 200 * 201 * Function sdp_disc_server_rsp 202 * 203 * Description This function is called when there is a response from 204 * the server. 205 * 206 * Returns void 207 * 208 ******************************************************************************/ 209void sdp_disc_server_rsp(tCONN_CB* p_ccb, BT_HDR* p_msg) { 210 uint8_t *p, rsp_pdu; 211 bool invalid_pdu = true; 212 213#if (SDP_DEBUG_RAW == TRUE) 214 SDP_TRACE_WARNING("sdp_disc_server_rsp disc_state:%d", p_ccb->disc_state); 215#endif 216 217 /* stop inactivity timer when we receive a response */ 218 alarm_cancel(p_ccb->sdp_conn_timer); 219 220 /* Got a reply!! Check what we got back */ 221 p = (uint8_t*)(p_msg + 1) + p_msg->offset; 222 223 BE_STREAM_TO_UINT8(rsp_pdu, p); 224 225 p_msg->len--; 226 227 switch (rsp_pdu) { 228 case SDP_PDU_SERVICE_SEARCH_RSP: 229 if (p_ccb->disc_state == SDP_DISC_WAIT_HANDLES) { 230 process_service_search_rsp(p_ccb, p); 231 invalid_pdu = false; 232 } 233 break; 234 235 case SDP_PDU_SERVICE_ATTR_RSP: 236 if (p_ccb->disc_state == SDP_DISC_WAIT_ATTR) { 237 process_service_attr_rsp(p_ccb, p); 238 invalid_pdu = false; 239 } 240 break; 241 242 case SDP_PDU_SERVICE_SEARCH_ATTR_RSP: 243 if (p_ccb->disc_state == SDP_DISC_WAIT_SEARCH_ATTR) { 244 process_service_search_attr_rsp(p_ccb, p); 245 invalid_pdu = false; 246 } 247 break; 248 } 249 250 if (invalid_pdu) { 251 SDP_TRACE_WARNING("SDP - Unexp. PDU: %d in state: %d", rsp_pdu, 252 p_ccb->disc_state); 253 sdp_disconnect(p_ccb, SDP_GENERIC_ERROR); 254 } 255} 256 257/****************************************************************************** 258 * 259 * Function process_service_search_rsp 260 * 261 * Description This function is called when there is a search response from 262 * the server. 263 * 264 * Returns void 265 * 266 ******************************************************************************/ 267static void process_service_search_rsp(tCONN_CB* p_ccb, uint8_t* p_reply) { 268 uint16_t xx; 269 uint16_t total, cur_handles, orig; 270 uint8_t cont_len; 271 272 /* Skip transaction, and param len */ 273 p_reply += 4; 274 BE_STREAM_TO_UINT16(total, p_reply); 275 BE_STREAM_TO_UINT16(cur_handles, p_reply); 276 277 orig = p_ccb->num_handles; 278 p_ccb->num_handles += cur_handles; 279 if (p_ccb->num_handles == 0) { 280 SDP_TRACE_WARNING("SDP - Rcvd ServiceSearchRsp, no matches"); 281 sdp_disconnect(p_ccb, SDP_NO_RECS_MATCH); 282 return; 283 } 284 285 /* Save the handles that match. We will can only process a certain number. */ 286 if (total > sdp_cb.max_recs_per_search) total = sdp_cb.max_recs_per_search; 287 if (p_ccb->num_handles > sdp_cb.max_recs_per_search) 288 p_ccb->num_handles = sdp_cb.max_recs_per_search; 289 290 for (xx = orig; xx < p_ccb->num_handles; xx++) 291 BE_STREAM_TO_UINT32(p_ccb->handles[xx], p_reply); 292 293 BE_STREAM_TO_UINT8(cont_len, p_reply); 294 if (cont_len != 0) { 295 if (cont_len > SDP_MAX_CONTINUATION_LEN) { 296 sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE); 297 return; 298 } 299 /* stay in the same state */ 300 sdp_snd_service_search_req(p_ccb, cont_len, p_reply); 301 } else { 302 /* change state */ 303 p_ccb->disc_state = SDP_DISC_WAIT_ATTR; 304 305 /* Kick off the first attribute request */ 306 process_service_attr_rsp(p_ccb, NULL); 307 } 308} 309 310/******************************************************************************* 311 * 312 * Function sdp_copy_raw_data 313 * 314 * Description copy the raw data 315 * 316 * 317 * Returns void 318 * 319 ******************************************************************************/ 320#if (SDP_RAW_DATA_INCLUDED == TRUE) 321static void sdp_copy_raw_data(tCONN_CB* p_ccb, bool offset) { 322 unsigned int cpy_len; 323 uint32_t list_len; 324 uint8_t* p; 325 uint8_t type; 326 327#if (SDP_DEBUG_RAW == TRUE) 328 uint8_t num_array[SDP_MAX_LIST_BYTE_COUNT]; 329 uint32_t i; 330 331 for (i = 0; i < p_ccb->list_len; i++) { 332 snprintf((char*)&num_array[i * 2], sizeof(num_array) - i * 2, "%02X", 333 (uint8_t)(p_ccb->rsp_list[i])); 334 } 335 SDP_TRACE_WARNING("result :%s", num_array); 336#endif 337 338 if (p_ccb->p_db->raw_data) { 339 cpy_len = p_ccb->p_db->raw_size - p_ccb->p_db->raw_used; 340 list_len = p_ccb->list_len; 341 p = &p_ccb->rsp_list[0]; 342 343 if (offset) { 344 type = *p++; 345 p = sdpu_get_len_from_type(p, type, &list_len); 346 } 347 if (list_len && list_len < cpy_len) { 348 cpy_len = list_len; 349 } 350 SDP_TRACE_WARNING( 351 "%s: list_len:%d cpy_len:%d p:%p p_ccb:%p p_db:%p raw_size:%d " 352 "raw_used:%d raw_data:%p", 353 __func__, list_len, cpy_len, p, p_ccb, p_ccb->p_db, 354 p_ccb->p_db->raw_size, p_ccb->p_db->raw_used, p_ccb->p_db->raw_data); 355 memcpy(&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len); 356 p_ccb->p_db->raw_used += cpy_len; 357 } 358} 359#endif 360 361/******************************************************************************* 362 * 363 * Function process_service_attr_rsp 364 * 365 * Description This function is called when there is a attribute response 366 * from the server. 367 * 368 * Returns void 369 * 370 ******************************************************************************/ 371static void process_service_attr_rsp(tCONN_CB* p_ccb, uint8_t* p_reply) { 372 uint8_t *p_start, *p_param_len; 373 uint16_t param_len, list_byte_count; 374 bool cont_request_needed = false; 375 376#if (SDP_DEBUG_RAW == TRUE) 377 SDP_TRACE_WARNING("process_service_attr_rsp raw inc:%d", 378 SDP_RAW_DATA_INCLUDED); 379#endif 380 /* If p_reply is NULL, we were called after the records handles were read */ 381 if (p_reply) { 382#if (SDP_DEBUG_RAW == TRUE) 383 SDP_TRACE_WARNING("ID & len: 0x%02x-%02x-%02x-%02x", p_reply[0], p_reply[1], 384 p_reply[2], p_reply[3]); 385#endif 386 /* Skip transaction ID and length */ 387 p_reply += 4; 388 389 BE_STREAM_TO_UINT16(list_byte_count, p_reply); 390#if (SDP_DEBUG_RAW == TRUE) 391 SDP_TRACE_WARNING("list_byte_count:%d", list_byte_count); 392#endif 393 394 /* Copy the response to the scratchpad. First, a safety check on the length 395 */ 396 if ((p_ccb->list_len + list_byte_count) > SDP_MAX_LIST_BYTE_COUNT) { 397 sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE); 398 return; 399 } 400 401#if (SDP_DEBUG_RAW == TRUE) 402 SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d", p_ccb->list_len, 403 list_byte_count); 404#endif 405 if (p_ccb->rsp_list == NULL) 406 p_ccb->rsp_list = (uint8_t*)osi_malloc(SDP_MAX_LIST_BYTE_COUNT); 407 memcpy(&p_ccb->rsp_list[p_ccb->list_len], p_reply, list_byte_count); 408 p_ccb->list_len += list_byte_count; 409 p_reply += list_byte_count; 410#if (SDP_DEBUG_RAW == TRUE) 411 SDP_TRACE_WARNING("list_len: %d(attr_rsp)", p_ccb->list_len); 412 413 /* Check if we need to request a continuation */ 414 SDP_TRACE_WARNING("*p_reply:%d(%d)", *p_reply, SDP_MAX_CONTINUATION_LEN); 415#endif 416 if (*p_reply) { 417 if (*p_reply > SDP_MAX_CONTINUATION_LEN) { 418 sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE); 419 return; 420 } 421 cont_request_needed = true; 422 } else { 423#if (SDP_RAW_DATA_INCLUDED == TRUE) 424 SDP_TRACE_WARNING("process_service_attr_rsp"); 425 sdp_copy_raw_data(p_ccb, false); 426#endif 427 428 /* Save the response in the database. Stop on any error */ 429 if (!save_attr_seq(p_ccb, &p_ccb->rsp_list[0], 430 &p_ccb->rsp_list[p_ccb->list_len])) { 431 sdp_disconnect(p_ccb, SDP_DB_FULL); 432 return; 433 } 434 p_ccb->list_len = 0; 435 p_ccb->cur_handle++; 436 } 437 } 438 439 /* Now, ask for the next handle. Re-use the buffer we just got. */ 440 if (p_ccb->cur_handle < p_ccb->num_handles) { 441 BT_HDR* p_msg = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE); 442 uint8_t* p; 443 444 p_msg->offset = L2CAP_MIN_OFFSET; 445 p = p_start = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET; 446 447 /* Get all the attributes from the server */ 448 UINT8_TO_BE_STREAM(p, SDP_PDU_SERVICE_ATTR_REQ); 449 UINT16_TO_BE_STREAM(p, p_ccb->transaction_id); 450 p_ccb->transaction_id++; 451 452 /* Skip the length, we need to add it at the end */ 453 p_param_len = p; 454 p += 2; 455 456 UINT32_TO_BE_STREAM(p, p_ccb->handles[p_ccb->cur_handle]); 457 458 /* Max attribute byte count */ 459 UINT16_TO_BE_STREAM(p, sdp_cb.max_attr_list_size); 460 461 /* If no attribute filters, build a wildcard attribute sequence */ 462 if (p_ccb->p_db->num_attr_filters) 463 p = sdpu_build_attrib_seq(p, p_ccb->p_db->attr_filters, 464 p_ccb->p_db->num_attr_filters); 465 else 466 p = sdpu_build_attrib_seq(p, NULL, 0); 467 468 /* Was this a continuation request ? */ 469 if (cont_request_needed) { 470 memcpy(p, p_reply, *p_reply + 1); 471 p += *p_reply + 1; 472 } else 473 UINT8_TO_BE_STREAM(p, 0); 474 475 /* Go back and put the parameter length into the buffer */ 476 param_len = (uint16_t)(p - p_param_len - 2); 477 UINT16_TO_BE_STREAM(p_param_len, param_len); 478 479 /* Set the length of the SDP data in the buffer */ 480 p_msg->len = (uint16_t)(p - p_start); 481 482 L2CA_DataWrite(p_ccb->connection_id, p_msg); 483 484 /* Start inactivity timer */ 485 alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS, 486 sdp_conn_timer_timeout, p_ccb, btu_general_alarm_queue); 487 } else { 488 sdp_disconnect(p_ccb, SDP_SUCCESS); 489 return; 490 } 491} 492 493/******************************************************************************* 494 * 495 * Function process_service_search_attr_rsp 496 * 497 * Description This function is called when there is a search attribute 498 * response from the server. 499 * 500 * Returns void 501 * 502 ******************************************************************************/ 503static void process_service_search_attr_rsp(tCONN_CB* p_ccb, uint8_t* p_reply) { 504 uint8_t *p, *p_start, *p_end, *p_param_len; 505 uint8_t type; 506 uint32_t seq_len; 507 uint16_t param_len, lists_byte_count = 0; 508 bool cont_request_needed = false; 509 510#if (SDP_DEBUG_RAW == TRUE) 511 SDP_TRACE_WARNING("process_service_search_attr_rsp"); 512#endif 513 /* If p_reply is NULL, we were called for the initial read */ 514 if (p_reply) { 515#if (SDP_DEBUG_RAW == TRUE) 516 SDP_TRACE_WARNING("ID & len: 0x%02x-%02x-%02x-%02x", p_reply[0], p_reply[1], 517 p_reply[2], p_reply[3]); 518#endif 519 /* Skip transaction ID and length */ 520 p_reply += 4; 521 522 BE_STREAM_TO_UINT16(lists_byte_count, p_reply); 523#if (SDP_DEBUG_RAW == TRUE) 524 SDP_TRACE_WARNING("lists_byte_count:%d", lists_byte_count); 525#endif 526 527 /* Copy the response to the scratchpad. First, a safety check on the length 528 */ 529 if ((p_ccb->list_len + lists_byte_count) > SDP_MAX_LIST_BYTE_COUNT) { 530 sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE); 531 return; 532 } 533 534#if (SDP_DEBUG_RAW == TRUE) 535 SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d", p_ccb->list_len, 536 lists_byte_count); 537#endif 538 if (p_ccb->rsp_list == NULL) 539 p_ccb->rsp_list = (uint8_t*)osi_malloc(SDP_MAX_LIST_BYTE_COUNT); 540 memcpy(&p_ccb->rsp_list[p_ccb->list_len], p_reply, lists_byte_count); 541 p_ccb->list_len += lists_byte_count; 542 p_reply += lists_byte_count; 543#if (SDP_DEBUG_RAW == TRUE) 544 SDP_TRACE_WARNING("list_len: %d(search_attr_rsp)", p_ccb->list_len); 545 546 /* Check if we need to request a continuation */ 547 SDP_TRACE_WARNING("*p_reply:%d(%d)", *p_reply, SDP_MAX_CONTINUATION_LEN); 548#endif 549 if (*p_reply) { 550 if (*p_reply > SDP_MAX_CONTINUATION_LEN) { 551 sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE); 552 return; 553 } 554 555 cont_request_needed = true; 556 } 557 } 558 559#if (SDP_DEBUG_RAW == TRUE) 560 SDP_TRACE_WARNING("cont_request_needed:%d", cont_request_needed); 561#endif 562 /* If continuation request (or first time request) */ 563 if ((cont_request_needed) || (!p_reply)) { 564 BT_HDR* p_msg = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE); 565 uint8_t* p; 566 567 p_msg->offset = L2CAP_MIN_OFFSET; 568 p = p_start = (uint8_t*)(p_msg + 1) + L2CAP_MIN_OFFSET; 569 570 /* Build a service search request packet */ 571 UINT8_TO_BE_STREAM(p, SDP_PDU_SERVICE_SEARCH_ATTR_REQ); 572 UINT16_TO_BE_STREAM(p, p_ccb->transaction_id); 573 p_ccb->transaction_id++; 574 575 /* Skip the length, we need to add it at the end */ 576 p_param_len = p; 577 p += 2; 578 579/* Build the UID sequence. */ 580#if (SDP_BROWSE_PLUS == TRUE) 581 p = sdpu_build_uuid_seq(p, 1, 582 &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx]); 583#else 584 p = sdpu_build_uuid_seq(p, p_ccb->p_db->num_uuid_filters, 585 p_ccb->p_db->uuid_filters); 586#endif 587 588 /* Max attribute byte count */ 589 UINT16_TO_BE_STREAM(p, sdp_cb.max_attr_list_size); 590 591 /* If no attribute filters, build a wildcard attribute sequence */ 592 if (p_ccb->p_db->num_attr_filters) 593 p = sdpu_build_attrib_seq(p, p_ccb->p_db->attr_filters, 594 p_ccb->p_db->num_attr_filters); 595 else 596 p = sdpu_build_attrib_seq(p, NULL, 0); 597 598 /* No continuation for first request */ 599 if (p_reply) { 600 memcpy(p, p_reply, *p_reply + 1); 601 p += *p_reply + 1; 602 } else 603 UINT8_TO_BE_STREAM(p, 0); 604 605 /* Go back and put the parameter length into the buffer */ 606 param_len = p - p_param_len - 2; 607 UINT16_TO_BE_STREAM(p_param_len, param_len); 608 609 /* Set the length of the SDP data in the buffer */ 610 p_msg->len = p - p_start; 611 612 L2CA_DataWrite(p_ccb->connection_id, p_msg); 613 614 /* Start inactivity timer */ 615 alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS, 616 sdp_conn_timer_timeout, p_ccb, btu_general_alarm_queue); 617 618 return; 619 } 620 621/*******************************************************************/ 622/* We now have the full response, which is a sequence of sequences */ 623/*******************************************************************/ 624 625#if (SDP_RAW_DATA_INCLUDED == TRUE) 626 SDP_TRACE_WARNING("process_service_search_attr_rsp"); 627 sdp_copy_raw_data(p_ccb, true); 628#endif 629 630 p = &p_ccb->rsp_list[0]; 631 632 /* The contents is a sequence of attribute sequences */ 633 type = *p++; 634 635 if ((type >> 3) != DATA_ELE_SEQ_DESC_TYPE) { 636 SDP_TRACE_WARNING("SDP - Wrong type: 0x%02x in attr_rsp", type); 637 return; 638 } 639 p = sdpu_get_len_from_type(p, type, &seq_len); 640 641 p_end = &p_ccb->rsp_list[p_ccb->list_len]; 642 643 if ((p + seq_len) != p_end) { 644 sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE); 645 return; 646 } 647 648 while (p < p_end) { 649 p = save_attr_seq(p_ccb, p, &p_ccb->rsp_list[p_ccb->list_len]); 650 if (!p) { 651 sdp_disconnect(p_ccb, SDP_DB_FULL); 652 return; 653 } 654 } 655 656 /* Since we got everything we need, disconnect the call */ 657 sdp_disconnect(p_ccb, SDP_SUCCESS); 658} 659 660/******************************************************************************* 661 * 662 * Function save_attr_seq 663 * 664 * Description This function is called when there is a response from 665 * the server. 666 * 667 * Returns pointer to next byte or NULL if error 668 * 669 ******************************************************************************/ 670static uint8_t* save_attr_seq(tCONN_CB* p_ccb, uint8_t* p, uint8_t* p_msg_end) { 671 uint32_t seq_len, attr_len; 672 uint16_t attr_id; 673 uint8_t type, *p_seq_end; 674 tSDP_DISC_REC* p_rec; 675 676 type = *p++; 677 678 if ((type >> 3) != DATA_ELE_SEQ_DESC_TYPE) { 679 SDP_TRACE_WARNING("SDP - Wrong type: 0x%02x in attr_rsp", type); 680 return (NULL); 681 } 682 683 p = sdpu_get_len_from_type(p, type, &seq_len); 684 if ((p + seq_len) > p_msg_end) { 685 SDP_TRACE_WARNING("SDP - Bad len in attr_rsp %d", seq_len); 686 return (NULL); 687 } 688 689 /* Create a record */ 690 p_rec = add_record(p_ccb->p_db, p_ccb->device_address); 691 if (!p_rec) { 692 SDP_TRACE_WARNING("SDP - DB full add_record"); 693 return (NULL); 694 } 695 696 p_seq_end = p + seq_len; 697 698 while (p < p_seq_end) { 699 /* First get the attribute ID */ 700 type = *p++; 701 p = sdpu_get_len_from_type(p, type, &attr_len); 702 if (((type >> 3) != UINT_DESC_TYPE) || (attr_len != 2)) { 703 SDP_TRACE_WARNING("SDP - Bad type: 0x%02x or len: %d in attr_rsp", type, 704 attr_len); 705 return (NULL); 706 } 707 BE_STREAM_TO_UINT16(attr_id, p); 708 709 /* Now, add the attribute value */ 710 p = add_attr(p, p_ccb->p_db, p_rec, attr_id, NULL, 0); 711 712 if (!p) { 713 SDP_TRACE_WARNING("SDP - DB full add_attr"); 714 return (NULL); 715 } 716 } 717 718 return (p); 719} 720 721/******************************************************************************* 722 * 723 * Function add_record 724 * 725 * Description This function allocates space for a record from the DB. 726 * 727 * Returns pointer to next byte in data stream 728 * 729 ******************************************************************************/ 730tSDP_DISC_REC* add_record(tSDP_DISCOVERY_DB* p_db, BD_ADDR p_bda) { 731 tSDP_DISC_REC* p_rec; 732 733 /* See if there is enough space in the database */ 734 if (p_db->mem_free < sizeof(tSDP_DISC_REC)) return (NULL); 735 736 p_rec = (tSDP_DISC_REC*)p_db->p_free_mem; 737 p_db->p_free_mem += sizeof(tSDP_DISC_REC); 738 p_db->mem_free -= sizeof(tSDP_DISC_REC); 739 740 p_rec->p_first_attr = NULL; 741 p_rec->p_next_rec = NULL; 742 743 memcpy(p_rec->remote_bd_addr, p_bda, BD_ADDR_LEN); 744 745 /* Add the record to the end of chain */ 746 if (!p_db->p_first_rec) 747 p_db->p_first_rec = p_rec; 748 else { 749 tSDP_DISC_REC* p_rec1 = p_db->p_first_rec; 750 751 while (p_rec1->p_next_rec) p_rec1 = p_rec1->p_next_rec; 752 753 p_rec1->p_next_rec = p_rec; 754 } 755 756 return (p_rec); 757} 758 759#define SDP_ADDITIONAL_LIST_MASK 0x80 760/******************************************************************************* 761 * 762 * Function add_attr 763 * 764 * Description This function allocates space for an attribute from the DB 765 * and copies the data into it. 766 * 767 * Returns pointer to next byte in data stream 768 * 769 ******************************************************************************/ 770static uint8_t* add_attr(uint8_t* p, tSDP_DISCOVERY_DB* p_db, 771 tSDP_DISC_REC* p_rec, uint16_t attr_id, 772 tSDP_DISC_ATTR* p_parent_attr, uint8_t nest_level) { 773 tSDP_DISC_ATTR* p_attr; 774 uint32_t attr_len; 775 uint32_t total_len; 776 uint16_t attr_type; 777 uint16_t id; 778 uint8_t type; 779 uint8_t* p_end; 780 uint8_t is_additional_list = nest_level & SDP_ADDITIONAL_LIST_MASK; 781 782 nest_level &= ~(SDP_ADDITIONAL_LIST_MASK); 783 784 type = *p++; 785 p = sdpu_get_len_from_type(p, type, &attr_len); 786 787 attr_len &= SDP_DISC_ATTR_LEN_MASK; 788 attr_type = (type >> 3) & 0x0f; 789 790 /* See if there is enough space in the database */ 791 if (attr_len > 4) 792 total_len = attr_len - 4 + (uint16_t)sizeof(tSDP_DISC_ATTR); 793 else 794 total_len = sizeof(tSDP_DISC_ATTR); 795 796 /* Ensure it is a multiple of 4 */ 797 total_len = (total_len + 3) & ~3; 798 799 /* See if there is enough space in the database */ 800 if (p_db->mem_free < total_len) return (NULL); 801 802 p_attr = (tSDP_DISC_ATTR*)p_db->p_free_mem; 803 p_attr->attr_id = attr_id; 804 p_attr->attr_len_type = (uint16_t)attr_len | (attr_type << 12); 805 p_attr->p_next_attr = NULL; 806 807 /* Store the attribute value */ 808 switch (attr_type) { 809 case UINT_DESC_TYPE: 810 if ((is_additional_list != 0) && (attr_len == 2)) { 811 BE_STREAM_TO_UINT16(id, p); 812 if (id != ATTR_ID_PROTOCOL_DESC_LIST) 813 p -= 2; 814 else { 815 /* Reserve the memory for the attribute now, as we need to add 816 * sub-attributes */ 817 p_db->p_free_mem += sizeof(tSDP_DISC_ATTR); 818 p_db->mem_free -= sizeof(tSDP_DISC_ATTR); 819 p_end = p + attr_len; 820 total_len = 0; 821 822 /* SDP_TRACE_DEBUG ("SDP - attr nest level:%d(list)", nest_level); */ 823 if (nest_level >= MAX_NEST_LEVELS) { 824 SDP_TRACE_ERROR("SDP - attr nesting too deep"); 825 return (p_end); 826 } 827 828 /* Now, add the list entry */ 829 p = add_attr(p, p_db, p_rec, ATTR_ID_PROTOCOL_DESC_LIST, p_attr, 830 (uint8_t)(nest_level + 1)); 831 832 break; 833 } 834 } 835 /* Case falls through */ 836 837 case TWO_COMP_INT_DESC_TYPE: 838 switch (attr_len) { 839 case 1: 840 p_attr->attr_value.v.u8 = *p++; 841 break; 842 case 2: 843 BE_STREAM_TO_UINT16(p_attr->attr_value.v.u16, p); 844 break; 845 case 4: 846 BE_STREAM_TO_UINT32(p_attr->attr_value.v.u32, p); 847 break; 848 default: 849 BE_STREAM_TO_ARRAY(p, p_attr->attr_value.v.array, (int32_t)attr_len); 850 break; 851 } 852 break; 853 854 case UUID_DESC_TYPE: 855 switch (attr_len) { 856 case 2: 857 BE_STREAM_TO_UINT16(p_attr->attr_value.v.u16, p); 858 break; 859 case 4: 860 BE_STREAM_TO_UINT32(p_attr->attr_value.v.u32, p); 861 if (p_attr->attr_value.v.u32 < 0x10000) { 862 attr_len = 2; 863 p_attr->attr_len_type = (uint16_t)attr_len | (attr_type << 12); 864 p_attr->attr_value.v.u16 = (uint16_t)p_attr->attr_value.v.u32; 865 } 866 break; 867 case 16: 868 /* See if we can compress his UUID down to 16 or 32bit UUIDs */ 869 if (sdpu_is_base_uuid(p)) { 870 if ((p[0] == 0) && (p[1] == 0)) { 871 p_attr->attr_len_type = 872 (p_attr->attr_len_type & ~SDP_DISC_ATTR_LEN_MASK) | 2; 873 p += 2; 874 BE_STREAM_TO_UINT16(p_attr->attr_value.v.u16, p); 875 p += MAX_UUID_SIZE - 4; 876 } else { 877 p_attr->attr_len_type = 878 (p_attr->attr_len_type & ~SDP_DISC_ATTR_LEN_MASK) | 4; 879 BE_STREAM_TO_UINT32(p_attr->attr_value.v.u32, p); 880 p += MAX_UUID_SIZE - 4; 881 } 882 } else { 883 BE_STREAM_TO_ARRAY(p, p_attr->attr_value.v.array, 884 (int32_t)attr_len); 885 } 886 break; 887 default: 888 SDP_TRACE_WARNING("SDP - bad len in UUID attr: %d", attr_len); 889 return (p + attr_len); 890 } 891 break; 892 893 case DATA_ELE_SEQ_DESC_TYPE: 894 case DATA_ELE_ALT_DESC_TYPE: 895 /* Reserve the memory for the attribute now, as we need to add 896 * sub-attributes */ 897 p_db->p_free_mem += sizeof(tSDP_DISC_ATTR); 898 p_db->mem_free -= sizeof(tSDP_DISC_ATTR); 899 p_end = p + attr_len; 900 total_len = 0; 901 902 /* SDP_TRACE_DEBUG ("SDP - attr nest level:%d", nest_level); */ 903 if (nest_level >= MAX_NEST_LEVELS) { 904 SDP_TRACE_ERROR("SDP - attr nesting too deep"); 905 return (p_end); 906 } 907 if (is_additional_list != 0 || 908 attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS) 909 nest_level |= SDP_ADDITIONAL_LIST_MASK; 910 /* SDP_TRACE_DEBUG ("SDP - attr nest level:0x%x(finish)", nest_level); */ 911 912 while (p < p_end) { 913 /* Now, add the list entry */ 914 p = add_attr(p, p_db, p_rec, 0, p_attr, (uint8_t)(nest_level + 1)); 915 916 if (!p) return (NULL); 917 } 918 break; 919 920 case TEXT_STR_DESC_TYPE: 921 case URL_DESC_TYPE: 922 BE_STREAM_TO_ARRAY(p, p_attr->attr_value.v.array, (int32_t)attr_len); 923 break; 924 925 case BOOLEAN_DESC_TYPE: 926 switch (attr_len) { 927 case 1: 928 p_attr->attr_value.v.u8 = *p++; 929 break; 930 default: 931 SDP_TRACE_WARNING("SDP - bad len in boolean attr: %d", attr_len); 932 return (p + attr_len); 933 } 934 break; 935 936 default: /* switch (attr_type) */ 937 break; 938 } 939 940 p_db->p_free_mem += total_len; 941 p_db->mem_free -= total_len; 942 943 /* Add the attribute to the end of the chain */ 944 if (!p_parent_attr) { 945 if (!p_rec->p_first_attr) 946 p_rec->p_first_attr = p_attr; 947 else { 948 tSDP_DISC_ATTR* p_attr1 = p_rec->p_first_attr; 949 950 while (p_attr1->p_next_attr) p_attr1 = p_attr1->p_next_attr; 951 952 p_attr1->p_next_attr = p_attr; 953 } 954 } else { 955 if (!p_parent_attr->attr_value.v.p_sub_attr) { 956 p_parent_attr->attr_value.v.p_sub_attr = p_attr; 957 /* SDP_TRACE_DEBUG ("parent:0x%x(id:%d), ch:0x%x(id:%d)", 958 p_parent_attr, p_parent_attr->attr_id, p_attr, p_attr->attr_id); */ 959 } else { 960 tSDP_DISC_ATTR* p_attr1 = p_parent_attr->attr_value.v.p_sub_attr; 961 /* SDP_TRACE_DEBUG ("parent:0x%x(id:%d), ch1:0x%x(id:%d)", 962 p_parent_attr, p_parent_attr->attr_id, p_attr1, p_attr1->attr_id); */ 963 964 while (p_attr1->p_next_attr) p_attr1 = p_attr1->p_next_attr; 965 966 p_attr1->p_next_attr = p_attr; 967 /* SDP_TRACE_DEBUG ("new ch:0x%x(id:%d)", p_attr, p_attr->attr_id); */ 968 } 969 } 970 971 return (p); 972} 973