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