static void bta_mce_search_cback(UINT16 result, void * user_data) { tSDP_DISC_REC *p_rec = NULL; tBTA_MCE_MAS_DISCOVERY_COMP evt_data; int found = 0; APPL_TRACE_DEBUG1("bta_mce_start_discovery_cback res: 0x%x", result); bta_mce_cb.sdp_active = BTA_MCE_SDP_ACT_NONE; if (bta_mce_cb.p_dm_cback == NULL) return; evt_data.status = BTA_MCE_FAILURE; bdcpy(evt_data.remote_addr, bta_mce_cb.remote_addr); evt_data.num_mas = 0; if (result == SDP_SUCCESS || result == SDP_DB_FULL) { do { tSDP_DISC_ATTR *p_attr; tSDP_PROTOCOL_ELEM pe; p_rec = SDP_FindServiceUUIDInDb(p_bta_mce_cfg->p_sdp_db, (tBT_UUID*) &bta_mce_mas_uuid, p_rec); APPL_TRACE_DEBUG1("p_rec:%p", p_rec); if (p_rec == NULL) break; if (!SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) continue; evt_data.mas[found].scn = pe.params[0]; if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_NAME)) == NULL) continue; evt_data.mas[found].p_srv_name = (char *) p_attr->attr_value.v.array; evt_data.mas[found].srv_name_len= SDP_DISC_ATTR_LEN(p_attr->attr_len_type); if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_MAS_INSTANCE_ID)) == NULL) break; evt_data.mas[found].instance_id = p_attr->attr_value.v.u8; if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_MSG_TYPE)) == NULL) break; evt_data.mas[found].msg_type = p_attr->attr_value.v.u8; found++; } while (p_rec != NULL && found < BTA_MCE_MAX_MAS_INSTANCES); evt_data.num_mas = found; evt_data.status = BTA_MCE_SUCCESS; } bta_mce_cb.p_dm_cback(BTA_MCE_MAS_DISCOVERY_COMP_EVT, (tBTA_MCE*) &evt_data, user_data); }
void hidh_get_str_attr( tSDP_DISC_REC *p_rec, UINT16 attr_id, UINT16 max_len, char *str ) { tSDP_DISC_ATTR *p_attr; UINT16 name_len; if ((p_attr = SDP_FindAttributeInRec(p_rec, attr_id)) != NULL) { if((name_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type)) < max_len ) { memcpy( str, (char *) p_attr->attr_value.v.array, name_len ); str[name_len] = '\0'; } else { memcpy( str, (char *) p_attr->attr_value.v.array, max_len-1 ); str[max_len] = '\0'; } } else str[0] = '\0'; }
static void hidh_search_callback (UINT16 sdp_result) { tSDP_DISCOVERY_DB *p_db = hh_cb.p_sdp_db; tSDP_DISC_REC *p_rec; tSDP_DISC_ATTR *p_attr, *p_subattr1, *p_subattr2, *p_repdesc; tBT_UUID hid_uuid; tHID_DEV_SDP_INFO *p_nvi = &hh_cb.sdp_rec; UINT16 attr_mask = 0; hid_uuid.len = LEN_UUID_16; hid_uuid.uu.uuid16 = UUID_SERVCLASS_HUMAN_INTERFACE; hh_cb.sdp_busy = FALSE; if (sdp_result != SDP_SUCCESS) { hh_cb.sdp_cback(sdp_result, 0, NULL); return; } if ((p_rec = SDP_FindServiceUUIDInDb (p_db, &hid_uuid, NULL)) == NULL) { hh_cb.sdp_cback(HID_SDP_NO_SERV_UUID, 0, NULL); return; } memset (&hh_cb.sdp_rec, 0, sizeof( tHID_DEV_SDP_INFO )); /* First, verify the mandatory fields we care about */ if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_DESCRIPTOR_LIST)) == NULL) || (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) || ((p_subattr1 = p_attr->attr_value.v.p_sub_attr) == NULL) || (SDP_DISC_ATTR_TYPE(p_subattr1->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) || ((p_subattr2 = p_subattr1->attr_value.v.p_sub_attr) == NULL) || ((p_repdesc = p_subattr2->p_next_attr) == NULL) || (SDP_DISC_ATTR_TYPE(p_repdesc->attr_len_type) != TEXT_STR_DESC_TYPE)) { hh_cb.sdp_cback(HID_SDP_MANDATORY_MISSING, 0, NULL); return; } if ((p_nvi->dscp_info.dl_len = SDP_DISC_ATTR_LEN(p_repdesc->attr_len_type)) != 0) p_nvi->dscp_info.dsc_list = (UINT8 *) &p_repdesc->attr_value; if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_VIRTUAL_CABLE)) != NULL) && (p_attr->attr_value.v.u8) ) { attr_mask |= HID_VIRTUAL_CABLE; } if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_RECONNECT_INITIATE)) != NULL) && (p_attr->attr_value.v.u8) ) { attr_mask |= HID_RECONN_INIT; } if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_NORMALLY_CONNECTABLE)) != NULL) && (p_attr->attr_value.v.u8) ) { attr_mask |= HID_NORMALLY_CONNECTABLE; } if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_SDP_DISABLE)) != NULL)&& (p_attr->attr_value.v.u8) ) { attr_mask |= HID_SDP_DISABLE; } if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_BATTERY_POWER)) != NULL)&& (p_attr->attr_value.v.u8) ) { attr_mask |= HID_BATTERY_POWER; } if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_REMOTE_WAKE)) != NULL)&& (p_attr->attr_value.v.u8) ) { attr_mask |= HID_REMOTE_WAKE; } hidh_get_str_attr( p_rec, ATTR_ID_SERVICE_NAME, HID_MAX_SVC_NAME_LEN, p_nvi->svc_name ); hidh_get_str_attr( p_rec, ATTR_ID_SERVICE_DESCRIPTION, HID_MAX_SVC_DESCR_LEN, p_nvi->svc_descr ); hidh_get_str_attr( p_rec, ATTR_ID_PROVIDER_NAME, HID_MAX_PROV_NAME_LEN, p_nvi->prov_name ); if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_DEVICE_RELNUM)) != NULL)) { p_nvi->rel_num = p_attr->attr_value.v.u16; } if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_COUNTRY_CODE)) != NULL)) { p_nvi->ctry_code = p_attr->attr_value.v.u8; } if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_DEVICE_SUBCLASS)) != NULL)) { p_nvi->sub_class = p_attr->attr_value.v.u8; } if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_PARSER_VERSION)) != NULL)) { p_nvi->hpars_ver = p_attr->attr_value.v.u16; } if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_LINK_SUPERVISION_TO)) != NULL)) { attr_mask |= HID_SUP_TOUT_AVLBL; p_nvi->sup_timeout = p_attr->attr_value.v.u16; } if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_SSR_HOST_MAX_LAT)) != NULL)) { attr_mask |= HID_SSR_MAX_LATENCY; p_nvi->ssr_max_latency = p_attr->attr_value.v.u16; } else p_nvi->ssr_max_latency = HID_SSR_PARAM_INVALID; if (((p_attr = SDP_FindAttributeInRec (p_rec, ATTR_ID_HID_SSR_HOST_MIN_TOUT)) != NULL)) { attr_mask |= HID_SSR_MIN_TOUT; p_nvi->ssr_min_tout = p_attr->attr_value.v.u16; } else p_nvi->ssr_max_latency = HID_SSR_PARAM_INVALID; hh_cb.sdp_rec.p_sdp_layer_rec = p_rec; hh_cb.sdp_cback(SDP_SUCCESS, attr_mask, &hh_cb.sdp_rec); }
/******************************************************************************* ** ** Function bta_hf_client_sdp_find_attr ** ** Description Process SDP discovery results to find requested attribute ** ** ** Returns TRUE if results found, FALSE otherwise. ** *******************************************************************************/ BOOLEAN bta_hf_client_sdp_find_attr(void) { tSDP_DISC_REC *p_rec = NULL; tSDP_DISC_ATTR *p_attr; tSDP_PROTOCOL_ELEM pe; BOOLEAN result = FALSE; bta_hf_client_cb.scb.peer_version = HFP_VERSION_1_1; /* Default version */ /* loop through all records we found */ while (TRUE) { /* get next record; if none found, we're done */ if ((p_rec = SDP_FindServiceInDb(bta_hf_client_cb.scb.p_disc_db, UUID_SERVCLASS_AG_HANDSFREE, p_rec)) == NULL) { break; } /* get scn from proto desc list if initiator */ if (bta_hf_client_cb.scb.role == BTA_HF_CLIENT_INT) { if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { bta_hf_client_cb.scb.peer_scn = (UINT8) pe.params[0]; } else { continue; } } /* get profile version (if failure, version parameter is not updated) */ SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_HF_HANDSFREE, &bta_hf_client_cb.scb.peer_version); /* get features */ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL) { /* Found attribute. Get value. */ /* There might be race condition between SDP and BRSF. */ /* Do not update if we already received BRSF. */ if (bta_hf_client_cb.scb.peer_features == 0) { bta_hf_client_cb.scb.peer_features = p_attr->attr_value.v.u16; /* SDP and BRSF WBS bit are different, correct it if set */ if (bta_hf_client_cb.scb.peer_features & 0x0020) { bta_hf_client_cb.scb.peer_features &= ~0x0020; bta_hf_client_cb.scb.peer_features |= BTA_HF_CLIENT_PEER_CODEC; } /* get network for ability to reject calls */ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_NETWORK)) != NULL) { if (p_attr->attr_value.v.u16 == 0x01) { bta_hf_client_cb.scb.peer_features |= BTA_HF_CLIENT_PEER_REJECT; } } } } /* found what we needed */ result = TRUE; break; } APPL_TRACE_DEBUG("%s peer_version=0x%x peer_features=0x%x", __FUNCTION__, bta_hf_client_cb.scb.peer_version, bta_hf_client_cb.scb.peer_features); return result; }
/******************************************************************************* ** ** Function bta_ag_sdp_find_attr ** ** Description Process SDP discovery results to find requested attributes ** for requested service. ** ** ** Returns TRUE if results found, FALSE otherwise. ** *******************************************************************************/ BOOLEAN bta_ag_sdp_find_attr(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service) { tSDP_DISC_REC *p_rec = NULL; tSDP_DISC_ATTR *p_attr; tSDP_PROTOCOL_ELEM pe; UINT16 uuid; BOOLEAN result = FALSE; if (service & BTA_HFP_SERVICE_MASK) { uuid = UUID_SERVCLASS_HF_HANDSFREE; p_scb->peer_version = HFP_VERSION_1_1; /* Default version */ } else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT) { uuid = UUID_SERVCLASS_HEADSET_HS; p_scb->peer_version = 0x0100; /* Default version */ } else { return result; } /* loop through all records we found */ while (TRUE) { /* get next record; if none found, we're done */ if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL) { if (uuid == UUID_SERVCLASS_HEADSET_HS) { /* Search again in case the peer device is HSP v1.0 */ uuid = UUID_SERVCLASS_HEADSET; if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL) { break; } } else break; } /* get scn from proto desc list if initiator */ if (p_scb->role == BTA_AG_INT) { if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { p_scb->peer_scn = (UINT8) pe.params[0]; } else { continue; } } /* get profile version (if failure, version parameter is not updated) */ SDP_FindProfileVersionInRec(p_rec, uuid, &p_scb->peer_version); /* get features if HFP */ if (service & BTA_HFP_SERVICE_MASK) { if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL) { /* Found attribute. Get value. */ /* There might be race condition between SDP and BRSF. */ /* Do not update if we already received BRSF. */ APPL_TRACE_DEBUG1("bta_ag_sdp_find_attr: peer_attr 0x%x", p_attr->attr_value.v.u16); APPL_TRACE_WARNING0("bta_ag_sdp_find_attr not using value as p_scb->peer_features"); /* Do not use the value as peer_features. ** ** if (p_scb->peer_features == 0) ** p_scb->peer_features = p_attr->attr_value.v.u16; ** ** Reason is, that the service connection negotiation depends on the ** BTA_AG_FEAT_3WAY feature (see the calling of bta_ag_svc_conn_open() ** for BTA_AG_HF_CMD_CMER). A race condition could result in erratic ** behavior. ** ** Background: Using the attr_value for peer_feature was a change introduced ** in android 4.2. That version triggered a number of bug-reports about ** bluetooth being broken. ** ** This problem was observed first hand on a BMW 2005/E46 car kit which does ** not send AT+BRSF and behaves as if it would not support 3WAY. With the newly ** introduced code for using attr_value as peer_feature the result was that ** bluetooth connections to the car kit always terminated after 5 seconds ** (via BTA_AG_SVC_TOUT_EVT). */ } } else /* HSP */ { if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL)) != NULL) { /* Remote volume control of HSP */ if (p_attr->attr_value.v.u8) p_scb->peer_features |= BTA_AG_PEER_FEAT_VOL; else p_scb->peer_features &= ~BTA_AG_PEER_FEAT_VOL; } } /* found what we needed */ result = TRUE; break; } return result; }
/******************************************************************************* ** ** Function bta_ag_sdp_find_attr ** ** Description Process SDP discovery results to find requested attributes ** for requested service. ** ** ** Returns TRUE if results found, FALSE otherwise. ** *******************************************************************************/ BOOLEAN bta_ag_sdp_find_attr(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service) { tSDP_DISC_REC *p_rec = NULL; tSDP_DISC_ATTR *p_attr; tSDP_PROTOCOL_ELEM pe; UINT16 uuid; BOOLEAN result = FALSE; if (service & BTA_HFP_SERVICE_MASK) { uuid = UUID_SERVCLASS_HF_HANDSFREE; p_scb->peer_version = HFP_VERSION_1_1; /* Default version */ } else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT) { uuid = UUID_SERVCLASS_HEADSET_HS; p_scb->peer_version = 0x0100; /* Default version */ } else { return result; } /* loop through all records we found */ while (TRUE) { /* get next record; if none found, we're done */ if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL) { if (uuid == UUID_SERVCLASS_HEADSET_HS) { /* Search again in case the peer device is HSP v1.0 */ uuid = UUID_SERVCLASS_HEADSET; if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL) { break; } } else break; } /* get scn from proto desc list if initiator */ if (p_scb->role == BTA_AG_INT) { if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) { p_scb->peer_scn = (UINT8) pe.params[0]; } else { continue; } } /* get profile version (if failure, version parameter is not updated) */ SDP_FindProfileVersionInRec(p_rec, uuid, &p_scb->peer_version); /* get features if HFP */ if (service & BTA_HFP_SERVICE_MASK) { if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL) { /* Found attribute. Get value. */ /* There might be race condition between SDP and BRSF. */ /* Do not update if we already received BRSF. */ if (p_scb->peer_features == 0) p_scb->peer_features = p_attr->attr_value.v.u16; } } else /* HSP */ { if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL)) != NULL) { /* Remote volume control of HSP */ if (p_attr->attr_value.v.u8) p_scb->peer_features |= BTA_AG_PEER_FEAT_VOL; else p_scb->peer_features &= ~BTA_AG_PEER_FEAT_VOL; } } /* found what we needed */ result = TRUE; break; } return result; }