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 /* only support 16 bits UUID for now */ 355 if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) 356 { 357 p_uuid->len = 2; 358 p_uuid->uu.uuid16 = p_sattr->attr_value.v.u16; 359 } 360 return(TRUE); 361 } 362 363 /* Checking for Toyota G Block Car Kit: 364 ** This car kit puts an extra data element sequence 365 ** where the UUID is suppose to be!!! 366 */ 367 else 368 { 369 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE) 370 { 371 /* Look through data element sequence until no more UUIDs */ 372 for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr) 373 { 374 /* Increment past this to see if the next attribut is UUID */ 375 if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE) 376 /* only support 16 bits UUID for now */ 377 && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2)) 378 { 379 p_uuid->len = 2; 380 p_uuid->uu.uuid16 = p_extra_sattr->attr_value.v.u16; 381 return(TRUE); 382 } 383 } 384 } 385 } 386 } 387 break; 388 } 389 else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) 390 { 391 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) 392 /* only support 16 bits UUID for now */ 393 && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2)) 394 { 395 p_uuid->len = 2; 396 p_uuid->uu.uuid16 = p_attr->attr_value.v.u16; 397 return(TRUE); 398 } 399 } 400 p_attr = p_attr->p_next_attr; 401 } 402 return FALSE; 403#endif 404} 405 406/******************************************************************************* 407** 408** Function SDP_FindServiceUUIDInRec_128bit 409** 410** Description This function is called to read the 128-bit service UUID within a record 411** if there is any. 412** 413** Parameters: p_rec - pointer to a SDP record. 414** p_uuid - output parameter to save the UUID found. 415** 416** Returns TRUE if found, otherwise FALSE. 417** 418*******************************************************************************/ 419BOOLEAN SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC *p_rec, tBT_UUID * p_uuid) 420{ 421#if SDP_CLIENT_ENABLED == TRUE 422 tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr; 423 424 p_attr = p_rec->p_first_attr; 425 426 while (p_attr) 427 { 428 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) 429 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) 430 { 431 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 432 { 433 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) 434 { 435 /* only support 128 bits UUID for now */ 436 if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16) 437 { 438 p_uuid->len = 16; 439 memcpy(p_uuid->uu.uuid128, p_sattr->attr_value.v.array, MAX_UUID_SIZE); 440 } 441 return(TRUE); 442 } 443 } 444 break; 445 } 446 else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) 447 { 448 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) 449 /* only support 128 bits UUID for now */ 450 && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16)) 451 { 452 p_uuid->len = 16; 453 memcpy(p_uuid->uu.uuid128, p_sattr->attr_value.v.array, MAX_UUID_SIZE); 454 return(TRUE); 455 } 456 } 457 p_attr = p_attr->p_next_attr; 458 } 459 return FALSE; 460#endif 461} 462 463/******************************************************************************* 464** 465** Function SDP_FindServiceInDb 466** 467** Description This function queries an SDP database for a specific service. 468** If the p_start_rec pointer is NULL, it looks from the beginning 469** of the database, else it continues from the next record after 470** p_start_rec. 471** 472** Returns Pointer to record containing service class, or NULL 473** 474*******************************************************************************/ 475tSDP_DISC_REC *SDP_FindServiceInDb (tSDP_DISCOVERY_DB *p_db, UINT16 service_uuid, tSDP_DISC_REC *p_start_rec) 476{ 477#if SDP_CLIENT_ENABLED == TRUE 478 tSDP_DISC_REC *p_rec; 479 tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr; 480 481 /* Must have a valid database */ 482 if (p_db == NULL) 483 return(NULL); 484 485 if (!p_start_rec) 486 p_rec = p_db->p_first_rec; 487 else 488 p_rec = p_start_rec->p_next_rec; 489 490 while (p_rec) 491 { 492 p_attr = p_rec->p_first_attr; 493 while (p_attr) 494 { 495 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) 496 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) 497 { 498 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 499 { 500 501 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) 502 && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) ) { 503 printf("SDP_FindServiceInDb - p_sattr value = 0x%x serviceuuid = 0x%x\r\n", p_sattr->attr_value.v.u16, service_uuid); 504 if(service_uuid == UUID_SERVCLASS_HDP_PROFILE) 505 { 506 if( (p_sattr->attr_value.v.u16==UUID_SERVCLASS_HDP_SOURCE) || ( p_sattr->attr_value.v.u16==UUID_SERVCLASS_HDP_SOURCE)) 507 { 508 printf("SDP_FindServiceInDb found HDP source or sink\n" ); 509 return (p_rec); 510 } 511 } 512 513 } 514 515 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) 516 && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) 517 /* for a specific uuid, or any one */ 518 && ((p_sattr->attr_value.v.u16 == service_uuid) || service_uuid == 0)) 519 { 520 return(p_rec); 521 } 522 523 /* Checking for Toyota G Block Car Kit: 524 ** This car kit puts an extra data element sequence 525 ** where the UUID is suppose to be!!! 526 */ 527 else 528 { 529 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE) 530 { 531 /* Look through data element sequence until no more UUIDs */ 532 for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr) 533 { 534 /* Increment past this to see if the next attribut is UUID */ 535 if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE) 536 && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2) 537 /* for a specific uuid, or any one */ 538 && ((p_extra_sattr->attr_value.v.u16 == service_uuid) || (service_uuid == 0))) 539 { 540 return(p_rec); 541 } 542 } 543 } 544 } 545 } 546 break; 547 } 548 else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) 549 { 550 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) 551 && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2)) 552 { 553 printf("SDP_FindServiceInDb - p_attr value = 0x%x serviceuuid= 0x%x \r\n", p_attr->attr_value.v.u16, service_uuid); 554 } 555 556 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) 557 && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2) 558 /* find a specific UUID or anyone */ 559 && ((p_attr->attr_value.v.u16 == service_uuid) || service_uuid == 0)) 560 return(p_rec); 561 } 562 563 p_attr = p_attr->p_next_attr; 564 } 565 566 p_rec = p_rec->p_next_rec; 567 } 568#endif 569 /* If here, no matching UUID found */ 570 return(NULL); 571} 572 573/******************************************************************************* 574** 575** Function SDP_FindServiceInDb_128bit 576** 577** Description This function queries an SDP database for a specific service. 578** If the p_start_rec pointer is NULL, it looks from the beginning 579** of the database, else it continues from the next record after 580** p_start_rec. 581** 582** This function is kept separate from SDP_FindServiceInDb since 583** that API is expected to return only 16-bit UUIDs 584** 585** Returns Pointer to record containing service class, or NULL 586** 587*******************************************************************************/ 588tSDP_DISC_REC *SDP_FindServiceInDb_128bit(tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_start_rec) 589{ 590#if SDP_CLIENT_ENABLED == TRUE 591 tSDP_DISC_REC *p_rec; 592 tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr; 593 594 /* Must have a valid database */ 595 if (p_db == NULL) 596 return(NULL); 597 598 if (!p_start_rec) 599 p_rec = p_db->p_first_rec; 600 else 601 p_rec = p_start_rec->p_next_rec; 602 603 while (p_rec) 604 { 605 p_attr = p_rec->p_first_attr; 606 while (p_attr) 607 { 608 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) 609 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) 610 { 611 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 612 { 613 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) 614 && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16)) 615 { 616 return(p_rec); 617 } 618 } 619 break; 620 } 621 else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) 622 { 623 if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE) 624 && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16)) 625 return(p_rec); 626 } 627 628 p_attr = p_attr->p_next_attr; 629 } 630 631 p_rec = p_rec->p_next_rec; 632 } 633#endif 634 /* If here, no matching UUID found */ 635 return(NULL); 636} 637 638 639/******************************************************************************* 640** 641** Function SDP_FindServiceUUIDInDb 642** 643** Description This function queries an SDP database for a specific service. 644** If the p_start_rec pointer is NULL, it looks from the beginning 645** of the database, else it continues from the next record after 646** p_start_rec. 647** 648** NOTE the only difference between this function and the previous function 649** "SDP_FindServiceInDb()" is that this function takes a tBT_UUID input 650** 651** Returns Pointer to record containing service class, or NULL 652** 653*******************************************************************************/ 654tSDP_DISC_REC *SDP_FindServiceUUIDInDb (tSDP_DISCOVERY_DB *p_db, tBT_UUID *p_uuid, tSDP_DISC_REC *p_start_rec) 655{ 656#if SDP_CLIENT_ENABLED == TRUE 657 tSDP_DISC_REC *p_rec; 658 tSDP_DISC_ATTR *p_attr, *p_sattr; 659 660 /* Must have a valid database */ 661 if (p_db == NULL) 662 return(NULL); 663 664 if (!p_start_rec) 665 p_rec = p_db->p_first_rec; 666 else 667 p_rec = p_start_rec->p_next_rec; 668 669 while (p_rec) 670 { 671 p_attr = p_rec->p_first_attr; 672 while (p_attr) 673 { 674 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) 675 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) 676 { 677 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 678 { 679 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) 680 { 681 682 printf("uuid len=%d ", p_uuid->len); 683 if (p_uuid->len == 2) 684 { 685 printf("uuid=0x%x \n", p_uuid->uu.uuid16); 686 } 687 else 688 { 689 printf("\n"); 690 } 691 692 if (sdpu_compare_uuid_with_attr (p_uuid, p_sattr)) 693 return(p_rec); 694 } 695 } 696 break; 697 } 698 else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) 699 { 700 if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE ) 701 { 702 if (sdpu_compare_uuid_with_attr (p_uuid, p_attr)) 703 return(p_rec); 704 } 705 } 706 707 p_attr = p_attr->p_next_attr; 708 } 709 710 p_rec = p_rec->p_next_rec; 711 } 712#endif /* CLIENT_ENABLED == TRUE */ 713 /* If here, no matching UUID found */ 714 return(NULL); 715} 716 717#if SDP_CLIENT_ENABLED == TRUE 718/******************************************************************************* 719** 720** Function sdp_fill_proto_elem 721** 722** Description This function retrieves the protocol element. 723** 724** Returns TRUE if found, FALSE if not 725** If found, the passed protocol list element is filled in. 726** 727*******************************************************************************/ 728static BOOLEAN sdp_fill_proto_elem( tSDP_DISC_ATTR *p_attr, UINT16 layer_uuid, 729 tSDP_PROTOCOL_ELEM *p_elem) 730{ 731 tSDP_DISC_ATTR *p_sattr; 732 733 /* Walk through the protocol descriptor list */ 734 for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr) 735 { 736 /* Safety check - each entry should itself be a sequence */ 737 if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) 738 return(FALSE); 739 740 /* Now, see if the entry contains the layer we are interested in */ 741 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 742 { 743 /* SDP_TRACE_DEBUG3 ("SDP - p_sattr 0x%x, layer_uuid:0x%x, u16:0x%x####", 744 p_sattr, layer_uuid, p_sattr->attr_value.v.u16); */ 745 746 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) 747 && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) 748 && (p_sattr->attr_value.v.u16 == layer_uuid)) 749 { 750 /* Bingo. Now fill in the passed element */ 751 p_elem->protocol_uuid = layer_uuid; 752 p_elem->num_params = 0; 753 754 /* Store the parameters, if any */ 755 for (p_sattr = p_sattr->p_next_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 756 { 757 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) != UINT_DESC_TYPE) 758 break; 759 760 if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) 761 p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u16; 762 else 763 p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u8; 764 765 if (p_elem->num_params >= SDP_MAX_PROTOCOL_PARAMS) 766 break; 767 } 768 return(TRUE); 769 } 770 } 771 } 772 773 return(FALSE); 774} 775#endif /* CLIENT_ENABLED == TRUE */ 776 777/******************************************************************************* 778** 779** Function SDP_FindProtocolListElemInRec 780** 781** Description This function looks at a specific discovery record for a protocol 782** list element. 783** 784** Returns TRUE if found, FALSE if not 785** If found, the passed protocol list element is filled in. 786** 787*******************************************************************************/ 788BOOLEAN SDP_FindProtocolListElemInRec (tSDP_DISC_REC *p_rec, UINT16 layer_uuid, tSDP_PROTOCOL_ELEM *p_elem) 789{ 790#if SDP_CLIENT_ENABLED == TRUE 791 tSDP_DISC_ATTR *p_attr; 792 793 p_attr = p_rec->p_first_attr; 794 while (p_attr) 795 { 796 /* Find the protocol descriptor list */ 797 if ((p_attr->attr_id == ATTR_ID_PROTOCOL_DESC_LIST) 798 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) 799 { 800 return sdp_fill_proto_elem(p_attr, layer_uuid, p_elem); 801 } 802 p_attr = p_attr->p_next_attr; 803 } 804#endif 805 /* If here, no match found */ 806 return(FALSE); 807} 808 809 810/******************************************************************************* 811** 812** Function SDP_FindAddProtoListsElemInRec 813** 814** Description This function looks at a specific discovery record for a protocol 815** list element. 816** 817** Returns TRUE if found, FALSE if not 818** If found, the passed protocol list element is filled in. 819** 820*******************************************************************************/ 821BOOLEAN SDP_FindAddProtoListsElemInRec (tSDP_DISC_REC *p_rec, UINT16 layer_uuid, tSDP_PROTOCOL_ELEM *p_elem) 822{ 823#if SDP_CLIENT_ENABLED == TRUE 824 tSDP_DISC_ATTR *p_attr, *p_sattr; 825 BOOLEAN ret = FALSE; 826 827 p_attr = p_rec->p_first_attr; 828 while (p_attr) 829 { 830 /* Find the additional protocol descriptor list attribute */ 831 if ((p_attr->attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS) 832 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) 833 { 834 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 835 { 836 /* Safety check - each entry should itself be a sequence */ 837 if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE) 838 { 839 if ( (ret = sdp_fill_proto_elem(p_sattr, layer_uuid, p_elem)) == TRUE) 840 break; 841 } 842 } 843 return ret; 844 } 845 p_attr = p_attr->p_next_attr; 846 } 847#endif 848 /* If here, no match found */ 849 return(FALSE); 850} 851 852 853/******************************************************************************* 854** 855** Function SDP_FindProfileVersionInRec 856** 857** Description This function looks at a specific discovery record for the 858** Profile list descriptor, and pulls out the version number. 859** The version number consists of an 8-bit major version and 860** an 8-bit minor version. 861** 862** Returns TRUE if found, FALSE if not 863** If found, the major and minor version numbers that were passed 864** in are filled in. 865** 866*******************************************************************************/ 867BOOLEAN SDP_FindProfileVersionInRec (tSDP_DISC_REC *p_rec, UINT16 profile_uuid, UINT16 *p_version) 868{ 869#if SDP_CLIENT_ENABLED == TRUE 870 tSDP_DISC_ATTR *p_attr, *p_sattr; 871 872 p_attr = p_rec->p_first_attr; 873 while (p_attr) 874 { 875 /* Find the profile descriptor list */ 876 if ((p_attr->attr_id == ATTR_ID_BT_PROFILE_DESC_LIST) 877 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) 878 { 879 /* Walk through the protocol descriptor list */ 880 for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr) 881 { 882 /* Safety check - each entry should itself be a sequence */ 883 if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) 884 return(FALSE); 885 886 /* Now, see if the entry contains the profile UUID we are interested in */ 887 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 888 { 889 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) 890 && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) /* <- This is bytes, not size code! */ 891 && (p_sattr->attr_value.v.u16 == profile_uuid)) 892 { 893 /* Now fill in the major and minor numbers */ 894 /* if the attribute matches the description for version (type UINT, size 2 bytes) */ 895 p_sattr = p_sattr->p_next_attr; 896 897 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UINT_DESC_TYPE) && 898 (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)) 899 { 900 /* The high order 8 bits is the major number, low order is the minor number (big endian) */ 901 *p_version = p_sattr->attr_value.v.u16; 902 903 return(TRUE); 904 } 905 else 906 return(FALSE); /* The type and/or size was not valid for the profile list version */ 907 } 908 } 909 } 910 911 return(FALSE); 912 } 913 p_attr = p_attr->p_next_attr; 914 } 915#endif /* CLIENT_ENABLED == TRUE */ 916 917 /* If here, no match found */ 918 return(FALSE); 919} 920 921/******************************************************************************* 922** Device Identification (DI) Client Functions 923*******************************************************************************/ 924 925/******************************************************************************* 926** 927** Function SDP_DiDiscover 928** 929** Description This function queries a remote device for DI information. 930** 931** Returns SDP_SUCCESS if query started successfully, else error 932** 933*******************************************************************************/ 934UINT16 SDP_DiDiscover( BD_ADDR remote_device, tSDP_DISCOVERY_DB *p_db, 935 UINT32 len, tSDP_DISC_CMPL_CB *p_cb ) 936{ 937#if SDP_CLIENT_ENABLED == TRUE 938 UINT16 result = SDP_DI_DISC_FAILED; 939 UINT16 num_uuids = 1; 940 UINT16 di_uuid = UUID_SERVCLASS_PNP_INFORMATION; 941 942 /* build uuid for db init */ 943 tSDP_UUID init_uuid; 944 init_uuid.len = 2; 945 init_uuid.uu.uuid16 = di_uuid; 946 947 if ( SDP_InitDiscoveryDb(p_db, len, num_uuids, &init_uuid, 0, NULL) ) 948 if ( SDP_ServiceSearchRequest(remote_device, p_db, p_cb) ) 949 result = SDP_SUCCESS; 950 951 return result; 952#else 953 return SDP_DI_DISC_FAILED; 954#endif 955} 956 957/******************************************************************************* 958** 959** Function SDP_GetNumDiRecords 960** 961** Description Searches specified database for DI records 962** 963** Returns number of DI records found 964** 965*******************************************************************************/ 966UINT8 SDP_GetNumDiRecords( tSDP_DISCOVERY_DB *p_db ) 967{ 968#if SDP_CLIENT_ENABLED == TRUE 969 UINT8 num_records = 0; 970 tSDP_DISC_REC *p_curr_record = NULL; 971 972 do 973 { 974 p_curr_record = SDP_FindServiceInDb( p_db, UUID_SERVCLASS_PNP_INFORMATION, 975 p_curr_record ); 976 if ( p_curr_record ) 977 num_records++; 978 }while ( p_curr_record ); 979 980 return num_records; 981#else 982 return 0; 983#endif 984} 985 986/******************************************************************************* 987** 988** Function SDP_GetDiRecord 989** 990** Description This function retrieves a remote device's DI record from 991** the specified database. 992** 993** Returns SDP_SUCCESS if record retrieved, else error 994** 995*******************************************************************************/ 996UINT16 SDP_GetDiRecord( UINT8 get_record_index, tSDP_DI_GET_RECORD *p_device_info, 997 tSDP_DISCOVERY_DB *p_db ) 998{ 999#if SDP_CLIENT_ENABLED == TRUE 1000 UINT16 result = SDP_NO_DI_RECORD_FOUND; 1001 UINT8 curr_record_index = 1; 1002 1003 tSDP_DISC_REC *p_curr_record = NULL; 1004 1005 /* find the requested SDP record in the discovery database */ 1006 do 1007 { 1008 p_curr_record = SDP_FindServiceInDb( p_db, UUID_SERVCLASS_PNP_INFORMATION, 1009 p_curr_record ); 1010 if ( p_curr_record ) 1011 { 1012 if ( curr_record_index++ == get_record_index ) 1013 { 1014 result = SDP_SUCCESS; 1015 break; 1016 } 1017 } 1018 }while ( p_curr_record ); 1019 1020 if ( result == SDP_SUCCESS ) 1021 { 1022 /* copy the information from the SDP record to the DI record */ 1023 tSDP_DISC_ATTR *p_curr_attr = NULL; 1024 1025 /* ClientExecutableURL is optional */ 1026 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_CLIENT_EXE_URL ); 1027 if ( p_curr_attr ) 1028 BCM_STRNCPY_S( p_device_info->rec.client_executable_url, sizeof(p_device_info->rec.client_executable_url), 1029 (char *)p_curr_attr->attr_value.v.array, SDP_MAX_ATTR_LEN ); 1030 else 1031 p_device_info->rec.client_executable_url[0] = '\0'; 1032 1033 /* Service Description is optional */ 1034 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_SERVICE_DESCRIPTION ); 1035 if ( p_curr_attr ) 1036 BCM_STRNCPY_S( p_device_info->rec.service_description, sizeof(p_device_info->rec.service_description), 1037 (char *)p_curr_attr->attr_value.v.array, SDP_MAX_ATTR_LEN ); 1038 else 1039 p_device_info->rec.service_description[0] = '\0'; 1040 1041 /* DocumentationURL is optional */ 1042 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_DOCUMENTATION_URL ); 1043 if ( p_curr_attr ) 1044 BCM_STRNCPY_S( p_device_info->rec.documentation_url, sizeof(p_device_info->rec.documentation_url), 1045 (char *)p_curr_attr->attr_value.v.array, SDP_MAX_ATTR_LEN ); 1046 else 1047 p_device_info->rec.documentation_url[0] = '\0'; 1048 1049 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_SPECIFICATION_ID ); 1050 if ( p_curr_attr ) 1051 p_device_info->spec_id = p_curr_attr->attr_value.v.u16; 1052 else 1053 result = SDP_ERR_ATTR_NOT_PRESENT; 1054 1055 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_VENDOR_ID ); 1056 if ( p_curr_attr ) 1057 p_device_info->rec.vendor = p_curr_attr->attr_value.v.u16; 1058 else 1059 result = SDP_ERR_ATTR_NOT_PRESENT; 1060 1061 p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_VENDOR_ID_SOURCE ); 1062 if ( p_curr_attr ) 1063 p_device_info->rec.vendor_id_source = 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_PRODUCT_ID ); 1068 if ( p_curr_attr ) 1069 p_device_info->rec.product = 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_PRODUCT_VERSION ); 1074 if ( p_curr_attr ) 1075 p_device_info->rec.version = 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_PRIMARY_RECORD ); 1080 if ( p_curr_attr ) 1081 p_device_info->rec.primary_record = (BOOLEAN)p_curr_attr->attr_value.v.u8; 1082 else 1083 result = SDP_ERR_ATTR_NOT_PRESENT; 1084 } 1085 1086 return result; 1087#else /* SDP_CLIENT_ENABLED is FALSE */ 1088 return SDP_NO_DI_RECORD_FOUND; 1089#endif 1090} 1091 1092/******************************************************************************* 1093** Device Identification (DI) Server Functions 1094*******************************************************************************/ 1095 1096/******************************************************************************* 1097** 1098** Function SDP_SetLocalDiRecord 1099** 1100** Description This function adds a DI record to the local SDP database. 1101** 1102** 1103** 1104** Returns Returns SDP_SUCCESS if record added successfully, else error 1105** 1106*******************************************************************************/ 1107UINT16 SDP_SetLocalDiRecord( tSDP_DI_RECORD *p_device_info, UINT32 *p_handle ) 1108{ 1109#if SDP_SERVER_ENABLED == TRUE 1110 UINT16 result = SDP_SUCCESS; 1111 UINT32 handle; 1112 UINT16 di_uuid = UUID_SERVCLASS_PNP_INFORMATION; 1113 UINT16 di_specid = BLUETOOTH_DI_SPECIFICATION; 1114 UINT8 temp_u16[2]; 1115 UINT8 *p_temp; 1116 UINT8 u8; 1117 1118 *p_handle = 0; 1119 if ( p_device_info == NULL ) 1120 return SDP_ILLEGAL_PARAMETER; 1121 1122 /* if record is to be primary record, get handle to replace old primary */ 1123 if ( p_device_info->primary_record == TRUE && sdp_cb.server_db.di_primary_handle ) 1124 handle = sdp_cb.server_db.di_primary_handle; 1125 else 1126 { 1127 if ( (handle = SDP_CreateRecord()) == 0 ) 1128 return SDP_NO_RESOURCES; 1129 } 1130 1131 *p_handle = handle; 1132 1133 /* build the SDP entry */ 1134 /* Add the UUID to the Service Class ID List */ 1135 if ((SDP_AddServiceClassIdList(handle, 1, &di_uuid)) == FALSE) 1136 result = SDP_DI_REG_FAILED; 1137 1138 /* mandatory */ 1139 if ( result == SDP_SUCCESS) 1140 { 1141 p_temp = temp_u16; 1142 UINT16_TO_BE_STREAM(p_temp, di_specid); 1143 if ( !(SDP_AddAttribute(handle, ATTR_ID_SPECIFICATION_ID, 1144 UINT_DESC_TYPE, sizeof(di_specid), 1145 temp_u16)) ) 1146 result = SDP_DI_REG_FAILED; 1147 } 1148 1149 /* optional - if string is null, do not add attribute */ 1150 if ( result == SDP_SUCCESS ) 1151 { 1152 if ( p_device_info->client_executable_url[0] != '\0' ) 1153 { 1154 if ( !((strlen(p_device_info->client_executable_url)+1 <= SDP_MAX_ATTR_LEN) && 1155 SDP_AddAttribute(handle, ATTR_ID_CLIENT_EXE_URL, URL_DESC_TYPE, 1156 (UINT32)(strlen(p_device_info->client_executable_url)+1), 1157 (UINT8 *)p_device_info->client_executable_url)) ) 1158 result = SDP_DI_REG_FAILED; 1159 } 1160 } 1161 1162 /* optional - if string is null, do not add attribute */ 1163 if ( result == SDP_SUCCESS ) 1164 { 1165 if ( p_device_info->service_description[0] != '\0' ) 1166 { 1167 if ( !((strlen(p_device_info->service_description)+1 <= SDP_MAX_ATTR_LEN) && 1168 SDP_AddAttribute(handle, ATTR_ID_SERVICE_DESCRIPTION, 1169 TEXT_STR_DESC_TYPE, 1170 (UINT32)(strlen(p_device_info->service_description)+1), 1171 (UINT8 *)p_device_info->service_description)) ) 1172 result = SDP_DI_REG_FAILED; 1173 } 1174 } 1175 1176 /* optional - if string is null, do not add attribute */ 1177 if ( result == SDP_SUCCESS ) 1178 { 1179 if ( p_device_info->documentation_url[0] != '\0' ) 1180 { 1181 if ( !((strlen(p_device_info->documentation_url)+1 <= SDP_MAX_ATTR_LEN) && 1182 SDP_AddAttribute(handle, ATTR_ID_DOCUMENTATION_URL, URL_DESC_TYPE, 1183 (UINT32)(strlen(p_device_info->documentation_url)+1), 1184 (UINT8 *)p_device_info->documentation_url)) ) 1185 result = SDP_DI_REG_FAILED; 1186 } 1187 } 1188 1189 /* mandatory */ 1190 if ( result == SDP_SUCCESS) 1191 { 1192 p_temp = temp_u16; 1193 UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor); 1194 if ( !(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID, UINT_DESC_TYPE, 1195 sizeof(p_device_info->vendor), temp_u16)) ) 1196 result = SDP_DI_REG_FAILED; 1197 } 1198 1199 /* mandatory */ 1200 if ( result == SDP_SUCCESS) 1201 { 1202 p_temp = temp_u16; 1203 UINT16_TO_BE_STREAM (p_temp, p_device_info->product); 1204 if ( !(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_ID, 1205 UINT_DESC_TYPE, sizeof(p_device_info->product), temp_u16)) ) 1206 result = SDP_DI_REG_FAILED; 1207 } 1208 1209 /* mandatory */ 1210 if ( result == SDP_SUCCESS) 1211 { 1212 p_temp = temp_u16; 1213 UINT16_TO_BE_STREAM (p_temp, p_device_info->version); 1214 if ( !(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_VERSION, UINT_DESC_TYPE, 1215 sizeof(p_device_info->version), temp_u16)) ) 1216 result = SDP_DI_REG_FAILED; 1217 } 1218 1219 /* mandatory */ 1220 if ( result == SDP_SUCCESS) 1221 { 1222 u8 = (UINT8)p_device_info->primary_record; 1223 if ( !(SDP_AddAttribute(handle, ATTR_ID_PRIMARY_RECORD, 1224 BOOLEAN_DESC_TYPE, 1, &u8)) ) 1225 result = SDP_DI_REG_FAILED; 1226 } 1227 1228 /* mandatory */ 1229 if ( result == SDP_SUCCESS) 1230 { 1231 p_temp = temp_u16; 1232 UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor_id_source); 1233 if ( !(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID_SOURCE, UINT_DESC_TYPE, 1234 sizeof(p_device_info->vendor_id_source), temp_u16)) ) 1235 result = SDP_DI_REG_FAILED; 1236 } 1237 1238 if ( result != SDP_SUCCESS ) 1239 SDP_DeleteRecord( handle ); 1240 else if (p_device_info->primary_record == TRUE) 1241 sdp_cb.server_db.di_primary_handle = handle; 1242 1243 return result; 1244#else /* SDP_SERVER_ENABLED is FALSE */ 1245 return SDP_DI_REG_FAILED; 1246#endif /* if SDP_SERVER_ENABLED */ 1247} 1248 1249/******************************************************************************* 1250** 1251** Function SDP_GetLocalDiRecord 1252** 1253** Description This function adds a DI record to the local SDP database. 1254** 1255** Fills in the device information of the record 1256** p_handle - if p_handle == 0, the primary record is returned 1257** 1258** Returns Returns SDP_SUCCESS if record exists, else error 1259** 1260*******************************************************************************/ 1261UINT16 SDP_GetLocalDiRecord(tSDP_DI_GET_RECORD *p_device_info, UINT32 *p_handle ) 1262{ 1263 UINT16 result = SDP_NO_DI_RECORD_FOUND; 1264 1265#if SDP_SERVER_ENABLED == TRUE 1266 tSDP_RECORD *p_rec; 1267 tSDP_ATTRIBUTE *p_attr; 1268 UINT8 *p_temp; 1269 INT32 templen; 1270 1271 if (*p_handle == 0) 1272 *p_handle = sdp_cb.server_db.di_primary_handle; 1273 1274 if ((p_rec = sdp_db_find_record(*p_handle)) != NULL) 1275 { 1276 memset(p_device_info, 0, sizeof(tSDP_DI_RECORD)); 1277 1278 result = SDP_SUCCESS; 1279 1280 /* Retrieve the Specification ID */ 1281 if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_SPECIFICATION_ID, 1282 ATTR_ID_SPECIFICATION_ID)) != NULL) 1283 { 1284 p_temp = p_attr->value_ptr; 1285 BE_STREAM_TO_UINT16 (p_device_info->spec_id, p_temp); 1286 } 1287 1288 /* Retrieve the Vendor ID */ 1289 if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_VENDOR_ID, 1290 ATTR_ID_VENDOR_ID)) != NULL) 1291 { 1292 p_temp = p_attr->value_ptr; 1293 BE_STREAM_TO_UINT16 (p_device_info->rec.vendor, p_temp); 1294 } 1295 1296 /* Retrieve the Product ID */ 1297 if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_PRODUCT_ID, 1298 ATTR_ID_PRODUCT_ID)) != NULL) 1299 { 1300 p_temp = p_attr->value_ptr; 1301 BE_STREAM_TO_UINT16 (p_device_info->rec.product, p_temp); 1302 } 1303 1304 /* Retrieve the Version ID */ 1305 if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_PRODUCT_VERSION, 1306 ATTR_ID_PRODUCT_VERSION)) != NULL) 1307 { 1308 p_temp = p_attr->value_ptr; 1309 BE_STREAM_TO_UINT16 (p_device_info->rec.version, p_temp); 1310 } 1311 1312 /* Retrieve the Vendor ID Source ID */ 1313 if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_VENDOR_ID_SOURCE, 1314 ATTR_ID_VENDOR_ID_SOURCE)) != NULL) 1315 { 1316 p_temp = p_attr->value_ptr; 1317 BE_STREAM_TO_UINT16 (p_device_info->rec.vendor_id_source, p_temp); 1318 } 1319 1320 /* Retrieve the Primary Record */ 1321 if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_PRIMARY_RECORD, 1322 ATTR_ID_PRIMARY_RECORD)) != NULL) 1323 { 1324 p_device_info->rec.primary_record = *p_attr->value_ptr; 1325 } 1326 1327 /* Retrieve the Client Executable URL */ 1328 if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_CLIENT_EXE_URL, 1329 ATTR_ID_CLIENT_EXE_URL)) != NULL) 1330 { 1331 templen = (INT32)((p_attr->len < SDP_MAX_ATTR_LEN) ? p_attr->len : SDP_MAX_ATTR_LEN); 1332 p_temp = p_attr->value_ptr; 1333 BE_STREAM_TO_ARRAY (p_temp, p_device_info->rec.client_executable_url, templen); 1334 } 1335 1336 /* Retrieve the Service Description */ 1337 if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_SERVICE_DESCRIPTION, 1338 ATTR_ID_SERVICE_DESCRIPTION)) != NULL) 1339 { 1340 templen = (INT32)((p_attr->len < SDP_MAX_ATTR_LEN) ? p_attr->len : SDP_MAX_ATTR_LEN); 1341 p_temp = p_attr->value_ptr; 1342 BE_STREAM_TO_ARRAY (p_temp, p_device_info->rec.service_description, templen); 1343 } 1344 1345 /* Retrieve the Documentation URL */ 1346 if ((p_attr = sdp_db_find_attr_in_rec(p_rec, ATTR_ID_DOCUMENTATION_URL, 1347 ATTR_ID_DOCUMENTATION_URL)) != NULL) 1348 { 1349 templen = (INT32)((p_attr->len < SDP_MAX_ATTR_LEN) ? p_attr->len : SDP_MAX_ATTR_LEN); 1350 p_temp = p_attr->value_ptr; 1351 BE_STREAM_TO_ARRAY (p_temp, p_device_info->rec.documentation_url, templen); 1352 } 1353 } 1354 else 1355 *p_handle = 0; 1356#endif 1357 1358 return result; 1359} 1360 1361 1362/******************************************************************************* 1363** 1364** Function SDP_SetTraceLevel 1365** 1366** Description This function sets the trace level for SDP. If called with 1367** a value of 0xFF, it simply reads the current trace level. 1368** 1369** Returns the new (current) trace level 1370** 1371*******************************************************************************/ 1372UINT8 SDP_SetTraceLevel (UINT8 new_level) 1373{ 1374 if (new_level != 0xFF) 1375 sdp_cb.trace_level = new_level; 1376 1377 return(sdp_cb.trace_level); 1378} 1379 1380#if SDP_FOR_JV_INCLUDED == TRUE 1381/******************************************************************************* 1382** 1383** Function SDP_ConnOpen 1384** 1385** Description This function creates a connection to the SDP server on the 1386** given device. 1387** 1388** Returns 0, if failed to initiate connection. Otherwise, the handle. 1389** 1390*******************************************************************************/ 1391UINT32 SDP_ConnOpen (UINT8 *p_bd_addr, tSDP_DISC_RES_CB *p_rcb, 1392 tSDP_DISC_CMPL_CB *p_cb) 1393{ 1394#if SDP_CLIENT_ENABLED == TRUE 1395 tCONN_CB *p_ccb; 1396 UINT32 idx = 0; 1397 1398 if (!p_cb || !p_rcb) 1399 return(idx); 1400 1401 /* Specific BD address */ 1402 p_ccb = sdp_conn_originate (p_bd_addr); 1403 1404 if (!p_ccb) 1405 return(idx); 1406 1407 p_ccb->disc_state = SDP_DISC_WAIT_CONN; 1408 p_ccb->p_db = (tSDP_DISCOVERY_DB *)p_rcb; 1409 p_ccb->p_cb = p_cb; 1410 1411 p_ccb->is_attr_search = SDP_IS_PASS_THRU; 1412 1413 idx = (UINT32)(p_ccb - sdp_cb.ccb); 1414 return(UINT32)(idx + 1); 1415#else 1416 return(0); 1417#endif 1418} 1419 1420/******************************************************************************* 1421** 1422** Function SDP_WriteData 1423** 1424** Description This function sends data to the connected SDP server. 1425** 1426** Returns TRUE if data is sent, FALSE if failed. 1427** 1428*******************************************************************************/ 1429BOOLEAN SDP_WriteData (UINT32 handle, BT_HDR *p_msg) 1430{ 1431#if SDP_CLIENT_ENABLED == TRUE 1432 tCONN_CB *p_ccb = NULL; 1433 1434 if (p_msg && (handle > 0) && (handle <= SDP_MAX_CONNECTIONS) ) 1435 { 1436 p_ccb = &sdp_cb.ccb[handle - 1]; 1437 if ( (p_ccb->con_state == SDP_STATE_CONNECTED) && 1438 (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) ) 1439 { 1440 /* Start inactivity timer */ 1441 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT); 1442 L2CA_DataWrite (p_ccb->connection_id, p_msg); 1443 return TRUE; 1444 } 1445 } 1446#endif 1447 return FALSE; 1448} 1449 1450/******************************************************************************* 1451** 1452** Function SDP_ConnClose 1453** 1454** Description This function is called to close a SDP connection. 1455** 1456** Parameters: handle - Handle of the connection returned by SDP_ConnOpen 1457** 1458** Returns TRUE if connection is closed, FALSE if failed to find the handle. 1459** 1460*******************************************************************************/ 1461BOOLEAN SDP_ConnClose (UINT32 handle) 1462{ 1463#if SDP_CLIENT_ENABLED == TRUE 1464 tCONN_CB *p_ccb = NULL; 1465 1466 if (handle > 0 && handle <= SDP_MAX_CONNECTIONS) 1467 { 1468 p_ccb = &sdp_cb.ccb[handle - 1]; 1469 sdp_disconnect (p_ccb, SDP_SUCCESS); 1470 return TRUE; 1471 } 1472#endif 1473 return FALSE; 1474} 1475#endif 1476