1 /****************************************************************************** 2 * 3 * Copyright 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 functions that handle the SDP server functions. 22 * This is mainly dealing with client requests 23 * 24 ******************************************************************************/ 25 26 #include <cutils/log.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 31 #include "bt_common.h" 32 #include "bt_types.h" 33 #include "bt_utils.h" 34 #include "btu.h" 35 36 #include "hcidefs.h" 37 #include "hcimsgs.h" 38 #include "l2cdefs.h" 39 40 #include "osi/include/osi.h" 41 #include "sdp_api.h" 42 #include "sdpint.h" 43 44 #if (SDP_SERVER_ENABLED == TRUE) 45 46 /* Maximum number of bytes to reserve out of SDP MTU for response data */ 47 #define SDP_MAX_SERVICE_RSPHDR_LEN 12 48 #define SDP_MAX_SERVATTR_RSPHDR_LEN 10 49 #define SDP_MAX_ATTR_RSPHDR_LEN 10 50 51 /******************************************************************************/ 52 /* L O C A L F U N C T I O N P R O T O T Y P E S */ 53 /******************************************************************************/ 54 static void process_service_search(tCONN_CB* p_ccb, uint16_t trans_num, 55 uint16_t param_len, uint8_t* p_req, 56 uint8_t* p_req_end); 57 58 static void process_service_attr_req(tCONN_CB* p_ccb, uint16_t trans_num, 59 uint16_t param_len, uint8_t* p_req, 60 uint8_t* p_req_end); 61 62 static void process_service_search_attr_req(tCONN_CB* p_ccb, uint16_t trans_num, 63 uint16_t param_len, uint8_t* p_req, 64 uint8_t* p_req_end); 65 66 /******************************************************************************/ 67 /* E R R O R T E X T S T R I N G S */ 68 /* */ 69 /* The default is to have no text string, but we allow the strings to be */ 70 /* configured in target.h if people want them. */ 71 /******************************************************************************/ 72 #ifndef SDP_TEXT_BAD_HEADER 73 #define SDP_TEXT_BAD_HEADER NULL 74 #endif 75 76 #ifndef SDP_TEXT_BAD_PDU 77 #define SDP_TEXT_BAD_PDU NULL 78 #endif 79 80 #ifndef SDP_TEXT_BAD_UUID_LIST 81 #define SDP_TEXT_BAD_UUID_LIST NULL 82 #endif 83 84 #ifndef SDP_TEXT_BAD_HANDLE 85 #define SDP_TEXT_BAD_HANDLE NULL 86 #endif 87 88 #ifndef SDP_TEXT_BAD_ATTR_LIST 89 #define SDP_TEXT_BAD_ATTR_LIST NULL 90 #endif 91 92 #ifndef SDP_TEXT_BAD_CONT_LEN 93 #define SDP_TEXT_BAD_CONT_LEN NULL 94 #endif 95 96 #ifndef SDP_TEXT_BAD_CONT_INX 97 #define SDP_TEXT_BAD_CONT_INX NULL 98 #endif 99 100 #ifndef SDP_TEXT_BAD_MAX_RECORDS_LIST 101 #define SDP_TEXT_BAD_MAX_RECORDS_LIST NULL 102 #endif 103 104 /******************************************************************************* 105 * 106 * Function sdp_server_handle_client_req 107 * 108 * Description This is the main dispatcher of the SDP server. It is called 109 * when any data is received from L2CAP, and dispatches the 110 * request to the appropriate handler. 111 * 112 * Returns void 113 * 114 ******************************************************************************/ 115 void sdp_server_handle_client_req(tCONN_CB* p_ccb, BT_HDR* p_msg) { 116 uint8_t* p_req = (uint8_t*)(p_msg + 1) + p_msg->offset; 117 uint8_t* p_req_end = p_req + p_msg->len; 118 uint8_t pdu_id; 119 uint16_t trans_num, param_len; 120 121 /* Start inactivity timer */ 122 alarm_set_on_mloop(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS, 123 sdp_conn_timer_timeout, p_ccb); 124 125 if (p_req + sizeof(pdu_id) + sizeof(trans_num) > p_req_end) { 126 android_errorWriteLog(0x534e4554, "69384124"); 127 trans_num = 0; 128 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, 129 SDP_TEXT_BAD_HEADER); 130 } 131 132 /* The first byte in the message is the pdu type */ 133 pdu_id = *p_req++; 134 135 /* Extract the transaction number and parameter length */ 136 BE_STREAM_TO_UINT16(trans_num, p_req); 137 138 if (p_req + sizeof(param_len) > p_req_end) { 139 android_errorWriteLog(0x534e4554, "69384124"); 140 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, 141 SDP_TEXT_BAD_HEADER); 142 } 143 144 BE_STREAM_TO_UINT16(param_len, p_req); 145 146 if ((p_req + param_len) != p_req_end) { 147 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_PDU_SIZE, 148 SDP_TEXT_BAD_HEADER); 149 return; 150 } 151 152 switch (pdu_id) { 153 case SDP_PDU_SERVICE_SEARCH_REQ: 154 process_service_search(p_ccb, trans_num, param_len, p_req, p_req_end); 155 break; 156 157 case SDP_PDU_SERVICE_ATTR_REQ: 158 process_service_attr_req(p_ccb, trans_num, param_len, p_req, p_req_end); 159 break; 160 161 case SDP_PDU_SERVICE_SEARCH_ATTR_REQ: 162 process_service_search_attr_req(p_ccb, trans_num, param_len, p_req, 163 p_req_end); 164 break; 165 166 default: 167 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, 168 SDP_TEXT_BAD_PDU); 169 SDP_TRACE_WARNING("SDP - server got unknown PDU: 0x%x", pdu_id); 170 break; 171 } 172 } 173 174 /******************************************************************************* 175 * 176 * Function process_service_search 177 * 178 * Description This function handles a service search request from the 179 * client. It builds a reply message with info from the 180 * database, and sends the reply back to the client. 181 * 182 * Returns void 183 * 184 ******************************************************************************/ 185 static void process_service_search(tCONN_CB* p_ccb, uint16_t trans_num, 186 uint16_t param_len, uint8_t* p_req, 187 uint8_t* p_req_end) { 188 uint16_t max_replies, cur_handles, rem_handles, cont_offset; 189 tSDP_UUID_SEQ uid_seq; 190 uint8_t *p_rsp, *p_rsp_start, *p_rsp_param_len; 191 uint16_t rsp_param_len, num_rsp_handles, xx; 192 uint32_t rsp_handles[SDP_MAX_RECORDS] = {0}; 193 tSDP_RECORD* p_rec = NULL; 194 bool is_cont = false; 195 196 p_req = sdpu_extract_uid_seq(p_req, param_len, &uid_seq); 197 198 if ((!p_req) || (!uid_seq.num_uids)) { 199 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, 200 SDP_TEXT_BAD_UUID_LIST); 201 return; 202 } 203 204 /* Get the max replies we can send. Cap it at our max anyways. */ 205 if (p_req + sizeof(max_replies) + sizeof(uint8_t) > p_req_end) { 206 android_errorWriteLog(0x534e4554, "69384124"); 207 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, 208 SDP_TEXT_BAD_MAX_RECORDS_LIST); 209 return; 210 } 211 BE_STREAM_TO_UINT16(max_replies, p_req); 212 213 if (max_replies > SDP_MAX_RECORDS) max_replies = SDP_MAX_RECORDS; 214 215 /* Get a list of handles that match the UUIDs given to us */ 216 for (num_rsp_handles = 0; num_rsp_handles < max_replies;) { 217 p_rec = sdp_db_service_search(p_rec, &uid_seq); 218 219 if (p_rec) 220 rsp_handles[num_rsp_handles++] = p_rec->record_handle; 221 else 222 break; 223 } 224 225 /* Check if this is a continuation request */ 226 if (*p_req) { 227 if (*p_req++ != SDP_CONTINUATION_LEN || 228 (p_req + sizeof(cont_offset) > p_req_end)) { 229 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, 230 SDP_TEXT_BAD_CONT_LEN); 231 return; 232 } 233 BE_STREAM_TO_UINT16(cont_offset, p_req); 234 235 if (cont_offset != p_ccb->cont_offset || num_rsp_handles < cont_offset) { 236 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, 237 SDP_TEXT_BAD_CONT_INX); 238 return; 239 } 240 241 rem_handles = 242 num_rsp_handles - cont_offset; /* extract the remaining handles */ 243 } else { 244 rem_handles = num_rsp_handles; 245 cont_offset = 0; 246 p_ccb->cont_offset = 0; 247 } 248 249 /* Calculate how many handles will fit in one PDU */ 250 cur_handles = 251 (uint16_t)((p_ccb->rem_mtu_size - SDP_MAX_SERVICE_RSPHDR_LEN) / 4); 252 253 if (rem_handles <= cur_handles) 254 cur_handles = rem_handles; 255 else /* Continuation is set */ 256 { 257 p_ccb->cont_offset += cur_handles; 258 is_cont = true; 259 } 260 261 /* Get a buffer to use to build the response */ 262 BT_HDR* p_buf = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE); 263 p_buf->offset = L2CAP_MIN_OFFSET; 264 p_rsp = p_rsp_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; 265 266 /* Start building a rsponse */ 267 UINT8_TO_BE_STREAM(p_rsp, SDP_PDU_SERVICE_SEARCH_RSP); 268 UINT16_TO_BE_STREAM(p_rsp, trans_num); 269 270 /* Skip the length, we need to add it at the end */ 271 p_rsp_param_len = p_rsp; 272 p_rsp += 2; 273 274 /* Put in total and current number of handles, and handles themselves */ 275 UINT16_TO_BE_STREAM(p_rsp, num_rsp_handles); 276 UINT16_TO_BE_STREAM(p_rsp, cur_handles); 277 278 /* SDP_TRACE_DEBUG("SDP Service Rsp: tothdl %d, curhdlr %d, start %d, end %d, 279 cont %d", 280 num_rsp_handles, cur_handles, cont_offset, 281 cont_offset + cur_handles-1, is_cont); */ 282 for (xx = cont_offset; xx < cont_offset + cur_handles; xx++) 283 UINT32_TO_BE_STREAM(p_rsp, rsp_handles[xx]); 284 285 if (is_cont) { 286 UINT8_TO_BE_STREAM(p_rsp, SDP_CONTINUATION_LEN); 287 UINT16_TO_BE_STREAM(p_rsp, p_ccb->cont_offset); 288 } else 289 UINT8_TO_BE_STREAM(p_rsp, 0); 290 291 /* Go back and put the parameter length into the buffer */ 292 rsp_param_len = p_rsp - p_rsp_param_len - 2; 293 UINT16_TO_BE_STREAM(p_rsp_param_len, rsp_param_len); 294 295 /* Set the length of the SDP data in the buffer */ 296 p_buf->len = p_rsp - p_rsp_start; 297 298 /* Send the buffer through L2CAP */ 299 L2CA_DataWrite(p_ccb->connection_id, p_buf); 300 } 301 302 /******************************************************************************* 303 * 304 * Function process_service_attr_req 305 * 306 * Description This function handles an attribute request from the client. 307 * It builds a reply message with info from the database, 308 * and sends the reply back to the client. 309 * 310 * Returns void 311 * 312 ******************************************************************************/ 313 static void process_service_attr_req(tCONN_CB* p_ccb, uint16_t trans_num, 314 uint16_t param_len, uint8_t* p_req, 315 uint8_t* p_req_end) { 316 uint16_t max_list_len, len_to_send, cont_offset; 317 int16_t rem_len; 318 tSDP_ATTR_SEQ attr_seq, attr_seq_sav; 319 uint8_t *p_rsp, *p_rsp_start, *p_rsp_param_len; 320 uint16_t rsp_param_len, xx; 321 uint32_t rec_handle; 322 tSDP_RECORD* p_rec; 323 tSDP_ATTRIBUTE* p_attr; 324 bool is_cont = false; 325 uint16_t attr_len; 326 327 if (p_req + sizeof(rec_handle) + sizeof(max_list_len) > p_req_end) { 328 android_errorWriteLog(0x534e4554, "69384124"); 329 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, 330 SDP_TEXT_BAD_HANDLE); 331 return; 332 } 333 334 /* Extract the record handle */ 335 BE_STREAM_TO_UINT32(rec_handle, p_req); 336 param_len -= sizeof(rec_handle); 337 338 /* Get the max list length we can send. Cap it at MTU size minus overhead */ 339 BE_STREAM_TO_UINT16(max_list_len, p_req); 340 param_len -= sizeof(max_list_len); 341 342 if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN)) 343 max_list_len = p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN; 344 345 p_req = sdpu_extract_attr_seq(p_req, param_len, &attr_seq); 346 347 if ((!p_req) || (!attr_seq.num_attr) || 348 (p_req + sizeof(uint8_t) > p_req_end)) { 349 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, 350 SDP_TEXT_BAD_ATTR_LIST); 351 return; 352 } 353 354 memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)); 355 356 /* Find a record with the record handle */ 357 p_rec = sdp_db_find_record(rec_handle); 358 if (!p_rec) { 359 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, 360 SDP_TEXT_BAD_HANDLE); 361 return; 362 } 363 364 if (max_list_len < 4) { 365 sdpu_build_n_send_error(p_ccb, trans_num, SDP_ILLEGAL_PARAMETER, NULL); 366 android_errorWriteLog(0x534e4554, "68776054"); 367 return; 368 } 369 370 /* Free and reallocate buffer */ 371 osi_free(p_ccb->rsp_list); 372 p_ccb->rsp_list = (uint8_t*)osi_malloc(max_list_len); 373 374 /* Check if this is a continuation request */ 375 if (*p_req) { 376 if (*p_req++ != SDP_CONTINUATION_LEN || 377 (p_req + sizeof(cont_offset) > p_req_end)) { 378 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, 379 SDP_TEXT_BAD_CONT_LEN); 380 return; 381 } 382 BE_STREAM_TO_UINT16(cont_offset, p_req); 383 384 if (cont_offset != p_ccb->cont_offset) { 385 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, 386 SDP_TEXT_BAD_CONT_INX); 387 return; 388 } 389 is_cont = true; 390 391 /* Initialise for continuation response */ 392 p_rsp = &p_ccb->rsp_list[0]; 393 attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start = 394 p_ccb->cont_info.next_attr_start_id; 395 } else { 396 p_ccb->cont_offset = 0; 397 p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */ 398 399 /* Reset continuation parameters in p_ccb */ 400 p_ccb->cont_info.prev_sdp_rec = NULL; 401 p_ccb->cont_info.next_attr_index = 0; 402 p_ccb->cont_info.attr_offset = 0; 403 } 404 405 /* Search for attributes that match the list given to us */ 406 for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++) { 407 p_attr = sdp_db_find_attr_in_rec(p_rec, attr_seq.attr_entry[xx].start, 408 attr_seq.attr_entry[xx].end); 409 410 if (p_attr) { 411 /* Check if attribute fits. Assume 3-byte value type/length */ 412 rem_len = max_list_len - (int16_t)(p_rsp - &p_ccb->rsp_list[0]); 413 414 /* just in case */ 415 if (rem_len <= 0) { 416 p_ccb->cont_info.next_attr_index = xx; 417 p_ccb->cont_info.next_attr_start_id = p_attr->id; 418 break; 419 } 420 421 attr_len = sdpu_get_attrib_entry_len(p_attr); 422 /* if there is a partial attribute pending to be sent */ 423 if (p_ccb->cont_info.attr_offset) { 424 p_rsp = sdpu_build_partial_attrib_entry(p_rsp, p_attr, rem_len, 425 &p_ccb->cont_info.attr_offset); 426 427 /* If the partial attrib could not been fully added yet */ 428 if (p_ccb->cont_info.attr_offset != attr_len) 429 break; 430 else /* If the partial attrib has been added in full by now */ 431 p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */ 432 } else if (rem_len < 433 attr_len) /* Not enough space for attr... so add partially */ 434 { 435 if (attr_len >= SDP_MAX_ATTR_LEN) { 436 SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d", 437 max_list_len, attr_len); 438 sdpu_build_n_send_error(p_ccb, trans_num, SDP_NO_RESOURCES, NULL); 439 return; 440 } 441 442 /* add the partial attribute if possible */ 443 p_rsp = sdpu_build_partial_attrib_entry( 444 p_rsp, p_attr, (uint16_t)rem_len, &p_ccb->cont_info.attr_offset); 445 446 p_ccb->cont_info.next_attr_index = xx; 447 p_ccb->cont_info.next_attr_start_id = p_attr->id; 448 break; 449 } else /* build the whole attribute */ 450 p_rsp = sdpu_build_attrib_entry(p_rsp, p_attr); 451 452 /* If doing a range, stick with this one till no more attributes found */ 453 if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end) { 454 /* Update for next time through */ 455 attr_seq.attr_entry[xx].start = p_attr->id + 1; 456 457 xx--; 458 } 459 } 460 } 461 /* If all the attributes have been accomodated in p_rsp, 462 reset next_attr_index */ 463 if (xx == attr_seq.num_attr) p_ccb->cont_info.next_attr_index = 0; 464 465 len_to_send = (uint16_t)(p_rsp - &p_ccb->rsp_list[0]); 466 cont_offset = 0; 467 468 if (!is_cont) { 469 p_ccb->list_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav) + 3; 470 /* Put in the sequence header (2 or 3 bytes) */ 471 if (p_ccb->list_len > 255) { 472 p_ccb->rsp_list[0] = 473 (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD); 474 p_ccb->rsp_list[1] = (uint8_t)((p_ccb->list_len - 3) >> 8); 475 p_ccb->rsp_list[2] = (uint8_t)(p_ccb->list_len - 3); 476 } else { 477 cont_offset = 1; 478 479 p_ccb->rsp_list[1] = 480 (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); 481 p_ccb->rsp_list[2] = (uint8_t)(p_ccb->list_len - 3); 482 483 p_ccb->list_len--; 484 len_to_send--; 485 } 486 } 487 488 /* Get a buffer to use to build the response */ 489 BT_HDR* p_buf = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE); 490 p_buf->offset = L2CAP_MIN_OFFSET; 491 p_rsp = p_rsp_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; 492 493 /* Start building a rsponse */ 494 UINT8_TO_BE_STREAM(p_rsp, SDP_PDU_SERVICE_ATTR_RSP); 495 UINT16_TO_BE_STREAM(p_rsp, trans_num); 496 497 /* Skip the parameter length, add it when we know the length */ 498 p_rsp_param_len = p_rsp; 499 p_rsp += 2; 500 501 UINT16_TO_BE_STREAM(p_rsp, len_to_send); 502 503 memcpy(p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send); 504 p_rsp += len_to_send; 505 506 p_ccb->cont_offset += len_to_send; 507 508 /* If anything left to send, continuation needed */ 509 if (p_ccb->cont_offset < p_ccb->list_len) { 510 is_cont = true; 511 512 UINT8_TO_BE_STREAM(p_rsp, SDP_CONTINUATION_LEN); 513 UINT16_TO_BE_STREAM(p_rsp, p_ccb->cont_offset); 514 } else 515 UINT8_TO_BE_STREAM(p_rsp, 0); 516 517 /* Go back and put the parameter length into the buffer */ 518 rsp_param_len = p_rsp - p_rsp_param_len - 2; 519 UINT16_TO_BE_STREAM(p_rsp_param_len, rsp_param_len); 520 521 /* Set the length of the SDP data in the buffer */ 522 p_buf->len = p_rsp - p_rsp_start; 523 524 /* Send the buffer through L2CAP */ 525 L2CA_DataWrite(p_ccb->connection_id, p_buf); 526 } 527 528 /******************************************************************************* 529 * 530 * Function process_service_search_attr_req 531 * 532 * Description This function handles a combined service search and 533 * attribute read request from the client. It builds a reply 534 * message with info from the database, and sends the reply 535 * back to the client. 536 * 537 * Returns void 538 * 539 ******************************************************************************/ 540 static void process_service_search_attr_req(tCONN_CB* p_ccb, uint16_t trans_num, 541 uint16_t param_len, uint8_t* p_req, 542 uint8_t* p_req_end) { 543 uint16_t max_list_len; 544 int16_t rem_len; 545 uint16_t len_to_send, cont_offset; 546 tSDP_UUID_SEQ uid_seq; 547 uint8_t *p_rsp, *p_rsp_start, *p_rsp_param_len; 548 uint16_t rsp_param_len, xx; 549 tSDP_RECORD* p_rec; 550 tSDP_ATTR_SEQ attr_seq, attr_seq_sav; 551 tSDP_ATTRIBUTE* p_attr; 552 bool maxxed_out = false, is_cont = false; 553 uint8_t* p_seq_start; 554 uint16_t seq_len, attr_len; 555 556 /* Extract the UUID sequence to search for */ 557 p_req = sdpu_extract_uid_seq(p_req, param_len, &uid_seq); 558 559 if ((!p_req) || (!uid_seq.num_uids) || 560 (p_req + sizeof(uint16_t) > p_req_end)) { 561 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, 562 SDP_TEXT_BAD_UUID_LIST); 563 return; 564 } 565 566 /* Get the max list length we can send. Cap it at our max list length. */ 567 BE_STREAM_TO_UINT16(max_list_len, p_req); 568 569 if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN)) 570 max_list_len = p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN; 571 572 param_len = static_cast<uint16_t>(p_req_end - p_req); 573 p_req = sdpu_extract_attr_seq(p_req, param_len, &attr_seq); 574 575 if ((!p_req) || (!attr_seq.num_attr) || 576 (p_req + sizeof(uint8_t) > p_req_end)) { 577 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, 578 SDP_TEXT_BAD_ATTR_LIST); 579 return; 580 } 581 582 memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)); 583 584 if (max_list_len < 4) { 585 sdpu_build_n_send_error(p_ccb, trans_num, SDP_ILLEGAL_PARAMETER, NULL); 586 android_errorWriteLog(0x534e4554, "68817966"); 587 return; 588 } 589 590 /* Free and reallocate buffer */ 591 osi_free(p_ccb->rsp_list); 592 p_ccb->rsp_list = (uint8_t*)osi_malloc(max_list_len); 593 594 /* Check if this is a continuation request */ 595 if (*p_req) { 596 if (*p_req++ != SDP_CONTINUATION_LEN || 597 (p_req + sizeof(uint16_t) > p_req_end)) { 598 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, 599 SDP_TEXT_BAD_CONT_LEN); 600 return; 601 } 602 BE_STREAM_TO_UINT16(cont_offset, p_req); 603 604 if (cont_offset != p_ccb->cont_offset) { 605 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, 606 SDP_TEXT_BAD_CONT_INX); 607 return; 608 } 609 is_cont = true; 610 611 /* Initialise for continuation response */ 612 p_rsp = &p_ccb->rsp_list[0]; 613 attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start = 614 p_ccb->cont_info.next_attr_start_id; 615 } else { 616 p_ccb->cont_offset = 0; 617 p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */ 618 619 /* Reset continuation parameters in p_ccb */ 620 p_ccb->cont_info.prev_sdp_rec = NULL; 621 p_ccb->cont_info.next_attr_index = 0; 622 p_ccb->cont_info.last_attr_seq_desc_sent = false; 623 p_ccb->cont_info.attr_offset = 0; 624 } 625 626 /* Get a list of handles that match the UUIDs given to us */ 627 for (p_rec = sdp_db_service_search(p_ccb->cont_info.prev_sdp_rec, &uid_seq); 628 p_rec; p_rec = sdp_db_service_search(p_rec, &uid_seq)) { 629 /* Allow space for attribute sequence type and length */ 630 p_seq_start = p_rsp; 631 if (!p_ccb->cont_info.last_attr_seq_desc_sent) { 632 /* See if there is enough room to include a new service in the current 633 * response */ 634 rem_len = max_list_len - (int16_t)(p_rsp - &p_ccb->rsp_list[0]); 635 if (rem_len < 3) { 636 /* Not enough room. Update continuation info for next response */ 637 p_ccb->cont_info.next_attr_index = 0; 638 p_ccb->cont_info.next_attr_start_id = attr_seq.attr_entry[0].start; 639 break; 640 } 641 p_rsp += 3; 642 } 643 644 /* Get a list of handles that match the UUIDs given to us */ 645 for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++) { 646 p_attr = sdp_db_find_attr_in_rec(p_rec, attr_seq.attr_entry[xx].start, 647 attr_seq.attr_entry[xx].end); 648 649 if (p_attr) { 650 /* Check if attribute fits. Assume 3-byte value type/length */ 651 rem_len = max_list_len - (int16_t)(p_rsp - &p_ccb->rsp_list[0]); 652 653 /* just in case */ 654 if (rem_len <= 0) { 655 p_ccb->cont_info.next_attr_index = xx; 656 p_ccb->cont_info.next_attr_start_id = p_attr->id; 657 maxxed_out = true; 658 break; 659 } 660 661 attr_len = sdpu_get_attrib_entry_len(p_attr); 662 /* if there is a partial attribute pending to be sent */ 663 if (p_ccb->cont_info.attr_offset) { 664 p_rsp = sdpu_build_partial_attrib_entry( 665 p_rsp, p_attr, rem_len, &p_ccb->cont_info.attr_offset); 666 667 /* If the partial attrib could not been fully added yet */ 668 if (p_ccb->cont_info.attr_offset != attr_len) { 669 maxxed_out = true; 670 break; 671 } else /* If the partial attrib has been added in full by now */ 672 p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */ 673 } else if (rem_len < 674 attr_len) /* Not enough space for attr... so add partially */ 675 { 676 if (attr_len >= SDP_MAX_ATTR_LEN) { 677 SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d", 678 max_list_len, attr_len); 679 sdpu_build_n_send_error(p_ccb, trans_num, SDP_NO_RESOURCES, NULL); 680 return; 681 } 682 683 /* add the partial attribute if possible */ 684 p_rsp = sdpu_build_partial_attrib_entry( 685 p_rsp, p_attr, (uint16_t)rem_len, &p_ccb->cont_info.attr_offset); 686 687 p_ccb->cont_info.next_attr_index = xx; 688 p_ccb->cont_info.next_attr_start_id = p_attr->id; 689 maxxed_out = true; 690 break; 691 } else /* build the whole attribute */ 692 p_rsp = sdpu_build_attrib_entry(p_rsp, p_attr); 693 694 /* If doing a range, stick with this one till no more attributes found 695 */ 696 if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end) { 697 /* Update for next time through */ 698 attr_seq.attr_entry[xx].start = p_attr->id + 1; 699 700 xx--; 701 } 702 } 703 } 704 705 /* Go back and put the type and length into the buffer */ 706 if (!p_ccb->cont_info.last_attr_seq_desc_sent) { 707 seq_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav); 708 if (seq_len != 0) { 709 UINT8_TO_BE_STREAM(p_seq_start, 710 (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD); 711 UINT16_TO_BE_STREAM(p_seq_start, seq_len); 712 713 if (maxxed_out) p_ccb->cont_info.last_attr_seq_desc_sent = true; 714 } else 715 p_rsp = p_seq_start; 716 } 717 718 if (maxxed_out) break; 719 720 /* Restore the attr_seq to look for in the next sdp record */ 721 memcpy(&attr_seq, &attr_seq_sav, sizeof(tSDP_ATTR_SEQ)); 722 723 /* Reset the next attr index */ 724 p_ccb->cont_info.next_attr_index = 0; 725 p_ccb->cont_info.prev_sdp_rec = p_rec; 726 p_ccb->cont_info.last_attr_seq_desc_sent = false; 727 } 728 729 /* response length */ 730 len_to_send = (uint16_t)(p_rsp - &p_ccb->rsp_list[0]); 731 cont_offset = 0; 732 733 // The current SDP server design has a critical flaw where it can run into 734 // an infinite request/response loop with the client. Here's the scenario: 735 // - client makes SDP request 736 // - server returns the first fragment of the response with a continuation 737 // token 738 // - an SDP record is deleted from the server 739 // - client issues another request with previous continuation token 740 // - server has nothing to send back because the record is unavailable but 741 // in the first fragment, it had specified more response bytes than are 742 // now available 743 // - server sends back no additional response bytes and returns the same 744 // continuation token 745 // - client issues another request with the continuation token, and the 746 // process repeats 747 // 748 // We work around this design flaw here by checking if we will make forward 749 // progress (i.e. we will send > 0 response bytes) on a continued request. 750 // If not, we must have run into the above situation and we tell the peer an 751 // error occurred. 752 // 753 // TODO(sharvil): rewrite SDP server. 754 if (is_cont && len_to_send == 0) { 755 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, NULL); 756 return; 757 } 758 759 /* If first response, insert sequence header */ 760 if (!is_cont) { 761 /* Get the total list length for requested uid and attribute sequence */ 762 p_ccb->list_len = sdpu_get_list_len(&uid_seq, &attr_seq_sav) + 3; 763 /* Put in the sequence header (2 or 3 bytes) */ 764 if (p_ccb->list_len > 255) { 765 p_ccb->rsp_list[0] = 766 (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD); 767 p_ccb->rsp_list[1] = (uint8_t)((p_ccb->list_len - 3) >> 8); 768 p_ccb->rsp_list[2] = (uint8_t)(p_ccb->list_len - 3); 769 } else { 770 cont_offset = 1; 771 772 p_ccb->rsp_list[1] = 773 (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); 774 p_ccb->rsp_list[2] = (uint8_t)(p_ccb->list_len - 3); 775 776 p_ccb->list_len--; 777 len_to_send--; 778 } 779 } 780 781 /* Get a buffer to use to build the response */ 782 BT_HDR* p_buf = (BT_HDR*)osi_malloc(SDP_DATA_BUF_SIZE); 783 p_buf->offset = L2CAP_MIN_OFFSET; 784 p_rsp = p_rsp_start = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET; 785 786 /* Start building a rsponse */ 787 UINT8_TO_BE_STREAM(p_rsp, SDP_PDU_SERVICE_SEARCH_ATTR_RSP); 788 UINT16_TO_BE_STREAM(p_rsp, trans_num); 789 790 /* Skip the parameter length, add it when we know the length */ 791 p_rsp_param_len = p_rsp; 792 p_rsp += 2; 793 794 /* Stream the list length to send */ 795 UINT16_TO_BE_STREAM(p_rsp, len_to_send); 796 797 /* copy from rsp_list to the actual buffer to be sent */ 798 memcpy(p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send); 799 p_rsp += len_to_send; 800 801 p_ccb->cont_offset += len_to_send; 802 803 /* If anything left to send, continuation needed */ 804 if (p_ccb->cont_offset < p_ccb->list_len) { 805 is_cont = true; 806 807 UINT8_TO_BE_STREAM(p_rsp, SDP_CONTINUATION_LEN); 808 UINT16_TO_BE_STREAM(p_rsp, p_ccb->cont_offset); 809 } else 810 UINT8_TO_BE_STREAM(p_rsp, 0); 811 812 /* Go back and put the parameter length into the buffer */ 813 rsp_param_len = p_rsp - p_rsp_param_len - 2; 814 UINT16_TO_BE_STREAM(p_rsp_param_len, rsp_param_len); 815 816 /* Set the length of the SDP data in the buffer */ 817 p_buf->len = p_rsp - p_rsp_start; 818 819 /* Send the buffer through L2CAP */ 820 L2CA_DataWrite(p_ccb->connection_id, p_buf); 821 } 822 823 #endif /* SDP_SERVER_ENABLED == TRUE */ 824