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