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 database 22 * 23 ******************************************************************************/ 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 29 #include "bt_target.h" 30 31 #include "bt_common.h" 32 33 #include "hcidefs.h" 34 #include "hcimsgs.h" 35 #include "l2cdefs.h" 36 37 #include "sdp_api.h" 38 #include "sdpint.h" 39 40 #if (SDP_SERVER_ENABLED == TRUE) 41 /******************************************************************************/ 42 /* L O C A L F U N C T I O N P R O T O T Y P E S */ 43 /******************************************************************************/ 44 static bool find_uuid_in_seq(uint8_t* p, uint32_t seq_len, uint8_t* p_his_uuid, 45 uint16_t his_len, int nest_level); 46 47 /******************************************************************************* 48 * 49 * Function sdp_db_service_search 50 * 51 * Description This function searches for a record that contains the 52 * specified UIDs. It is passed either NULL to start at the 53 * beginning, or the previous record found. 54 * 55 * Returns Pointer to the record, or NULL if not found. 56 * 57 ******************************************************************************/ 58 tSDP_RECORD* sdp_db_service_search(tSDP_RECORD* p_rec, tSDP_UUID_SEQ* p_seq) { 59 uint16_t xx, yy; 60 tSDP_ATTRIBUTE* p_attr; 61 tSDP_RECORD* p_end = &sdp_cb.server_db.record[sdp_cb.server_db.num_records]; 62 63 /* If NULL, start at the beginning, else start at the first specified record 64 */ 65 if (!p_rec) 66 p_rec = &sdp_cb.server_db.record[0]; 67 else 68 p_rec++; 69 70 /* Look through the records. The spec says that a match occurs if */ 71 /* the record contains all the passed UUIDs in it. */ 72 for (; p_rec < p_end; p_rec++) { 73 for (yy = 0; yy < p_seq->num_uids; yy++) { 74 p_attr = &p_rec->attribute[0]; 75 for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++) { 76 if (p_attr->type == UUID_DESC_TYPE) { 77 if (sdpu_compare_uuid_arrays(p_attr->value_ptr, p_attr->len, 78 &p_seq->uuid_entry[yy].value[0], 79 p_seq->uuid_entry[yy].len)) 80 break; 81 } else if (p_attr->type == DATA_ELE_SEQ_DESC_TYPE) { 82 if (find_uuid_in_seq(p_attr->value_ptr, p_attr->len, 83 &p_seq->uuid_entry[yy].value[0], 84 p_seq->uuid_entry[yy].len, 0)) 85 break; 86 } 87 } 88 /* If any UUID was not found, on to the next record */ 89 if (xx == p_rec->num_attributes) break; 90 } 91 92 /* If every UUID was found in the record, return the record */ 93 if (yy == p_seq->num_uids) return (p_rec); 94 } 95 96 /* If here, no more records found */ 97 return (NULL); 98 } 99 100 /******************************************************************************* 101 * 102 * Function find_uuid_in_seq 103 * 104 * Description This function searches a data element sequenct for a UUID. 105 * 106 * Returns true if found, else false 107 * 108 ******************************************************************************/ 109 static bool find_uuid_in_seq(uint8_t* p, uint32_t seq_len, uint8_t* p_uuid, 110 uint16_t uuid_len, int nest_level) { 111 uint8_t* p_end = p + seq_len; 112 uint8_t type; 113 uint32_t len; 114 115 /* A little safety check to avoid excessive recursion */ 116 if (nest_level > 3) return (false); 117 118 while (p < p_end) { 119 type = *p++; 120 p = sdpu_get_len_from_type(p, type, &len); 121 type = type >> 3; 122 if (type == UUID_DESC_TYPE) { 123 if (sdpu_compare_uuid_arrays(p, len, p_uuid, uuid_len)) return (true); 124 } else if (type == DATA_ELE_SEQ_DESC_TYPE) { 125 if (find_uuid_in_seq(p, len, p_uuid, uuid_len, nest_level + 1)) 126 return (true); 127 } 128 p = p + len; 129 } 130 131 /* If here, failed to match */ 132 return (false); 133 } 134 135 /******************************************************************************* 136 * 137 * Function sdp_db_find_record 138 * 139 * Description This function searches for a record with a specific handle 140 * It is passed the handle of the record. 141 * 142 * Returns Pointer to the record, or NULL if not found. 143 * 144 ******************************************************************************/ 145 tSDP_RECORD* sdp_db_find_record(uint32_t handle) { 146 tSDP_RECORD* p_rec; 147 tSDP_RECORD* p_end = &sdp_cb.server_db.record[sdp_cb.server_db.num_records]; 148 149 /* Look through the records for the caller's handle */ 150 for (p_rec = &sdp_cb.server_db.record[0]; p_rec < p_end; p_rec++) { 151 if (p_rec->record_handle == handle) return (p_rec); 152 } 153 154 /* Record with that handle not found. */ 155 return (NULL); 156 } 157 158 /******************************************************************************* 159 * 160 * Function sdp_db_find_attr_in_rec 161 * 162 * Description This function searches a record for specific attributes. 163 * It is passed a pointer to the record. If the record contains 164 * the specified attribute, (the caller may specify be a range 165 * of attributes), the attribute is returned. 166 * 167 * Returns Pointer to the attribute, or NULL if not found. 168 * 169 ******************************************************************************/ 170 tSDP_ATTRIBUTE* sdp_db_find_attr_in_rec(tSDP_RECORD* p_rec, uint16_t start_attr, 171 uint16_t end_attr) { 172 tSDP_ATTRIBUTE* p_at; 173 uint16_t xx; 174 175 /* Note that the attributes in a record are assumed to be in sorted order */ 176 for (xx = 0, p_at = &p_rec->attribute[0]; xx < p_rec->num_attributes; 177 xx++, p_at++) { 178 if ((p_at->id >= start_attr) && (p_at->id <= end_attr)) return (p_at); 179 } 180 181 /* No matching attribute found */ 182 return (NULL); 183 } 184 185 /******************************************************************************* 186 * 187 * Function sdp_compose_proto_list 188 * 189 * Description This function is called to compose a data sequence from 190 * protocol element list struct pointer 191 * 192 * Returns the length of the data sequence 193 * 194 ******************************************************************************/ 195 static int sdp_compose_proto_list(uint8_t* p, uint16_t num_elem, 196 tSDP_PROTOCOL_ELEM* p_elem_list) { 197 uint16_t xx, yy, len; 198 bool is_rfcomm_scn; 199 uint8_t* p_head = p; 200 uint8_t* p_len; 201 202 /* First, build the protocol list. This consists of a set of data element 203 ** sequences, one for each layer. Each layer sequence consists of layer's 204 ** UUID and optional parameters 205 */ 206 for (xx = 0; xx < num_elem; xx++, p_elem_list++) { 207 len = 3 + (p_elem_list->num_params * 3); 208 UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); 209 210 p_len = p; 211 *p++ = (uint8_t)len; 212 213 UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES); 214 UINT16_TO_BE_STREAM(p, p_elem_list->protocol_uuid); 215 216 if (p_elem_list->protocol_uuid == UUID_PROTOCOL_RFCOMM) 217 is_rfcomm_scn = true; 218 else 219 is_rfcomm_scn = false; 220 221 for (yy = 0; yy < p_elem_list->num_params; yy++) { 222 if (is_rfcomm_scn) { 223 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE); 224 UINT8_TO_BE_STREAM(p, p_elem_list->params[yy]); 225 226 *p_len -= 1; 227 } else { 228 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); 229 UINT16_TO_BE_STREAM(p, p_elem_list->params[yy]); 230 } 231 } 232 } 233 return (p - p_head); 234 } 235 236 #endif /* SDP_SERVER_ENABLED == TRUE */ 237 238 /******************************************************************************* 239 * 240 * Function SDP_CreateRecord 241 * 242 * Description This function is called to create a record in the database. 243 * This would be through the SDP database maintenance API. The 244 * record is created empty, teh application should then call 245 * "add_attribute" to add the record's attributes. 246 * 247 * Returns Record handle if OK, else 0. 248 * 249 ******************************************************************************/ 250 uint32_t SDP_CreateRecord(void) { 251 #if (SDP_SERVER_ENABLED == TRUE) 252 uint32_t handle; 253 uint8_t buf[4]; 254 tSDP_DB* p_db = &sdp_cb.server_db; 255 256 /* First, check if there is a free record */ 257 if (p_db->num_records < SDP_MAX_RECORDS) { 258 memset(&p_db->record[p_db->num_records], 0, sizeof(tSDP_RECORD)); 259 260 /* We will use a handle of the first unreserved handle plus last record 261 ** number + 1 */ 262 if (p_db->num_records) 263 handle = p_db->record[p_db->num_records - 1].record_handle + 1; 264 else 265 handle = 0x10000; 266 267 p_db->record[p_db->num_records].record_handle = handle; 268 269 p_db->num_records++; 270 SDP_TRACE_DEBUG("SDP_CreateRecord ok, num_records:%d", p_db->num_records); 271 /* Add the first attribute (the handle) automatically */ 272 UINT32_TO_BE_FIELD(buf, handle); 273 SDP_AddAttribute(handle, ATTR_ID_SERVICE_RECORD_HDL, UINT_DESC_TYPE, 4, 274 buf); 275 276 return (p_db->record[p_db->num_records - 1].record_handle); 277 } else 278 SDP_TRACE_ERROR("SDP_CreateRecord fail, exceed maximum records:%d", 279 SDP_MAX_RECORDS); 280 #endif 281 return (0); 282 } 283 284 /******************************************************************************* 285 * 286 * Function SDP_DeleteRecord 287 * 288 * Description This function is called to add a record (or all records) 289 * from the database. This would be through the SDP database 290 * maintenance API. 291 * 292 * If a record handle of 0 is passed, all records are deleted. 293 * 294 * Returns true if succeeded, else false 295 * 296 ******************************************************************************/ 297 bool SDP_DeleteRecord(uint32_t handle) { 298 #if (SDP_SERVER_ENABLED == TRUE) 299 uint16_t xx, yy, zz; 300 tSDP_RECORD* p_rec = &sdp_cb.server_db.record[0]; 301 302 if (handle == 0 || sdp_cb.server_db.num_records == 0) { 303 /* Delete all records in the database */ 304 sdp_cb.server_db.num_records = 0; 305 306 /* require new DI record to be created in SDP_SetLocalDiRecord */ 307 sdp_cb.server_db.di_primary_handle = 0; 308 309 return (true); 310 } else { 311 /* Find the record in the database */ 312 for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++) { 313 if (p_rec->record_handle == handle) { 314 /* Found it. Shift everything up one */ 315 for (yy = xx; yy < sdp_cb.server_db.num_records - 1; yy++, p_rec++) { 316 *p_rec = *(p_rec + 1); 317 318 /* Adjust the attribute value pointer for each attribute */ 319 for (zz = 0; zz < p_rec->num_attributes; zz++) 320 p_rec->attribute[zz].value_ptr -= sizeof(tSDP_RECORD); 321 } 322 323 sdp_cb.server_db.num_records--; 324 325 SDP_TRACE_DEBUG("SDP_DeleteRecord ok, num_records:%d", 326 sdp_cb.server_db.num_records); 327 /* if we're deleting the primary DI record, clear the */ 328 /* value in the control block */ 329 if (sdp_cb.server_db.di_primary_handle == handle) { 330 sdp_cb.server_db.di_primary_handle = 0; 331 } 332 333 return (true); 334 } 335 } 336 } 337 #endif 338 return (false); 339 } 340 341 /******************************************************************************* 342 * 343 * Function SDP_AddAttribute 344 * 345 * Description This function is called to add an attribute to a record. 346 * This would be through the SDP database maintenance API. 347 * If the attribute already exists in the record, it is 348 * replaced with the new value. 349 * 350 * NOTE Attribute values must be passed as a Big Endian stream. 351 * 352 * Returns true if added OK, else false 353 * 354 ******************************************************************************/ 355 bool SDP_AddAttribute(uint32_t handle, uint16_t attr_id, uint8_t attr_type, 356 uint32_t attr_len, uint8_t* p_val) { 357 #if (SDP_SERVER_ENABLED == TRUE) 358 uint16_t xx, yy, zz; 359 tSDP_RECORD* p_rec = &sdp_cb.server_db.record[0]; 360 361 if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) { 362 if ((attr_type == UINT_DESC_TYPE) || 363 (attr_type == TWO_COMP_INT_DESC_TYPE) || 364 (attr_type == UUID_DESC_TYPE) || 365 (attr_type == DATA_ELE_SEQ_DESC_TYPE) || 366 (attr_type == DATA_ELE_ALT_DESC_TYPE)) { 367 uint8_t num_array[400]; 368 uint32_t len = (attr_len > 200) ? 200 : attr_len; 369 370 num_array[0] = '\0'; 371 for (uint32_t i = 0; i < len; i++) { 372 snprintf((char*)&num_array[i * 2], sizeof(num_array) - i * 2, "%02X", 373 (uint8_t)(p_val[i])); 374 } 375 SDP_TRACE_DEBUG( 376 "SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, " 377 "*p_val:%s", 378 handle, attr_id, attr_type, attr_len, p_val, num_array); 379 } else if (attr_type == BOOLEAN_DESC_TYPE) { 380 SDP_TRACE_DEBUG( 381 "SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, " 382 "*p_val:%d", 383 handle, attr_id, attr_type, attr_len, p_val, *p_val); 384 } else { 385 SDP_TRACE_DEBUG( 386 "SDP_AddAttribute: handle:%X, id:%04X, type:%d, len:%d, p_val:%p, " 387 "*p_val:%s", 388 handle, attr_id, attr_type, attr_len, p_val, p_val); 389 } 390 } 391 392 /* Find the record in the database */ 393 for (zz = 0; zz < sdp_cb.server_db.num_records; zz++, p_rec++) { 394 if (p_rec->record_handle == handle) { 395 tSDP_ATTRIBUTE* p_attr = &p_rec->attribute[0]; 396 397 /* Found the record. Now, see if the attribute already exists */ 398 for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++) { 399 /* The attribute exists. replace it */ 400 if (p_attr->id == attr_id) { 401 SDP_DeleteAttribute(handle, attr_id); 402 break; 403 } 404 if (p_attr->id > attr_id) break; 405 } 406 407 if (p_rec->num_attributes == SDP_MAX_REC_ATTR) return (false); 408 409 /* If not found, see if we can allocate a new entry */ 410 if (xx == p_rec->num_attributes) 411 p_attr = &p_rec->attribute[p_rec->num_attributes]; 412 else { 413 /* Since the attributes are kept in sorted order, insert ours here */ 414 for (yy = p_rec->num_attributes; yy > xx; yy--) 415 p_rec->attribute[yy] = p_rec->attribute[yy - 1]; 416 } 417 418 p_attr->id = attr_id; 419 p_attr->type = attr_type; 420 p_attr->len = attr_len; 421 422 if (p_rec->free_pad_ptr + attr_len >= SDP_MAX_PAD_LEN) { 423 /* do truncate only for text string type descriptor */ 424 if (attr_type == TEXT_STR_DESC_TYPE) { 425 SDP_TRACE_WARNING( 426 "SDP_AddAttribute: attr_len:%d too long. truncate to (%d)", 427 attr_len, SDP_MAX_PAD_LEN - p_rec->free_pad_ptr); 428 429 attr_len = SDP_MAX_PAD_LEN - p_rec->free_pad_ptr; 430 p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr] = '\0'; 431 p_val[SDP_MAX_PAD_LEN - p_rec->free_pad_ptr + 1] = '\0'; 432 } else 433 attr_len = 0; 434 } 435 436 if ((attr_len > 0) && (p_val != 0)) { 437 p_attr->len = attr_len; 438 memcpy(&p_rec->attr_pad[p_rec->free_pad_ptr], p_val, (size_t)attr_len); 439 p_attr->value_ptr = &p_rec->attr_pad[p_rec->free_pad_ptr]; 440 p_rec->free_pad_ptr += attr_len; 441 } else if ((attr_len == 0 && 442 p_attr->len != 443 0) || /* if truncate to 0 length, simply don't add */ 444 p_val == 0) { 445 SDP_TRACE_ERROR( 446 "SDP_AddAttribute fail, length exceed maximum: ID %d: attr_len:%d ", 447 attr_id, attr_len); 448 p_attr->id = p_attr->type = p_attr->len = 0; 449 return (false); 450 } 451 p_rec->num_attributes++; 452 return (true); 453 } 454 } 455 #endif 456 return (false); 457 } 458 459 /******************************************************************************* 460 * 461 * Function SDP_AddSequence 462 * 463 * Description This function is called to add a sequence to a record. 464 * This would be through the SDP database maintenance API. 465 * If the sequence already exists in the record, it is replaced 466 * with the new sequence. 467 * 468 * NOTE Element values must be passed as a Big Endian stream. 469 * 470 * Returns true if added OK, else false 471 * 472 ******************************************************************************/ 473 bool SDP_AddSequence(uint32_t handle, uint16_t attr_id, uint16_t num_elem, 474 uint8_t type[], uint8_t len[], uint8_t* p_val[]) { 475 #if (SDP_SERVER_ENABLED == TRUE) 476 uint16_t xx; 477 uint8_t* p; 478 uint8_t* p_head; 479 bool result; 480 uint8_t* p_buff = 481 (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2); 482 483 p = p_buff; 484 485 /* First, build the sequence */ 486 for (xx = 0; xx < num_elem; xx++) { 487 p_head = p; 488 switch (len[xx]) { 489 case 1: 490 UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_ONE_BYTE); 491 break; 492 case 2: 493 UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_TWO_BYTES); 494 break; 495 case 4: 496 UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_FOUR_BYTES); 497 break; 498 case 8: 499 UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_EIGHT_BYTES); 500 break; 501 case 16: 502 UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_SIXTEEN_BYTES); 503 break; 504 default: 505 UINT8_TO_BE_STREAM(p, (type[xx] << 3) | SIZE_IN_NEXT_BYTE); 506 UINT8_TO_BE_STREAM(p, len[xx]); 507 break; 508 } 509 510 ARRAY_TO_BE_STREAM(p, p_val[xx], len[xx]); 511 512 if (p - p_buff > SDP_MAX_ATTR_LEN) { 513 /* go back to before we add this element */ 514 p = p_head; 515 if (p_head == p_buff) { 516 /* the first element exceed the max length */ 517 SDP_TRACE_ERROR("SDP_AddSequence - too long(attribute is not added)!!"); 518 osi_free(p_buff); 519 return false; 520 } else 521 SDP_TRACE_ERROR("SDP_AddSequence - too long, add %d elements of %d", xx, 522 num_elem); 523 break; 524 } 525 } 526 result = SDP_AddAttribute(handle, attr_id, DATA_ELE_SEQ_DESC_TYPE, 527 (uint32_t)(p - p_buff), p_buff); 528 osi_free(p_buff); 529 return result; 530 #else /* SDP_SERVER_ENABLED == FALSE */ 531 return (false); 532 #endif 533 } 534 535 /******************************************************************************* 536 * 537 * Function SDP_AddUuidSequence 538 * 539 * Description This function is called to add a UUID sequence to a record. 540 * This would be through the SDP database maintenance API. 541 * If the sequence already exists in the record, it is replaced 542 * with the new sequence. 543 * 544 * Returns true if added OK, else false 545 * 546 ******************************************************************************/ 547 bool SDP_AddUuidSequence(uint32_t handle, uint16_t attr_id, uint16_t num_uuids, 548 uint16_t* p_uuids) { 549 #if (SDP_SERVER_ENABLED == TRUE) 550 uint16_t xx; 551 uint8_t* p; 552 int32_t max_len = SDP_MAX_ATTR_LEN - 3; 553 bool result; 554 uint8_t* p_buff = 555 (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2); 556 557 p = p_buff; 558 559 /* First, build the sequence */ 560 for (xx = 0; xx < num_uuids; xx++, p_uuids++) { 561 UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES); 562 UINT16_TO_BE_STREAM(p, *p_uuids); 563 564 if ((p - p_buff) > max_len) { 565 SDP_TRACE_WARNING("SDP_AddUuidSequence - too long, add %d uuids of %d", 566 xx, num_uuids); 567 break; 568 } 569 } 570 571 result = SDP_AddAttribute(handle, attr_id, DATA_ELE_SEQ_DESC_TYPE, 572 (uint32_t)(p - p_buff), p_buff); 573 osi_free(p_buff); 574 return result; 575 #else /* SDP_SERVER_ENABLED == FALSE */ 576 return (false); 577 #endif 578 } 579 580 /******************************************************************************* 581 * 582 * Function SDP_AddProtocolList 583 * 584 * Description This function is called to add a protocol descriptor list to 585 * a record. This would be through the SDP database 586 * maintenance API. If the protocol list already exists in the 587 * record, it is replaced with the new list. 588 * 589 * Returns true if added OK, else false 590 * 591 ******************************************************************************/ 592 bool SDP_AddProtocolList(uint32_t handle, uint16_t num_elem, 593 tSDP_PROTOCOL_ELEM* p_elem_list) { 594 #if (SDP_SERVER_ENABLED == TRUE) 595 int offset; 596 bool result; 597 uint8_t* p_buff = 598 (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2); 599 600 offset = sdp_compose_proto_list(p_buff, num_elem, p_elem_list); 601 result = SDP_AddAttribute(handle, ATTR_ID_PROTOCOL_DESC_LIST, 602 DATA_ELE_SEQ_DESC_TYPE, (uint32_t)offset, p_buff); 603 osi_free(p_buff); 604 return result; 605 #else /* SDP_SERVER_ENABLED == FALSE */ 606 return (false); 607 #endif 608 } 609 610 /******************************************************************************* 611 * 612 * Function SDP_AddAdditionProtoLists 613 * 614 * Description This function is called to add a protocol descriptor list to 615 * a record. This would be through the SDP database maintenance 616 * API. If the protocol list already exists in the record, it 617 * is replaced with the new list. 618 * 619 * Returns true if added OK, else false 620 * 621 ******************************************************************************/ 622 bool SDP_AddAdditionProtoLists(uint32_t handle, uint16_t num_elem, 623 tSDP_PROTO_LIST_ELEM* p_proto_list) { 624 #if (SDP_SERVER_ENABLED == TRUE) 625 uint16_t xx; 626 uint8_t* p; 627 uint8_t* p_len; 628 int offset; 629 bool result; 630 uint8_t* p_buff = 631 (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2); 632 633 p = p_buff; 634 635 /* for each ProtocolDescriptorList */ 636 for (xx = 0; xx < num_elem; xx++, p_proto_list++) { 637 UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); 638 p_len = p++; 639 640 offset = sdp_compose_proto_list(p, p_proto_list->num_elems, 641 p_proto_list->list_elem); 642 p += offset; 643 644 *p_len = (uint8_t)(p - p_len - 1); 645 } 646 result = 647 SDP_AddAttribute(handle, ATTR_ID_ADDITION_PROTO_DESC_LISTS, 648 DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - p_buff), p_buff); 649 osi_free(p_buff); 650 return result; 651 652 #else /* SDP_SERVER_ENABLED == FALSE */ 653 return (false); 654 #endif 655 } 656 657 /******************************************************************************* 658 * 659 * Function SDP_AddProfileDescriptorList 660 * 661 * Description This function is called to add a profile descriptor list to 662 * a record. This would be through the SDP database maintenance 663 * API. If the version already exists in the record, it is 664 * replaced with the new one. 665 * 666 * Returns true if added OK, else false 667 * 668 ******************************************************************************/ 669 bool SDP_AddProfileDescriptorList(uint32_t handle, uint16_t profile_uuid, 670 uint16_t version) { 671 #if (SDP_SERVER_ENABLED == TRUE) 672 uint8_t* p; 673 bool result; 674 uint8_t* p_buff = (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN); 675 676 p = p_buff + 2; 677 678 /* First, build the profile descriptor list. This consists of a data element 679 * sequence. */ 680 /* The sequence consists of profile's UUID and version number */ 681 UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES); 682 UINT16_TO_BE_STREAM(p, profile_uuid); 683 684 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); 685 UINT16_TO_BE_STREAM(p, version); 686 687 /* Add in type and length fields */ 688 *p_buff = (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); 689 *(p_buff + 1) = (uint8_t)(p - (p_buff + 2)); 690 691 result = 692 SDP_AddAttribute(handle, ATTR_ID_BT_PROFILE_DESC_LIST, 693 DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - p_buff), p_buff); 694 osi_free(p_buff); 695 return result; 696 697 #else /* SDP_SERVER_ENABLED == FALSE */ 698 return (false); 699 #endif 700 } 701 702 /******************************************************************************* 703 * 704 * Function SDP_AddLanguageBaseAttrIDList 705 * 706 * Description This function is called to add a language base attr list to 707 * a record. This would be through the SDP database maintenance 708 * API. If the version already exists in the record, it is 709 * replaced with the new one. 710 * 711 * Returns true if added OK, else false 712 * 713 ******************************************************************************/ 714 bool SDP_AddLanguageBaseAttrIDList(uint32_t handle, uint16_t lang, 715 uint16_t char_enc, uint16_t base_id) { 716 #if (SDP_SERVER_ENABLED == TRUE) 717 uint8_t* p; 718 bool result; 719 uint8_t* p_buff = (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN); 720 721 p = p_buff; 722 723 /* First, build the language base descriptor list. This consists of a data */ 724 /* element sequence. The sequence consists of 9 bytes (3 UINt16 fields) */ 725 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); 726 UINT16_TO_BE_STREAM(p, lang); 727 728 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); 729 UINT16_TO_BE_STREAM(p, char_enc); 730 731 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); 732 UINT16_TO_BE_STREAM(p, base_id); 733 734 result = 735 SDP_AddAttribute(handle, ATTR_ID_LANGUAGE_BASE_ATTR_ID_LIST, 736 DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - p_buff), p_buff); 737 osi_free(p_buff); 738 return result; 739 #else /* SDP_SERVER_ENABLED == FALSE */ 740 return (false); 741 #endif 742 } 743 744 /******************************************************************************* 745 * 746 * Function SDP_AddServiceClassIdList 747 * 748 * Description This function is called to add a service list to a record. 749 * This would be through the SDP database maintenance API. 750 * If the service list already exists in the record, it is 751 * replaced with the new list. 752 * 753 * Returns true if added OK, else false 754 * 755 ******************************************************************************/ 756 bool SDP_AddServiceClassIdList(uint32_t handle, uint16_t num_services, 757 uint16_t* p_service_uuids) { 758 #if (SDP_SERVER_ENABLED == TRUE) 759 uint16_t xx; 760 uint8_t* p; 761 bool result; 762 uint8_t* p_buff = 763 (uint8_t*)osi_malloc(sizeof(uint8_t) * SDP_MAX_ATTR_LEN * 2); 764 765 p = p_buff; 766 767 for (xx = 0; xx < num_services; xx++, p_service_uuids++) { 768 UINT8_TO_BE_STREAM(p, (UUID_DESC_TYPE << 3) | SIZE_TWO_BYTES); 769 UINT16_TO_BE_STREAM(p, *p_service_uuids); 770 } 771 772 result = 773 SDP_AddAttribute(handle, ATTR_ID_SERVICE_CLASS_ID_LIST, 774 DATA_ELE_SEQ_DESC_TYPE, (uint32_t)(p - p_buff), p_buff); 775 osi_free(p_buff); 776 return result; 777 #else /* SDP_SERVER_ENABLED == FALSE */ 778 return (false); 779 #endif 780 } 781 782 /******************************************************************************* 783 * 784 * Function SDP_DeleteAttribute 785 * 786 * Description This function is called to delete an attribute from a 787 * record. This would be through the SDP database maintenance 788 * API. 789 * 790 * Returns true if deleted OK, else false if not found 791 * 792 ******************************************************************************/ 793 bool SDP_DeleteAttribute(uint32_t handle, uint16_t attr_id) { 794 #if (SDP_SERVER_ENABLED == TRUE) 795 uint16_t xx, yy; 796 tSDP_RECORD* p_rec = &sdp_cb.server_db.record[0]; 797 uint8_t* pad_ptr; 798 uint32_t len; /* Number of bytes in the entry */ 799 800 /* Find the record in the database */ 801 for (xx = 0; xx < sdp_cb.server_db.num_records; xx++, p_rec++) { 802 if (p_rec->record_handle == handle) { 803 tSDP_ATTRIBUTE* p_attr = &p_rec->attribute[0]; 804 805 SDP_TRACE_API("Deleting attr_id 0x%04x for handle 0x%x", attr_id, handle); 806 /* Found it. Now, find the attribute */ 807 for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++) { 808 if (p_attr->id == attr_id) { 809 pad_ptr = p_attr->value_ptr; 810 len = p_attr->len; 811 812 if (len) { 813 for (yy = 0; yy < p_rec->num_attributes; yy++) { 814 if (p_rec->attribute[yy].value_ptr > pad_ptr) 815 p_rec->attribute[yy].value_ptr -= len; 816 } 817 } 818 819 /* Found it. Shift everything up one */ 820 p_rec->num_attributes--; 821 822 for (yy = xx; yy < p_rec->num_attributes; yy++, p_attr++) { 823 *p_attr = *(p_attr + 1); 824 } 825 826 /* adjust attribute values if needed */ 827 if (len) { 828 xx = 829 (p_rec->free_pad_ptr - ((pad_ptr + len) - &p_rec->attr_pad[0])); 830 for (yy = 0; yy < xx; yy++, pad_ptr++) *pad_ptr = *(pad_ptr + len); 831 p_rec->free_pad_ptr -= len; 832 } 833 return (true); 834 } 835 } 836 } 837 } 838 #endif 839 /* If here, not found */ 840 return (false); 841 } 842 843 /******************************************************************************* 844 * 845 * Function SDP_ReadRecord 846 * 847 * Description This function is called to get the raw data of the record 848 * with the given handle from the database. 849 * 850 * Returns -1, if the record is not found. 851 * Otherwise, the offset (0 or 1) to start of data in p_data. 852 * 853 * The size of data copied into p_data is in *p_data_len. 854 * 855 ******************************************************************************/ 856 #if (SDP_RAW_DATA_INCLUDED == TRUE) 857 int32_t SDP_ReadRecord(uint32_t handle, uint8_t* p_data, int32_t* p_data_len) { 858 int32_t len = 0; /* Number of bytes in the entry */ 859 int32_t offset = -1; /* default to not found */ 860 #if (SDP_SERVER_ENABLED == TRUE) 861 tSDP_RECORD* p_rec; 862 uint16_t start = 0; 863 uint16_t end = 0xffff; 864 tSDP_ATTRIBUTE* p_attr; 865 uint16_t rem_len; 866 uint8_t* p_rsp; 867 868 /* Find the record in the database */ 869 p_rec = sdp_db_find_record(handle); 870 if (p_rec && p_data && p_data_len) { 871 p_rsp = &p_data[3]; 872 while ((p_attr = sdp_db_find_attr_in_rec(p_rec, start, end)) != NULL) { 873 /* Check if attribute fits. Assume 3-byte value type/length */ 874 rem_len = *p_data_len - (uint16_t)(p_rsp - p_data); 875 876 if (p_attr->len > (uint32_t)(rem_len - 6)) break; 877 878 p_rsp = sdpu_build_attrib_entry(p_rsp, p_attr); 879 880 /* next attr id */ 881 start = p_attr->id + 1; 882 } 883 len = (int32_t)(p_rsp - p_data); 884 885 /* Put in the sequence header (2 or 3 bytes) */ 886 if (len > 255) { 887 offset = 0; 888 p_data[0] = (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD); 889 p_data[1] = (uint8_t)((len - 3) >> 8); 890 p_data[2] = (uint8_t)(len - 3); 891 } else { 892 offset = 1; 893 894 p_data[1] = (uint8_t)((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); 895 p_data[2] = (uint8_t)(len - 3); 896 897 len--; 898 } 899 *p_data_len = len; 900 } 901 #endif 902 /* If here, not found */ 903 return (offset); 904 } 905 #endif 906