/******************************************************************************* ** ** Function sdp_disconnect ** ** Description This function disconnects a connection. ** ** Returns void ** *******************************************************************************/ void sdp_disconnect (tCONN_CB*p_ccb, UINT16 reason) { #if (defined(SDP_BROWSE_PLUS) && SDP_BROWSE_PLUS == TRUE) /* If we are browsing for multiple UUIDs ... */ if ((p_ccb->con_state == SDP_STATE_CONNECTED) && (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) && ((reason == SDP_SUCCESS) || (reason == SDP_NO_RECS_MATCH))) { /* If the browse found something, do no more searching */ if ((p_ccb->cur_uuid_idx == 0) && (p_ccb->p_db->p_first_rec)) p_ccb->cur_uuid_idx = p_ccb->p_db->num_uuid_filters; while (++p_ccb->cur_uuid_idx < p_ccb->p_db->num_uuid_filters) { /* Check we have not already found the UUID (maybe through browse) */ if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len == 2) && (SDP_FindServiceInDb (p_ccb->p_db, p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].uu.uuid16, NULL))) continue; if ((p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx].len > 2) && (SDP_FindServiceUUIDInDb (p_ccb->p_db, &p_ccb->p_db->uuid_filters[p_ccb->cur_uuid_idx], NULL))) continue; p_ccb->cur_handle = 0; SDP_TRACE_EVENT1 ("SDP - looking for for more, CID: 0x%x", p_ccb->connection_id); sdp_disc_connected (p_ccb); return; } } if ((reason == SDP_NO_RECS_MATCH) && (p_ccb->p_db->p_first_rec)) reason = SDP_SUCCESS; #endif SDP_TRACE_EVENT1 ("SDP - disconnect CID: 0x%x", p_ccb->connection_id); /* Check if we have a connection ID */ if (p_ccb->connection_id != 0) { L2CA_DisconnectReq (p_ccb->connection_id); p_ccb->disconnect_reason = reason; } /* If at setup state, we may not get callback ind from L2CAP */ /* Call user callback immediately */ if (p_ccb->con_state == SDP_STATE_CONN_SETUP) { /* Tell the user if he has a callback */ if (p_ccb->p_cb) (*p_ccb->p_cb) (reason); else if (p_ccb->p_cb2) (*p_ccb->p_cb2) (reason, p_ccb->user_data); sdpu_release_ccb (p_ccb); } }
/******************************************************************************* ** ** 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_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. */ 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; }