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 interface functions 22 * 23 ******************************************************************************/ 24 25 #include <stdlib.h> 26 #include <string.h> 27 #include <stdio.h> 28 29 #include "bt_target.h" 30 #include "bt_utils.h" 31 #include "gki.h" 32 #include "l2cdefs.h" 33 #include "hcidefs.h" 34 #include "hcimsgs.h" 35 36 #include "sdp_api.h" 37 #include "sdpint.h" 38 #include "btu.h" 39 40 /********************************************************************** 41 ** C L I E N T F U N C T I O N P R O T O T Y P E S * 42 ***********************************************************************/ 43 44 /******************************************************************************* 45 ** 46 ** Function SDP_InitDiscoveryDb 47 ** 48 ** Description This function is called to initialize a discovery database. 49 ** 50 ** Parameters: p_db - (input) address of an area of memory where the 51 ** discovery database is managed. 52 ** len - (input) size (in bytes) of the memory 53 ** NOTE: This must be larger than sizeof(tSDP_DISCOVERY_DB) 54 ** num_uuid - (input) number of UUID filters applied 55 ** p_uuid_list - (input) list of UUID filters 56 ** num_attr - (input) number of attribute filters applied 57 ** p_attr_list - (input) list of attribute filters 58 ** 59 ** 60 ** Returns BOOLEAN 61 ** TRUE if successful 62 ** FALSE if one or more parameters are bad 63 ** 64 *******************************************************************************/ 65 BOOLEAN SDP_InitDiscoveryDb (tSDP_DISCOVERY_DB *p_db, UINT32 len, UINT16 num_uuid, 66 tSDP_UUID *p_uuid_list, UINT16 num_attr, UINT16 *p_attr_list) 67 { 68 #if SDP_CLIENT_ENABLED == TRUE 69 UINT16 xx; 70 71 /* verify the parameters */ 72 if (p_db == NULL || (sizeof (tSDP_DISCOVERY_DB) > len) || 73 num_attr > SDP_MAX_ATTR_FILTERS || num_uuid > SDP_MAX_UUID_FILTERS) 74 { 75 SDP_TRACE_ERROR("SDP_InitDiscoveryDb Illegal param: p_db 0x%x, len %d, num_uuid %d, num_attr %d", 76 (UINT32)p_db, len, num_uuid, num_attr); 77 78 return(FALSE); 79 } 80 81 memset (p_db, 0, (size_t)len); 82 83 p_db->mem_size = len - sizeof (tSDP_DISCOVERY_DB); 84 p_db->mem_free = p_db->mem_size; 85 p_db->p_first_rec = NULL; 86 p_db->p_free_mem = (UINT8 *)(p_db + 1); 87 88 for (xx = 0; xx < num_uuid; xx++) 89 p_db->uuid_filters[xx] = *p_uuid_list++; 90 91 p_db->num_uuid_filters = num_uuid; 92 93 for (xx = 0; xx < num_attr; xx++) 94 p_db->attr_filters[xx] = *p_attr_list++; 95 96 /* sort attributes */ 97 sdpu_sort_attr_list( num_attr, p_db ); 98 99 p_db->num_attr_filters = num_attr; 100 #endif 101 return(TRUE); 102 } 103 104 105 106 /******************************************************************************* 107 ** 108 ** Function SDP_CancelServiceSearch 109 ** 110 ** Description This function cancels an active query to an SDP server. 111 ** 112 ** Returns TRUE if discovery cancelled, FALSE if a matching activity is not found. 113 ** 114 *******************************************************************************/ 115 BOOLEAN SDP_CancelServiceSearch (tSDP_DISCOVERY_DB *p_db) 116 { 117 #if SDP_CLIENT_ENABLED == TRUE 118 tCONN_CB *p_ccb = sdpu_find_ccb_by_db (p_db); 119 if (!p_ccb) 120 return(FALSE); 121 122 sdp_disconnect (p_ccb, SDP_CANCEL); 123 p_ccb->disc_state = SDP_DISC_WAIT_CANCEL; 124 #endif 125 return(TRUE); 126 } 127 128 129 130 /******************************************************************************* 131 ** 132 ** Function SDP_ServiceSearchRequest 133 ** 134 ** Description This function queries an SDP server for information. 135 ** 136 ** Returns TRUE if discovery started, FALSE if failed. 137 ** 138 *******************************************************************************/ 139 BOOLEAN SDP_ServiceSearchRequest (UINT8 *p_bd_addr, tSDP_DISCOVERY_DB *p_db, 140 tSDP_DISC_CMPL_CB *p_cb) 141 { 142 #if SDP_CLIENT_ENABLED == TRUE 143 tCONN_CB *p_ccb; 144 145 /* Specific BD address */ 146 p_ccb = sdp_conn_originate (p_bd_addr); 147 148 if (!p_ccb) 149 return(FALSE); 150 151 p_ccb->disc_state = SDP_DISC_WAIT_CONN; 152 p_ccb->p_db = p_db; 153 p_ccb->p_cb = p_cb; 154 155 return(TRUE); 156 #else 157 return(FALSE); 158 #endif 159 } 160 161 162 /******************************************************************************* 163 ** 164 ** Function SDP_ServiceSearchAttributeRequest 165 ** 166 ** Description This function queries an SDP server for information. 167 ** 168 ** The difference between this API function and the function 169 ** SDP_ServiceSearchRequest is that this one does a 170 ** combined ServiceSearchAttributeRequest SDP function. 171 ** (This is for Unplug Testing) 172 ** 173 ** Returns TRUE if discovery started, FALSE if failed. 174 ** 175 *******************************************************************************/ 176 BOOLEAN SDP_ServiceSearchAttributeRequest (UINT8 *p_bd_addr, tSDP_DISCOVERY_DB *p_db, 177 tSDP_DISC_CMPL_CB *p_cb) 178 { 179 #if SDP_CLIENT_ENABLED == TRUE 180 tCONN_CB *p_ccb; 181 182 /* Specific BD address */ 183 p_ccb = sdp_conn_originate (p_bd_addr); 184 185 if (!p_ccb) 186 return(FALSE); 187 188 p_ccb->disc_state = SDP_DISC_WAIT_CONN; 189 p_ccb->p_db = p_db; 190 p_ccb->p_cb = p_cb; 191 192 p_ccb->is_attr_search = TRUE; 193 194 return(TRUE); 195 #else 196 return(FALSE); 197 #endif 198 } 199 /******************************************************************************* 200 ** 201 ** Function SDP_ServiceSearchAttributeRequest2 202 ** 203 ** Description This function queries an SDP server for information. 204 ** 205 ** The difference between this API function and the function 206 ** SDP_ServiceSearchRequest is that this one does a 207 ** combined ServiceSearchAttributeRequest SDP function. 208 ** (This is for Unplug Testing) 209 ** 210 ** Returns TRUE if discovery started, FALSE if failed. 211 ** 212 *******************************************************************************/ 213 BOOLEAN SDP_ServiceSearchAttributeRequest2 (UINT8 *p_bd_addr, tSDP_DISCOVERY_DB *p_db, 214 tSDP_DISC_CMPL_CB2 *p_cb2, void * user_data) 215 { 216 #if SDP_CLIENT_ENABLED == TRUE 217 tCONN_CB *p_ccb; 218 219 /* Specific BD address */ 220 p_ccb = sdp_conn_originate (p_bd_addr); 221 222 if (!p_ccb) 223 return(FALSE); 224 225 p_ccb->disc_state = SDP_DISC_WAIT_CONN; 226 p_ccb->p_db = p_db; 227 p_ccb->p_cb2 = p_cb2; 228 229 p_ccb->is_attr_search = TRUE; 230 p_ccb->user_data = user_data; 231 232 return(TRUE); 233 #else 234 return(FALSE); 235 #endif 236 } 237 238 #if SDP_CLIENT_ENABLED == TRUE 239 void SDP_SetIdleTimeout (BD_ADDR addr, UINT16 timeout) 240 { 241 UNUSED(addr); 242 UNUSED(timeout); 243 } 244 #endif 245 246 /******************************************************************************* 247 ** 248 ** Function SDP_FindAttributeInDb 249 ** 250 ** Description This function queries an SDP database for a specific attribute. 251 ** If the p_start_rec pointer is NULL, it looks from the beginning 252 ** of the database, else it continues from the next record after 253 ** p_start_rec. 254 ** 255 ** Returns Pointer to matching record, or NULL 256 ** 257 *******************************************************************************/ 258 tSDP_DISC_REC *SDP_FindAttributeInDb (tSDP_DISCOVERY_DB *p_db, UINT16 attr_id, 259 tSDP_DISC_REC *p_start_rec) 260 { 261 #if SDP_CLIENT_ENABLED == TRUE 262 tSDP_DISC_REC *p_rec; 263 tSDP_DISC_ATTR *p_attr; 264 265 /* Must have a valid database */ 266 if (p_db == NULL) 267 return(NULL); 268 269 if (!p_start_rec) 270 p_rec = p_db->p_first_rec; 271 else 272 p_rec = p_start_rec->p_next_rec; 273 274 while (p_rec) 275 { 276 p_attr = p_rec->p_first_attr; 277 while (p_attr) 278 { 279 if (p_attr->attr_id == attr_id) 280 return(p_rec); 281 282 p_attr = p_attr->p_next_attr; 283 } 284 285 p_rec = p_rec->p_next_rec; 286 } 287 #endif 288 /* If here, no matching attribute found */ 289 return(NULL); 290 } 291 292 293 /******************************************************************************* 294 ** 295 ** Function SDP_FindAttributeInRec 296 ** 297 ** Description This function searches an SDP discovery record for a specific 298 ** attribute. 299 ** 300 ** Returns Pointer to matching attribute entry, or NULL 301 ** 302 *******************************************************************************/ 303 tSDP_DISC_ATTR *SDP_FindAttributeInRec (tSDP_DISC_REC *p_rec, UINT16 attr_id) 304 { 305 #if SDP_CLIENT_ENABLED == TRUE 306 tSDP_DISC_ATTR *p_attr; 307 308 p_attr = p_rec->p_first_attr; 309 while (p_attr) 310 { 311 if (p_attr->attr_id == attr_id) 312 return(p_attr); 313 314 p_attr = p_attr->p_next_attr; 315 } 316 #endif 317 /* If here, no matching attribute found */ 318 return(NULL); 319 } 320 321 /******************************************************************************* 322 ** 323 ** Function SDP_FindServiceUUIDInRec 324 ** 325 ** Description This function is called to read the service UUID within a record 326 ** if there is any. 327 ** 328 ** Parameters: p_rec - pointer to a SDP record. 329 ** p_uuid - output parameter to save the UUID found. 330 ** 331 ** Returns TRUE if found, otherwise FALSE. 332 ** 333 *******************************************************************************/ 334 BOOLEAN SDP_FindServiceUUIDInRec(tSDP_DISC_REC *p_rec, tBT_UUID * p_uuid) 335 { 336 #if SDP_CLIENT_ENABLED == TRUE 337 tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr; 338 339 p_attr = p_rec->p_first_attr; 340 341 while (p_attr) 342 { 343 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) 344 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) 345 { 346 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 347 { 348 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) 349 { 350 if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_16) 351 { 352 p_uuid->len = LEN_UUID_16; 353 p_uuid->uu.uuid16 = p_sattr->attr_value.v.u16; 354 } 355 else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_128) 356 { 357 p_uuid->len = LEN_UUID_128; 358 memcpy(p_uuid->uu.uuid128, p_sattr->attr_value.v.array, LEN_UUID_128); 359 } 360 else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_32) 361 { 362 p_uuid->len = LEN_UUID_32; 363 p_uuid->uu.uuid32 = p_sattr->attr_value.v.u32; 364 } 365 366 return(TRUE); 367 } 368 369 /* Checking for Toyota G Block Car Kit: 370 ** This car kit puts an extra data element sequence 371 ** where the UUID is suppose to be!!! 372 */ 373 else 374 { 375 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE) 376 { 377 /* Look through data element sequence until no more UUIDs */ 378 for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr) 379 { 380 /* Increment past this to see if the next attribut is UUID */ 381 if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE) 382 /* only support 16 bits UUID for now */ 383 && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2)) 384 { 385 p_uuid->len = 2; 386 p_uuid->uu.uuid16 = p_extra_sattr->attr_value.v.u16; 387 return(TRUE); 388 } 389 } 390 } 391 } 392 } 393 break; 394 } 395 else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) 396 { 397 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) 398 /* only support 16 bits UUID for now */ 399 && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2)) 400 { 401 p_uuid->len = 2; 402 p_uuid->uu.uuid16 = p_attr->attr_value.v.u16; 403 return(TRUE); 404 } 405 } 406 p_attr = p_attr->p_next_attr; 407 } 408 return FALSE; 409 #endif 410 } 411 412 /******************************************************************************* 413 ** 414 ** Function SDP_FindServiceUUIDInRec_128bit 415 ** 416 ** Description This function is called to read the 128-bit service UUID within a record 417 ** if there is any. 418 ** 419 ** Parameters: p_rec - pointer to a SDP record. 420 ** p_uuid - output parameter to save the UUID found. 421 ** 422 ** Returns TRUE if found, otherwise FALSE. 423 ** 424 *******************************************************************************/ 425 BOOLEAN SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC *p_rec, tBT_UUID * p_uuid) 426 { 427 #if SDP_CLIENT_ENABLED == TRUE 428 tSDP_DISC_ATTR *p_attr, *p_sattr; 429 430 p_attr = p_rec->p_first_attr; 431 432 while (p_attr) 433 { 434 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) 435 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) 436 { 437 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 438 { 439 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) 440 { 441 /* only support 128 bits UUID for now */ 442 if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16) 443 { 444 p_uuid->len = 16; 445 memcpy(p_uuid->uu.uuid128, p_sattr->attr_value.v.array, MAX_UUID_SIZE); 446 } 447 return(TRUE); 448 } 449 } 450 break; 451 } 452 else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) 453 { 454 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) 455 /* only support 128 bits UUID for now */ 456 && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16)) 457 { 458 p_uuid->len = 16; 459 memcpy(p_uuid->uu.uuid128, p_attr->attr_value.v.array, MAX_UUID_SIZE); 460 return(TRUE); 461 } 462 } 463 p_attr = p_attr->p_next_attr; 464 } 465 return FALSE; 466 #endif 467 } 468 469 /******************************************************************************* 470 ** 471 ** Function SDP_FindServiceInDb 472 ** 473 ** Description This function queries an SDP database for a specific service. 474 ** If the p_start_rec pointer is NULL, it looks from the beginning 475 ** of the database, else it continues from the next record after 476 ** p_start_rec. 477 ** 478 ** Returns Pointer to record containing service class, or NULL 479 ** 480 *******************************************************************************/ 481 tSDP_DISC_REC *SDP_FindServiceInDb (tSDP_DISCOVERY_DB *p_db, UINT16 service_uuid, tSDP_DISC_REC *p_start_rec) 482 { 483 #if SDP_CLIENT_ENABLED == TRUE 484 tSDP_DISC_REC *p_rec; 485 tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr; 486 487 /* Must have a valid database */ 488 if (p_db == NULL) 489 return(NULL); 490 491 if (!p_start_rec) 492 p_rec = p_db->p_first_rec; 493 else 494 p_rec = p_start_rec->p_next_rec; 495 496 while (p_rec) 497 { 498 p_attr = p_rec->p_first_attr; 499 while (p_attr) 500 { 501 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) 502 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) 503 { 504 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 505 { 506 507 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) 508 && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) ) { 509 SDP_TRACE_DEBUG("SDP_FindServiceInDb - p_sattr value = 0x%x serviceuuid = 0x%x\r\n", 510 p_sattr->attr_value.v.u16, service_uuid); 511 if(service_uuid == UUID_SERVCLASS_HDP_PROFILE) 512 { 513 if( (p_sattr->attr_value.v.u16==UUID_SERVCLASS_HDP_SOURCE) || ( p_sattr->attr_value.v.u16==UUID_SERVCLASS_HDP_SINK)) 514 { 515 SDP_TRACE_DEBUG("SDP_FindServiceInDb found HDP source or sink\n" ); 516 return (p_rec); 517 } 518 } 519 520 } 521 522 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE && (service_uuid == 0 523 || (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2 524 && p_sattr->attr_value.v.u16 == service_uuid))) 525 /* for a specific uuid, or any one */ 526 { 527 return(p_rec); 528 } 529 530 /* Checking for Toyota G Block Car Kit: 531 ** This car kit puts an extra data element sequence 532 ** where the UUID is suppose to be!!! 533 */ 534 else 535 { 536 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE) 537 { 538 /* Look through data element sequence until no more UUIDs */ 539 for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr) 540 { 541 /* Increment past this to see if the next attribut is UUID */ 542 if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE) 543 && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2) 544 /* for a specific uuid, or any one */ 545 && ((p_extra_sattr->attr_value.v.u16 == service_uuid) || (service_uuid == 0))) 546 { 547 return(p_rec); 548 } 549 } 550 } 551 } 552 } 553 break; 554 } 555 else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) 556 { 557 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) 558 && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2) 559 /* find a specific UUID or anyone */ 560 && ((p_attr->attr_value.v.u16 == service_uuid) || service_uuid == 0)) 561 return(p_rec); 562 } 563 564 p_attr = p_attr->p_next_attr; 565 } 566 567 p_rec = p_rec->p_next_rec; 568 } 569 #endif 570 /* If here, no matching UUID found */ 571 return(NULL); 572 } 573 574 /******************************************************************************* 575 ** 576 ** Function SDP_FindServiceInDb_128bit 577 ** 578 ** Description This function queries an SDP database for a specific service. 579 ** If the p_start_rec pointer is NULL, it looks from the beginning 580 ** of the database, else it continues from the next record after 581 ** p_start_rec. 582 ** 583 ** This function is kept separate from SDP_FindServiceInDb since 584 ** that API is expected to return only 16-bit UUIDs 585 ** 586 ** Returns Pointer to record containing service class, or NULL 587 ** 588 *******************************************************************************/ 589 tSDP_DISC_REC *SDP_FindServiceInDb_128bit(tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_start_rec) 590 { 591 #if SDP_CLIENT_ENABLED == TRUE 592 tSDP_DISC_REC *p_rec; 593 tSDP_DISC_ATTR *p_attr, *p_sattr; 594 595 /* Must have a valid database */ 596 if (p_db == NULL) 597 return(NULL); 598 599 if (!p_start_rec) 600 p_rec = p_db->p_first_rec; 601 else 602 p_rec = p_start_rec->p_next_rec; 603 604 while (p_rec) 605 { 606 p_attr = p_rec->p_first_attr; 607 while (p_attr) 608 { 609 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) 610 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) 611 { 612 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 613 { 614 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) 615 && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16)) 616 { 617 return(p_rec); 618 } 619 } 620 break; 621 } 622 else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) 623 { 624 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) 625 && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16)) 626 return(p_rec); 627 } 628 629 p_attr = p_attr->p_next_attr; 630 } 631 632 p_rec = p_rec->p_next_rec; 633 } 634 #endif 635 /* If here, no matching UUID found */ 636 return(NULL); 637 } 638 639 640 /******************************************************************************* 641 ** 642 ** Function SDP_FindServiceUUIDInDb 643 ** 644 ** Description This function queries an SDP database for a specific service. 645 ** If the p_start_rec pointer is NULL, it looks from the beginning 646 ** of the database, else it continues from the next record after 647 ** p_start_rec. 648 ** 649 ** NOTE the only difference between this function and the previous function 650 ** "SDP_FindServiceInDb()" is that this function takes a tBT_UUID input 651 ** 652 ** Returns Pointer to record containing service class, or NULL 653 ** 654 *******************************************************************************/ 655 tSDP_DISC_REC *SDP_FindServiceUUIDInDb (tSDP_DISCOVERY_DB *p_db, tBT_UUID *p_uuid, tSDP_DISC_REC *p_start_rec) 656 { 657 #if SDP_CLIENT_ENABLED == TRUE 658 tSDP_DISC_REC *p_rec; 659 tSDP_DISC_ATTR *p_attr, *p_sattr; 660 661 /* Must have a valid database */ 662 if (p_db == NULL) 663 return(NULL); 664 665 if (!p_start_rec) 666 p_rec = p_db->p_first_rec; 667 else 668 p_rec = p_start_rec->p_next_rec; 669 670 while (p_rec) 671 { 672 p_attr = p_rec->p_first_attr; 673 while (p_attr) 674 { 675 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) 676 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) 677 { 678 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 679 { 680 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) 681 { 682 if (sdpu_compare_uuid_with_attr (p_uuid, p_sattr)) 683 return(p_rec); 684 } 685 } 686 break; 687 } 688 else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) 689 { 690 if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE ) 691 { 692 if (sdpu_compare_uuid_with_attr (p_uuid, p_attr)) 693 return(p_rec); 694 } 695 } 696 697 p_attr = p_attr->p_next_attr; 698 } 699 700 p_rec = p_rec->p_next_rec; 701 } 702 #endif /* CLIENT_ENABLED == TRUE */ 703 /* If here, no matching UUID found */ 704 return(NULL); 705 } 706 707 #if SDP_CLIENT_ENABLED == TRUE 708 /******************************************************************************* 709 ** 710 ** Function sdp_fill_proto_elem 711 ** 712 ** Description This function retrieves the protocol element. 713 ** 714 ** Returns TRUE if found, FALSE if not 715 ** If found, the passed protocol list element is filled in. 716 ** 717 *******************************************************************************/ 718 static BOOLEAN sdp_fill_proto_elem( tSDP_DISC_ATTR *p_attr, UINT16 layer_uuid, 719 tSDP_PROTOCOL_ELEM *p_elem) 720 { 721 tSDP_DISC_ATTR *p_sattr; 722 723 /* Walk through the protocol descriptor list */ 724 for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr) 725 { 726 /* Safety check - each entry should itself be a sequence */ 727 if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) 728 return(FALSE); 729 730 /* Now, see if the entry contains the layer we are interested in */ 731 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 732 { 733 /* SDP_TRACE_DEBUG ("SDP - p_sattr 0x%x, layer_uuid:0x%x, u16:0x%x####", 734 p_sattr, layer_uuid, p_sattr->attr_value.v.u16); */ 735 736 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) 737 && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) 738 && (p_sattr->attr_value.v.u16 == layer_uuid)) 739 { 740 /* Bingo. Now fill in the passed element */ 741 p_elem->protocol_uuid = layer_uuid; 742 p_elem->num_params = 0; 743 744 /* Store the parameters, if any */ 745 for (p_sattr = p_sattr->p_next_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 746 { 747 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) != UINT_DESC_TYPE) 748 break; 749 750 if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) 751 p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u16; 752 else 753 p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u8; 754 755 if (p_elem->num_params >= SDP_MAX_PROTOCOL_PARAMS) 756 break; 757 } 758 return(TRUE); 759 } 760 } 761 } 762 763 return(FALSE); 764 } 765 #endif /* CLIENT_ENABLED == TRUE */ 766 767 /******************************************************************************* 768 ** 769 ** Function SDP_FindProtocolListElemInRec 770 ** 771 ** Description This function looks at a specific discovery record for a protocol 772 ** list element. 773 ** 774 ** Returns TRUE if found, FALSE if not 775 ** If found, the passed protocol list element is filled in. 776 ** 777 *******************************************************************************/ 778 BOOLEAN SDP_FindProtocolListElemInRec (tSDP_DISC_REC *p_rec, UINT16 layer_uuid, tSDP_PROTOCOL_ELEM *p_elem) 779 { 780 #if SDP_CLIENT_ENABLED == TRUE 781 tSDP_DISC_ATTR *p_attr; 782 783 p_attr = p_rec->p_first_attr; 784 while (p_attr) 785 { 786 /* Find the protocol descriptor list */ 787 if ((p_attr->attr_id == ATTR_ID_PROTOCOL_DESC_LIST) 788 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) 789 { 790 return sdp_fill_proto_elem(p_attr, layer_uuid, p_elem); 791 } 792 p_attr = p_attr->p_next_attr; 793 } 794 #endif 795 /* If here, no match found */ 796 return(FALSE); 797 } 798 799 800 /******************************************************************************* 801 ** 802 ** Function SDP_FindAddProtoListsElemInRec 803 ** 804 ** Description This function looks at a specific discovery record for a protocol 805 ** list element. 806 ** 807 ** Returns TRUE if found, FALSE if not 808 ** If found, the passed protocol list element is filled in. 809 ** 810 *******************************************************************************/ 811 BOOLEAN SDP_FindAddProtoListsElemInRec (tSDP_DISC_REC *p_rec, UINT16 layer_uuid, tSDP_PROTOCOL_ELEM *p_elem) 812 { 813 #if SDP_CLIENT_ENABLED == TRUE 814 tSDP_DISC_ATTR *p_attr, *p_sattr; 815 BOOLEAN ret = FALSE; 816 817 p_attr = p_rec->p_first_attr; 818 while (p_attr) 819 { 820 /* Find the additional protocol descriptor list attribute */ 821 if ((p_attr->attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS) 822 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) 823 { 824 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 825 { 826 /* Safety check - each entry should itself be a sequence */ 827 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE) 828 { 829 if ( (ret = sdp_fill_proto_elem(p_sattr, layer_uuid, p_elem)) == TRUE) 830 break; 831 } 832 } 833 return ret; 834 } 835 p_attr = p_attr->p_next_attr; 836 } 837 #endif 838 /* If here, no match found */ 839 return(FALSE); 840 } 841 842 843 /******************************************************************************* 844 ** 845 ** Function SDP_FindProfileVersionInRec 846 ** 847 ** Description This function looks at a specific discovery record for the 848 ** Profile list descriptor, and pulls out the version number. 849 ** The version number consists of an 8-bit major version and 850 ** an 8-bit minor version. 851 ** 852 ** Returns TRUE if found, FALSE if not 853 ** If found, the major and minor version numbers that were passed 854 ** in are filled in. 855 ** 856 *******************************************************************************/ 857 BOOLEAN SDP_FindProfileVersionInRec (tSDP_DISC_REC *p_rec, UINT16 profile_uuid, UINT16 *p_version) 858 { 859 #if SDP_CLIENT_ENABLED == TRUE 860 tSDP_DISC_ATTR *p_attr, *p_sattr; 861 862 p_attr = p_rec->p_first_attr; 863 while (p_attr) 864 { 865 /* Find the profile descriptor list */ 866 if ((p_attr->attr_id == ATTR_ID_BT_PROFILE_DESC_LIST) 867 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) 868 { 869 /* Walk through the protocol descriptor list */ 870 for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr) 871 { 872 /* Safety check - each entry should itself be a sequence */ 873 if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) 874 return(FALSE); 875 876 /* Now, see if the entry contains the profile UUID we are interested in */ 877 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 878 { 879 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) 880 && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) /* <- This is bytes, not size code! */ 881 && (p_sattr->attr_value.v.u16 == profile_uuid)) 882 { 883 /* Now fill in the major and minor numbers */ 884 /* if the attribute matches the description for version (type UINT, size 2 bytes) */ 885 p_sattr = p_sattr->p_next_attr; 886 887 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UINT_DESC_TYPE) && 888 (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)) 889 { 890 /* The high order 8 bits is the major number, low order is the minor number (big endian) */ 891 *p_version = p_sattr->attr_value.v.u16; 892 893 return(TRUE); 894 } 895 else 896 return(FALSE); /* The type and/or size was not valid for the profile list version */ 897 } 898 } 899 } 900 901 return(FALSE); 902 } 903 p_attr = p_attr->p_next_attr; 904 } 905 #endif /* CLIENT_ENABLED == TRUE */ 906 907 /* If here, no match found */ 908 return(FALSE); 909 } 910 911 /******************************************************************************* 912 ** Device Identification (DI) Client Functions 913 *******************************************************************************/ 914 915 /******************************************************************************* 916 ** 917 ** Function SDP_DiDiscover 918 ** 919 ** Description This function queries a remote device for DI information. 920 ** 921 ** Returns SDP_SUCCESS if query started successfully, else error 922 ** 923 *******************************************************************************/ 924 UINT16 SDP_DiDiscover( BD_ADDR remote_device, tSDP_DISCOVERY_DB *p_db, 925 UINT32 len, tSDP_DISC_CMPL_CB *p_cb ) 926 { 927 #if SDP_CLIENT_ENABLED == TRUE 928 UINT16 result = SDP_DI_DISC_FAILED; 929 UINT16 num_uuids = 1; 930 UINT16 di_uuid = UUID_SERVCLASS_PNP_INFORMATION; 931 932 /* build uuid for db init */ 933 tSDP_UUID init_uuid; 934 init_uuid.len = 2; 935 init_uuid.uu.uuid16 = di_uuid; 936 937 if ( SDP_InitDiscoveryDb(p_db, len, num_uuids, &init_uuid, 0, NULL) ) 938 if ( SDP_ServiceSearchRequest(remote_device, p_db, p_cb) ) 939 result = SDP_SUCCESS; 940 941 return result; 942 #else 943 return SDP_DI_DISC_FAILED; 944 #endif 945 } 946 947 /******************************************************************************* 948 ** 949 ** Function SDP_GetNumDiRecords 950 ** 951 ** Description Searches specified database for DI records 952 ** 953 ** Returns number of DI records found 954 ** 955 *******************************************************************************/ 956 UINT8 SDP_GetNumDiRecords( tSDP_DISCOVERY_DB *p_db ) 957 { 958 #if SDP_CLIENT_ENABLED == TRUE 959 UINT8 num_records = 0; 960 tSDP_DISC_REC *p_curr_record = NULL; 961 962 do 963 { 964 p_curr_record = SDP_FindServiceInDb( p_db, UUID_SERVCLASS_PNP_INFORMATION, 965 p_curr_record ); 966 if ( p_curr_record ) 967 num_records++; 968 }while ( p_curr_record ); 969 970 return num_records; 971 #else 972 return 0; 973 #endif 974 } 975 976 /******************************************************************************* 977 ** 978 ** Function SDP_AttrStringCopy 979 ** 980 ** Description This function copy given attribute to specified buffer as a string 981 ** 982 ** Returns none 983 ** 984 *******************************************************************************/ 985 static void SDP_AttrStringCopy(char *dst, tSDP_DISC_ATTR *p_attr, UINT16 dst_size) 986 { 987 if ( dst == NULL ) return; 988 if ( p_attr ) 989 { 990 UINT16 len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type); 991 if ( len > dst_size - 1 ) 992 { 993 len = dst_size - 1; 994 } 995 memcpy(dst, (char *)p_attr->attr_value.v.array, len); 996 dst[len] = '\0'; 997 } 998 else 999 { 1000 dst[0] = '\0'; 1001 } 1002 } 1003 1004 /******************************************************************************* 1005 ** 1006 ** Function SDP_GetDiRecord 1007 ** 1008 ** Description This function retrieves a remote device's DI record from 1009 ** the specified database. 1010 ** 1011 ** Returns SDP_SUCCESS if record retrieved, else error 1012 ** 1013 *******************************************************************************/ 1014 UINT16 SDP_GetDiRecord( UINT8 get_record_index, tSDP_DI_GET_RECORD *p_device_info, 1015 tSDP_DISCOVERY_DB *p_db ) 1016 { 1017 #if SDP_CLIENT_ENABLED == TRUE 1018 UINT16 result = SDP_NO_DI_RECORD_FOUND; 1019 UINT8 curr_record_index = 1; 1020 1021 tSDP_DISC_REC *p_curr_record = NULL; 1022 1023 /* find the requested SDP record in the discovery database */ 1024 do 1025 { 1026 p_curr_record = SDP_FindServiceInDb( p_db, UUID_SERVCLASS_PNP_INFORMATION, 1027 p_curr_record ); 1028 if ( p_curr_record ) 1029 { 1030 if ( curr_record_index++ == get_record_index ) 1031 { 1032 result = SDP_SUCCESS; 1033 break; 1034 } 1035 } 1036 }while ( p_curr_record ); 1037 1038 if ( result == SDP_SUCCESS ) 1039 { 1040 /* copy the information from the SDP record to the DI record */ 1041 tSDP_DISC_ATTR *p_curr_attr = NULL; 1042 1043 /* ClientExecutableURL is optional */ 1044 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_CLIENT_EXE_URL ); 1045 SDP_AttrStringCopy( p_device_info->rec.client_executable_url, p_curr_attr, 1046 SDP_MAX_ATTR_LEN ); 1047 1048 /* Service Description is optional */ 1049 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_SERVICE_DESCRIPTION ); 1050 SDP_AttrStringCopy( p_device_info->rec.service_description, p_curr_attr, SDP_MAX_ATTR_LEN ); 1051 1052 /* DocumentationURL is optional */ 1053 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_DOCUMENTATION_URL ); 1054 SDP_AttrStringCopy( p_device_info->rec.documentation_url, p_curr_attr, SDP_MAX_ATTR_LEN ); 1055 1056 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_SPECIFICATION_ID ); 1057 if ( p_curr_attr ) 1058 p_device_info->spec_id = p_curr_attr->attr_value.v.u16; 1059 else 1060 result = SDP_ERR_ATTR_NOT_PRESENT; 1061 1062 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_VENDOR_ID ); 1063 if ( p_curr_attr ) 1064 p_device_info->rec.vendor = p_curr_attr->attr_value.v.u16; 1065 else 1066 result = SDP_ERR_ATTR_NOT_PRESENT; 1067 1068 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_VENDOR_ID_SOURCE ); 1069 if ( p_curr_attr ) 1070 p_device_info->rec.vendor_id_source = p_curr_attr->attr_value.v.u16; 1071 else 1072 result = SDP_ERR_ATTR_NOT_PRESENT; 1073 1074 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRODUCT_ID ); 1075 if ( p_curr_attr ) 1076 p_device_info->rec.product = p_curr_attr->attr_value.v.u16; 1077 else 1078 result = SDP_ERR_ATTR_NOT_PRESENT; 1079 1080 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRODUCT_VERSION ); 1081 if ( p_curr_attr ) 1082 p_device_info->rec.version = p_curr_attr->attr_value.v.u16; 1083 else 1084 result = SDP_ERR_ATTR_NOT_PRESENT; 1085 1086 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRIMARY_RECORD ); 1087 if ( p_curr_attr ) 1088 p_device_info->rec.primary_record = (BOOLEAN)p_curr_attr->attr_value.v.u8; 1089 else 1090 result = SDP_ERR_ATTR_NOT_PRESENT; 1091 } 1092 1093 return result; 1094 #else /* SDP_CLIENT_ENABLED is FALSE */ 1095 return SDP_NO_DI_RECORD_FOUND; 1096 #endif 1097 } 1098 1099 /******************************************************************************* 1100 ** Device Identification (DI) Server Functions 1101 *******************************************************************************/ 1102 1103 /******************************************************************************* 1104 ** 1105 ** Function SDP_SetLocalDiRecord 1106 ** 1107 ** Description This function adds a DI record to the local SDP database. 1108 ** 1109 ** 1110 ** 1111 ** Returns Returns SDP_SUCCESS if record added successfully, else error 1112 ** 1113 *******************************************************************************/ 1114 UINT16 SDP_SetLocalDiRecord( tSDP_DI_RECORD *p_device_info, UINT32 *p_handle ) 1115 { 1116 #if SDP_SERVER_ENABLED == TRUE 1117 UINT16 result = SDP_SUCCESS; 1118 UINT32 handle; 1119 UINT16 di_uuid = UUID_SERVCLASS_PNP_INFORMATION; 1120 UINT16 di_specid = BLUETOOTH_DI_SPECIFICATION; 1121 UINT8 temp_u16[2]; 1122 UINT8 *p_temp; 1123 UINT8 u8; 1124 1125 *p_handle = 0; 1126 if ( p_device_info == NULL ) 1127 return SDP_ILLEGAL_PARAMETER; 1128 1129 /* if record is to be primary record, get handle to replace old primary */ 1130 if ( p_device_info->primary_record == TRUE && sdp_cb.server_db.di_primary_handle ) 1131 handle = sdp_cb.server_db.di_primary_handle; 1132 else 1133 { 1134 if ( (handle = SDP_CreateRecord()) == 0 ) 1135 return SDP_NO_RESOURCES; 1136 } 1137 1138 *p_handle = handle; 1139 1140 /* build the SDP entry */ 1141 /* Add the UUID to the Service Class ID List */ 1142 if ((SDP_AddServiceClassIdList(handle, 1, &di_uuid)) == FALSE) 1143 result = SDP_DI_REG_FAILED; 1144 1145 /* mandatory */ 1146 if ( result == SDP_SUCCESS) 1147 { 1148 p_temp = temp_u16; 1149 UINT16_TO_BE_STREAM(p_temp, di_specid); 1150 if ( !(SDP_AddAttribute(handle, ATTR_ID_SPECIFICATION_ID, 1151 UINT_DESC_TYPE, sizeof(di_specid), 1152 temp_u16)) ) 1153 result = SDP_DI_REG_FAILED; 1154 } 1155 1156 /* optional - if string is null, do not add attribute */ 1157 if ( result == SDP_SUCCESS ) 1158 { 1159 if ( p_device_info->client_executable_url[0] != '\0' ) 1160 { 1161 if ( !((strlen(p_device_info->client_executable_url)+1 <= SDP_MAX_ATTR_LEN) && 1162 SDP_AddAttribute(handle, ATTR_ID_CLIENT_EXE_URL, URL_DESC_TYPE, 1163 (UINT32)(strlen(p_device_info->client_executable_url)+1), 1164 (UINT8 *)p_device_info->client_executable_url)) ) 1165 result = SDP_DI_REG_FAILED; 1166 } 1167 } 1168 1169 /* optional - if string is null, do not add attribute */ 1170 if ( result == SDP_SUCCESS ) 1171 { 1172 if ( p_device_info->service_description[0] != '\0' ) 1173 { 1174 if ( !((strlen(p_device_info->service_description)+1 <= SDP_MAX_ATTR_LEN) && 1175 SDP_AddAttribute(handle, ATTR_ID_SERVICE_DESCRIPTION, 1176 TEXT_STR_DESC_TYPE, 1177 (UINT32)(strlen(p_device_info->service_description)+1), 1178 (UINT8 *)p_device_info->service_description)) ) 1179 result = SDP_DI_REG_FAILED; 1180 } 1181 } 1182 1183 /* optional - if string is null, do not add attribute */ 1184 if ( result == SDP_SUCCESS ) 1185 { 1186 if ( p_device_info->documentation_url[0] != '\0' ) 1187 { 1188 if ( !((strlen(p_device_info->documentation_url)+1 <= SDP_MAX_ATTR_LEN) && 1189 SDP_AddAttribute(handle, ATTR_ID_DOCUMENTATION_URL, URL_DESC_TYPE, 1190 (UINT32)(strlen(p_device_info->documentation_url)+1), 1191 (UINT8 *)p_device_info->documentation_url)) ) 1192 result = SDP_DI_REG_FAILED; 1193 } 1194 } 1195 1196 /* mandatory */ 1197 if ( result == SDP_SUCCESS) 1198 { 1199 p_temp = temp_u16; 1200 UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor); 1201 if ( !(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID, UINT_DESC_TYPE, 1202 sizeof(p_device_info->vendor), temp_u16)) ) 1203 result = SDP_DI_REG_FAILED; 1204 } 1205 1206 /* mandatory */ 1207 if ( result == SDP_SUCCESS) 1208 { 1209 p_temp = temp_u16; 1210 UINT16_TO_BE_STREAM (p_temp, p_device_info->product); 1211 if ( !(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_ID, 1212 UINT_DESC_TYPE, sizeof(p_device_info->product), temp_u16)) ) 1213 result = SDP_DI_REG_FAILED; 1214 } 1215 1216 /* mandatory */ 1217 if ( result == SDP_SUCCESS) 1218 { 1219 p_temp = temp_u16; 1220 UINT16_TO_BE_STREAM (p_temp, p_device_info->version); 1221 if ( !(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_VERSION, UINT_DESC_TYPE, 1222 sizeof(p_device_info->version), temp_u16)) ) 1223 result = SDP_DI_REG_FAILED; 1224 } 1225 1226 /* mandatory */ 1227 if ( result == SDP_SUCCESS) 1228 { 1229 u8 = (UINT8)p_device_info->primary_record; 1230 if ( !(SDP_AddAttribute(handle, ATTR_ID_PRIMARY_RECORD, 1231 BOOLEAN_DESC_TYPE, 1, &u8)) ) 1232 result = SDP_DI_REG_FAILED; 1233 } 1234 1235 /* mandatory */ 1236 if ( result == SDP_SUCCESS) 1237 { 1238 p_temp = temp_u16; 1239 UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor_id_source); 1240 if ( !(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID_SOURCE, UINT_DESC_TYPE, 1241 sizeof(p_device_info->vendor_id_source), temp_u16)) ) 1242 result = SDP_DI_REG_FAILED; 1243 } 1244 1245 if ( result != SDP_SUCCESS ) 1246 SDP_DeleteRecord( handle ); 1247 else if (p_device_info->primary_record == TRUE) 1248 sdp_cb.server_db.di_primary_handle = handle; 1249 1250 return result; 1251 #else /* SDP_SERVER_ENABLED is FALSE */ 1252 return SDP_DI_REG_FAILED; 1253 #endif /* if SDP_SERVER_ENABLED */ 1254 } 1255 1256 /******************************************************************************* 1257 ** 1258 ** Function SDP_SetTraceLevel 1259 ** 1260 ** Description This function sets the trace level for SDP. If called with 1261 ** a value of 0xFF, it simply reads the current trace level. 1262 ** 1263 ** Returns the new (current) trace level 1264 ** 1265 *******************************************************************************/ 1266 UINT8 SDP_SetTraceLevel (UINT8 new_level) 1267 { 1268 if (new_level != 0xFF) 1269 sdp_cb.trace_level = new_level; 1270 1271 return(sdp_cb.trace_level); 1272 } 1273