1 /****************************************************************************** 2 * 3 * Copyright (C) 1998-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 #include <string.h> 20 21 #include "bt_target.h" 22 #if defined(HL_INCLUDED) && (HL_INCLUDED == TRUE) 23 24 #include "sdp_api.h" 25 #include "bta_hl_int.h" 26 #include "utl.h" 27 28 /******************************************************************************* 29 ** 30 ** Function bta_hl_fill_sup_feature_list 31 ** 32 ** Description Fill the supported features from teh SDP record 33 ** 34 ** Returns TRUE if found, FALSE if not 35 ** If found, the passed protocol list element is filled in. 36 ** 37 *******************************************************************************/ 38 BOOLEAN bta_hl_fill_sup_feature_list( const tSDP_DISC_ATTR *p_attr, 39 tBTA_HL_SUP_FEATURE_LIST_ELEM *p_list) 40 { 41 tSDP_DISC_ATTR *p_sattr; 42 UINT8 item_cnt; 43 UINT8 list_cnt=0; 44 BOOLEAN status=TRUE; 45 46 for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr) 47 { 48 /* mdep sequence */ 49 if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) 50 { 51 return(FALSE); 52 } 53 54 item_cnt=0; 55 56 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr && (item_cnt < 4) ; p_sattr = p_sattr->p_next_attr) 57 { 58 /* for each mdep list */ 59 60 p_list->list_elem[list_cnt].p_mdep_desp = NULL; 61 switch (item_cnt) 62 { 63 case 0: 64 p_list->list_elem[list_cnt].mdep_id = p_sattr->attr_value.v.u8; 65 break; 66 case 1: 67 p_list->list_elem[list_cnt].data_type = p_sattr->attr_value.v.u16; 68 break; 69 case 2: 70 p_list->list_elem[list_cnt].mdep_role = (tBTA_HL_MDEP_ROLE) p_sattr->attr_value.v.u8; 71 break; 72 case 3: 73 p_list->list_elem[list_cnt].p_mdep_desp = (char *) p_sattr->attr_value.v.array; 74 break; 75 } 76 77 item_cnt++; 78 } 79 list_cnt++; 80 } 81 p_list->num_elems = list_cnt; 82 return(status); 83 } 84 85 /******************************************************************************* 86 ** 87 ** Function bta_hl_compose_supported_feature_list 88 ** 89 ** Description This function is called to compose a data sequence from 90 ** the supported feature element list struct pointer 91 ** 92 ** Returns the length of the data sequence 93 ** 94 *******************************************************************************/ 95 int bta_hl_compose_supported_feature_list( UINT8 *p, UINT16 num_elem, 96 const tBTA_HL_SUP_FEATURE_ELEM *p_elem_list) 97 { 98 UINT16 xx, str_len, seq_len; 99 UINT8 *p_head = p; 100 101 for (xx = 0; xx < num_elem; xx++, p_elem_list++) 102 { 103 UINT8_TO_BE_STREAM (p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); 104 seq_len=7; 105 str_len=0; 106 if (p_elem_list->p_mdep_desp) 107 { 108 str_len = strlen(p_elem_list->p_mdep_desp)+1; 109 seq_len += str_len+2; /* todo add a # symbol for 2 */ 110 } 111 112 *p++ = (UINT8) seq_len; 113 114 UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE); 115 UINT8_TO_BE_STREAM (p, p_elem_list->mdep_id); 116 UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); 117 UINT16_TO_BE_STREAM (p, p_elem_list->data_type); 118 UINT8_TO_BE_STREAM (p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE); 119 UINT8_TO_BE_STREAM (p, p_elem_list->mdep_role); 120 121 if (str_len) 122 { 123 UINT8_TO_BE_STREAM (p, (TEXT_STR_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); 124 UINT8_TO_BE_STREAM (p, str_len); 125 ARRAY_TO_BE_STREAM(p, p_elem_list->p_mdep_desp, str_len); 126 } 127 } 128 129 return(p - p_head); 130 } 131 132 /******************************************************************************* 133 ** 134 ** Function bta_hl_add_sup_feature_list 135 ** 136 ** Description This function is called to add a protocol descriptor list to 137 ** a record. This would be through the SDP database maintenance API. 138 ** If the protocol list already exists in the record, it is replaced 139 ** with the new list. 140 ** 141 ** Returns TRUE if added OK, else FALSE 142 ** 143 *******************************************************************************/ 144 BOOLEAN bta_hl_add_sup_feature_list (UINT32 handle, UINT16 num_elem, 145 const tBTA_HL_SUP_FEATURE_ELEM *p_elem_list) 146 { 147 int offset; 148 BOOLEAN result; 149 UINT8 *p_buf = (UINT8 *)osi_malloc(BTA_HL_SUP_FEATURE_SDP_BUF_SIZE); 150 151 offset = bta_hl_compose_supported_feature_list(p_buf, num_elem, 152 p_elem_list); 153 result = SDP_AddAttribute(handle, ATTR_ID_HDP_SUP_FEAT_LIST, 154 DATA_ELE_SEQ_DESC_TYPE, (UINT32) offset, p_buf); 155 osi_free(p_buf); 156 157 return result; 158 } 159 160 /***************************************************************************** 161 ** 162 ** Function: bta_hl_sdp_update 163 ** 164 ** Purpose: Register an HDP application with SDP 165 ** 166 ** Parameters: 167 ** 168 ** Returns: void 169 ** 170 *****************************************************************************/ 171 tBTA_HL_STATUS bta_hl_sdp_update (UINT8 app_id) 172 { 173 UINT16 svc_class_id_list[BTA_HL_NUM_SVC_ELEMS]; 174 tSDP_PROTOCOL_ELEM proto_elem_list[BTA_HL_NUM_PROTO_ELEMS]; 175 tSDP_PROTO_LIST_ELEM add_proto_list; 176 tBTA_HL_SUP_FEATURE_LIST_ELEM sup_feature_list; 177 UINT16 browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP}; 178 UINT8 i,j, cnt,mdep_id, mdep_role; 179 UINT8 data_exchange_spec = BTA_HL_SDP_IEEE_11073_20601; 180 UINT8 mcap_sup_proc = BTA_HL_MCAP_SUP_PROC_MASK; 181 UINT16 profile_uuid = UUID_SERVCLASS_HDP_PROFILE; 182 UINT16 version = BTA_HL_VERSION; 183 UINT8 num_services=1; 184 tBTA_HL_APP_CB *p_cb = BTA_HL_GET_APP_CB_PTR(0); 185 BOOLEAN result = TRUE; 186 tBTA_HL_STATUS status = BTA_HL_STATUS_OK; 187 UNUSED(app_id); 188 189 if ((p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE) && 190 (!p_cb->sup_feature.advertize_source_sdp)) 191 { 192 return BTA_HL_STATUS_OK; 193 } 194 195 num_services=1; 196 svc_class_id_list[0]= UUID_SERVCLASS_HDP_SOURCE; 197 if (p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SINK) 198 { 199 svc_class_id_list[0]= UUID_SERVCLASS_HDP_SINK; 200 } 201 else 202 { 203 if (p_cb->sup_feature.app_role_mask != BTA_HL_MDEP_ROLE_MASK_SOURCE) 204 { 205 /* dual role */ 206 num_services=2; 207 svc_class_id_list[1]= UUID_SERVCLASS_HDP_SINK; 208 } 209 } 210 result &= SDP_AddServiceClassIdList(p_cb->sdp_handle, num_services, svc_class_id_list); 211 212 if (result) 213 { 214 /* add the protocol element sequence */ 215 proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP; 216 proto_elem_list[0].num_params = 1; 217 proto_elem_list[0].params[0] = p_cb->ctrl_psm; 218 proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_MCAP_CTRL; 219 proto_elem_list[1].num_params = 1; 220 proto_elem_list[1].params[0] = version; 221 result &= SDP_AddProtocolList(p_cb->sdp_handle, BTA_HL_NUM_PROTO_ELEMS, proto_elem_list); 222 223 result &= SDP_AddProfileDescriptorList(p_cb->sdp_handle, profile_uuid, version); 224 } 225 226 if (result) 227 { 228 add_proto_list.num_elems = BTA_HL_NUM_ADD_PROTO_ELEMS; 229 add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP; 230 add_proto_list.list_elem[0].num_params = 1; 231 add_proto_list.list_elem[0].params[0] = p_cb->data_psm; 232 add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_MCAP_DATA; 233 add_proto_list.list_elem[1].num_params = 0; 234 result &= SDP_AddAdditionProtoLists(p_cb->sdp_handle, BTA_HL_NUM_ADD_PROTO_LISTS, 235 (tSDP_PROTO_LIST_ELEM *)&add_proto_list); 236 } 237 238 if (result) 239 { 240 if (p_cb->srv_name[0] ) 241 { 242 result &= SDP_AddAttribute(p_cb->sdp_handle, 243 (UINT16)ATTR_ID_SERVICE_NAME, 244 (UINT8)TEXT_STR_DESC_TYPE, 245 (UINT32)(strlen(p_cb->srv_name) + 1), 246 (UINT8 *)p_cb->srv_name); 247 } /* end of setting optional service name */ 248 } 249 250 if (result) 251 { 252 if (p_cb->srv_desp[0] ) 253 { 254 result &= SDP_AddAttribute(p_cb->sdp_handle, 255 (UINT16)ATTR_ID_SERVICE_DESCRIPTION, 256 (UINT8)TEXT_STR_DESC_TYPE, 257 (UINT32)(strlen(p_cb->srv_desp) + 1), 258 (UINT8 *)p_cb->srv_desp); 259 260 } /* end of setting optional service description */ 261 262 } 263 264 if (result) 265 { 266 if (p_cb->provider_name[0] ) 267 { 268 result &= SDP_AddAttribute(p_cb->sdp_handle, 269 (UINT16)ATTR_ID_PROVIDER_NAME, 270 (UINT8)TEXT_STR_DESC_TYPE, 271 (UINT32)(strlen(p_cb->provider_name) + 1), 272 (UINT8 *)p_cb->provider_name); 273 } /* end of setting optional provider name */ 274 } 275 276 /* add supported feture list */ 277 278 if (result) 279 { 280 cnt=0; 281 for (i=1; i< BTA_HL_NUM_MDEPS; i++) 282 { 283 if (p_cb->sup_feature.mdep[i].mdep_id) 284 { 285 mdep_id = (UINT8)p_cb->sup_feature.mdep[i].mdep_id; 286 mdep_role = (UINT8)p_cb->sup_feature.mdep[i].mdep_cfg.mdep_role; 287 288 APPL_TRACE_DEBUG("num_of_mdep_data_types %d ", p_cb->sup_feature.mdep[i].mdep_cfg.num_of_mdep_data_types); 289 for (j=0; j<p_cb->sup_feature.mdep[i].mdep_cfg.num_of_mdep_data_types; j++) 290 { 291 sup_feature_list.list_elem[cnt].mdep_id = mdep_id; 292 sup_feature_list.list_elem[cnt].mdep_role = mdep_role; 293 sup_feature_list.list_elem[cnt].data_type = p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].data_type; 294 if (p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp[0] != '\0') 295 { 296 sup_feature_list.list_elem[cnt].p_mdep_desp = p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp; 297 } 298 else 299 { 300 sup_feature_list.list_elem[cnt].p_mdep_desp = NULL; 301 } 302 303 cnt++; 304 if (cnt==BTA_HL_NUM_SUP_FEATURE_ELEMS) 305 { 306 result = FALSE; 307 break; 308 } 309 } 310 } 311 } 312 sup_feature_list.num_elems = cnt; 313 result &= bta_hl_add_sup_feature_list (p_cb->sdp_handle, 314 sup_feature_list.num_elems, 315 sup_feature_list.list_elem); 316 } 317 if (result) 318 { 319 result &= SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_DATA_EXCH_SPEC, UINT_DESC_TYPE, 320 (UINT32)1, (UINT8*)&data_exchange_spec); 321 } 322 323 if (result) 324 { 325 326 result &= SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_MCAP_SUP_PROC, UINT_DESC_TYPE, 327 (UINT32)1, (UINT8*)&mcap_sup_proc); 328 } 329 330 if (result) 331 { 332 result &= SDP_AddUuidSequence(p_cb->sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list); 333 } 334 335 if (result) 336 { 337 for(i=0; i < num_services; i++) 338 { 339 bta_sys_add_uuid(svc_class_id_list[i]); 340 APPL_TRACE_DEBUG("dbg bta_sys_add_uuid i=%d uuid=0x%x", i, svc_class_id_list[i]); //todo 341 } 342 } 343 else 344 { 345 if (p_cb->sdp_handle) 346 { 347 SDP_DeleteRecord(p_cb->sdp_handle); 348 p_cb->sdp_handle = 0; 349 } 350 status = BTA_HL_STATUS_SDP_FAIL; 351 } 352 #if BTA_HL_DEBUG == TRUE 353 APPL_TRACE_DEBUG("bta_hl_sdp_update status=%s", bta_hl_status_code(status)); 354 #endif 355 return status; 356 } 357 358 359 /***************************************************************************** 360 ** 361 ** Function: bta_hl_sdp_register 362 ** 363 ** Purpose: Register an HDP application with SDP 364 ** 365 ** Parameters: p_cb - Pointer to MA instance control block 366 ** p_service_name - MA server name 367 ** inst_id - MAS instance ID 368 ** msg_type - Supported message type(s) 369 ** 370 ** 371 ** Returns: void 372 ** 373 *****************************************************************************/ 374 tBTA_HL_STATUS bta_hl_sdp_register (UINT8 app_idx) 375 { 376 UINT16 svc_class_id_list[BTA_HL_NUM_SVC_ELEMS]; 377 tSDP_PROTOCOL_ELEM proto_elem_list[BTA_HL_NUM_PROTO_ELEMS]; 378 tSDP_PROTO_LIST_ELEM add_proto_list; 379 tBTA_HL_SUP_FEATURE_LIST_ELEM sup_feature_list; 380 UINT16 browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP}; 381 UINT8 i,j, cnt,mdep_id, mdep_role; 382 UINT8 data_exchange_spec = BTA_HL_SDP_IEEE_11073_20601; 383 UINT8 mcap_sup_proc = BTA_HL_MCAP_SUP_PROC_MASK; 384 UINT16 profile_uuid = UUID_SERVCLASS_HDP_PROFILE; 385 UINT16 version = BTA_HL_VERSION; 386 UINT8 num_services=1; 387 tBTA_HL_APP_CB *p_cb = BTA_HL_GET_APP_CB_PTR(app_idx); 388 BOOLEAN result = TRUE; 389 tBTA_HL_STATUS status = BTA_HL_STATUS_OK; 390 391 #if BTA_HL_DEBUG == TRUE 392 APPL_TRACE_DEBUG("bta_hl_sdp_register app_idx=%d",app_idx); 393 #endif 394 395 if ((p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SOURCE) && 396 (!p_cb->sup_feature.advertize_source_sdp)) 397 { 398 return BTA_HL_STATUS_OK; 399 } 400 401 if ((p_cb->sdp_handle = SDP_CreateRecord()) == 0) 402 { 403 return BTA_HL_STATUS_SDP_NO_RESOURCE; 404 } 405 406 num_services=1; 407 svc_class_id_list[0]= UUID_SERVCLASS_HDP_SOURCE; 408 if (p_cb->sup_feature.app_role_mask == BTA_HL_MDEP_ROLE_MASK_SINK) 409 { 410 svc_class_id_list[0]= UUID_SERVCLASS_HDP_SINK; 411 } 412 else 413 { 414 if (p_cb->sup_feature.app_role_mask != BTA_HL_MDEP_ROLE_MASK_SOURCE) 415 { 416 /* dual role */ 417 num_services=2; 418 svc_class_id_list[1]= UUID_SERVCLASS_HDP_SINK; 419 } 420 } 421 result &= SDP_AddServiceClassIdList(p_cb->sdp_handle, num_services, svc_class_id_list); 422 423 if (result) 424 { 425 /* add the protocol element sequence */ 426 proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP; 427 proto_elem_list[0].num_params = 1; 428 proto_elem_list[0].params[0] = p_cb->ctrl_psm; 429 proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_MCAP_CTRL; 430 proto_elem_list[1].num_params = 1; 431 proto_elem_list[1].params[0] = version; 432 result &= SDP_AddProtocolList(p_cb->sdp_handle, BTA_HL_NUM_PROTO_ELEMS, proto_elem_list); 433 434 result &= SDP_AddProfileDescriptorList(p_cb->sdp_handle, profile_uuid, version); 435 } 436 437 if (result) 438 { 439 add_proto_list.num_elems = BTA_HL_NUM_ADD_PROTO_ELEMS; 440 add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP; 441 add_proto_list.list_elem[0].num_params = 1; 442 add_proto_list.list_elem[0].params[0] = p_cb->data_psm; 443 add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_MCAP_DATA; 444 add_proto_list.list_elem[1].num_params = 0; 445 result &= SDP_AddAdditionProtoLists(p_cb->sdp_handle, BTA_HL_NUM_ADD_PROTO_LISTS, 446 (tSDP_PROTO_LIST_ELEM *)&add_proto_list); 447 } 448 449 if (result) 450 { 451 if (p_cb->srv_name[0] ) 452 { 453 result &= SDP_AddAttribute(p_cb->sdp_handle, 454 (UINT16)ATTR_ID_SERVICE_NAME, 455 (UINT8)TEXT_STR_DESC_TYPE, 456 (UINT32)(strlen(p_cb->srv_name) + 1), 457 (UINT8 *)p_cb->srv_name); 458 } /* end of setting optional service name */ 459 } 460 461 if (result) 462 { 463 if (p_cb->srv_desp[0] ) 464 { 465 result &= SDP_AddAttribute(p_cb->sdp_handle, 466 (UINT16)ATTR_ID_SERVICE_DESCRIPTION, 467 (UINT8)TEXT_STR_DESC_TYPE, 468 (UINT32)(strlen(p_cb->srv_desp) + 1), 469 (UINT8 *)p_cb->srv_desp); 470 471 } /* end of setting optional service description */ 472 473 } 474 475 if (result) 476 { 477 if (p_cb->provider_name[0] ) 478 { 479 result &= SDP_AddAttribute(p_cb->sdp_handle, 480 (UINT16)ATTR_ID_PROVIDER_NAME, 481 (UINT8)TEXT_STR_DESC_TYPE, 482 (UINT32)(strlen(p_cb->provider_name) + 1), 483 (UINT8 *)p_cb->provider_name); 484 } /* end of setting optional provider name */ 485 } 486 487 /* add supported feture list */ 488 489 if (result) 490 { 491 cnt=0; 492 for (i=1; i<= p_cb->sup_feature.num_of_mdeps; i++) 493 { 494 mdep_id = (UINT8)p_cb->sup_feature.mdep[i].mdep_id; 495 mdep_role = (UINT8)p_cb->sup_feature.mdep[i].mdep_cfg.mdep_role; 496 497 for (j=0; j<p_cb->sup_feature.mdep[i].mdep_cfg.num_of_mdep_data_types; j++) 498 { 499 sup_feature_list.list_elem[cnt].mdep_id = mdep_id; 500 sup_feature_list.list_elem[cnt].mdep_role = mdep_role; 501 sup_feature_list.list_elem[cnt].data_type = p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].data_type; 502 if (p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp[0] != '\0') 503 { 504 sup_feature_list.list_elem[cnt].p_mdep_desp = p_cb->sup_feature.mdep[i].mdep_cfg.data_cfg[j].desp; 505 } 506 else 507 { 508 sup_feature_list.list_elem[cnt].p_mdep_desp = NULL; 509 } 510 511 cnt++; 512 if (cnt==BTA_HL_NUM_SUP_FEATURE_ELEMS) 513 { 514 result = FALSE; 515 break; 516 } 517 } 518 } 519 sup_feature_list.num_elems = cnt; 520 result &= bta_hl_add_sup_feature_list (p_cb->sdp_handle, 521 sup_feature_list.num_elems, 522 sup_feature_list.list_elem); 523 } 524 if (result) 525 { 526 result &= SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_DATA_EXCH_SPEC, UINT_DESC_TYPE, 527 (UINT32)1, (UINT8*)&data_exchange_spec); 528 } 529 530 if (result) 531 { 532 533 result &= SDP_AddAttribute(p_cb->sdp_handle, ATTR_ID_HDP_MCAP_SUP_PROC, UINT_DESC_TYPE, 534 (UINT32)1, (UINT8*)&mcap_sup_proc); 535 } 536 537 if (result) 538 { 539 result &= SDP_AddUuidSequence(p_cb->sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list); 540 } 541 542 if (result) 543 { 544 for(i=0; i < num_services; i++) 545 { 546 bta_sys_add_uuid(svc_class_id_list[i]); 547 APPL_TRACE_DEBUG("dbg bta_sys_add_uuid i=%d uuid=0x%x", i, svc_class_id_list[i]); //todo 548 } 549 } 550 else 551 { 552 if (p_cb->sdp_handle) 553 { 554 SDP_DeleteRecord(p_cb->sdp_handle); 555 p_cb->sdp_handle = 0; 556 } 557 status = BTA_HL_STATUS_SDP_FAIL; 558 } 559 #if BTA_HL_DEBUG == TRUE 560 APPL_TRACE_DEBUG("bta_hl_sdp_register status=%s", bta_hl_status_code(status)); 561 #endif 562 return status; 563 } 564 565 /******************************************************************************* 566 ** 567 ** Function bta_hl_find_sink_or_src_srv_class_in_db 568 ** 569 ** Description This function queries an SDP database for either a HDP Sink or 570 ** Source service class ID. 571 ** If the p_start_rec pointer is NULL, it looks from the beginning 572 ** of the database, else it continues from the next record after 573 ** p_start_rec. 574 ** 575 ** Returns Pointer to record containing service class, or NULL 576 ** 577 *******************************************************************************/ 578 tSDP_DISC_REC *bta_hl_find_sink_or_src_srv_class_in_db (const tSDP_DISCOVERY_DB *p_db, 579 const tSDP_DISC_REC *p_start_rec) 580 { 581 #if SDP_CLIENT_ENABLED == TRUE 582 tSDP_DISC_REC *p_rec; 583 tSDP_DISC_ATTR *p_attr, *p_sattr; 584 585 /* Must have a valid database */ 586 if (p_db == NULL) 587 return(NULL); 588 589 590 if (!p_start_rec) 591 { 592 593 p_rec = p_db->p_first_rec; 594 } 595 else 596 { 597 p_rec = p_start_rec->p_next_rec; 598 } 599 600 while (p_rec) 601 { 602 p_attr = p_rec->p_first_attr; 603 while (p_attr) 604 { 605 if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST) 606 && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) 607 { 608 for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) 609 { 610 if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) 611 && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) 612 && ( (p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SINK) || 613 (p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SOURCE)) ) 614 { 615 return(p_rec); 616 } 617 } 618 break; 619 } 620 621 p_attr = p_attr->p_next_attr; 622 } 623 624 p_rec = p_rec->p_next_rec; 625 } 626 #endif 627 /* If here, no matching UUID found */ 628 629 #if BTA_HL_DEBUG == TRUE 630 APPL_TRACE_DEBUG("bta_hl_find_sink_or_src_srv_class_in_db failed"); 631 #endif 632 633 return(NULL); 634 } 635 #endif /* HL_INCLUDED */ 636