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