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 *******************************************************************************/ 71 BOOLEAN 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 *******************************************************************************/ 121 BOOLEAN 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 *******************************************************************************/ 145 BOOLEAN 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 *******************************************************************************/ 182 BOOLEAN 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 *******************************************************************************/ 219 BOOLEAN 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 245 void 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 *******************************************************************************/ 262 tSDP_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 *******************************************************************************/ 307 tSDP_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 *******************************************************************************/ 338 BOOLEAN 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 *******************************************************************************/ 419 BOOLEAN 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 *******************************************************************************/ 475 tSDP_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 *******************************************************************************/ 588 tSDP_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 *******************************************************************************/ 654 tSDP_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 *******************************************************************************/ 728 static 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 *******************************************************************************/ 788 BOOLEAN 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 *******************************************************************************/ 821 BOOLEAN 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 *******************************************************************************/ 867 BOOLEAN 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 *******************************************************************************/ 934 UINT16 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 *******************************************************************************/ 966 UINT8 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 *******************************************************************************/ 996 UINT16 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 *******************************************************************************/ 1107 UINT16 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 *******************************************************************************/ 1261 UINT16 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 *******************************************************************************/ 1372 UINT8 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 *******************************************************************************/ 1391 UINT32 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 *******************************************************************************/ 1429 BOOLEAN 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 *******************************************************************************/ 1461 BOOLEAN 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