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