/******************************************************************************
*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include <frameworks/base/core/proto/android/bluetooth/enums.pb.h>
#include <frameworks/base/core/proto/android/bluetooth/hci/enums.pb.h>
#include "bt_types.h"
#include "btm_int.h"
#include "common/metrics.h"
#include "device/include/controller.h"
#include "l2c_int.h"
#include "stack/gatt/connection_manager.h"
#include "stack/include/hcimsgs.h"
extern void btm_ble_advertiser_notify_terminated_legacy(
uint8_t status, uint16_t connection_handle);
/** This function get BLE connection state */
tBTM_BLE_CONN_ST btm_ble_get_conn_st(void) {
return btm_cb.ble_ctr_cb.conn_state;
}
/** This function set BLE connection state */
void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st) {
btm_cb.ble_ctr_cb.conn_state = new_st;
if (new_st == BLE_CONNECTING)
btm_ble_set_topology_mask(BTM_BLE_STATE_INIT_BIT);
else
btm_ble_clear_topology_mask(BTM_BLE_STATE_INIT_BIT);
}
void btm_send_hci_create_connection(
uint16_t scan_int, uint16_t scan_win, uint8_t init_filter_policy,
uint8_t addr_type_peer, const RawAddress& bda_peer, uint8_t addr_type_own,
uint16_t conn_int_min, uint16_t conn_int_max, uint16_t conn_latency,
uint16_t conn_timeout, uint16_t min_ce_len, uint16_t max_ce_len,
uint8_t initiating_phys) {
if (controller_get_interface()->supports_ble_extended_advertising()) {
EXT_CONN_PHY_CFG phy_cfg[3]; // maximum three phys
int phy_cnt =
std::bitset<std::numeric_limits<uint8_t>::digits>(initiating_phys)
.count();
LOG_ASSERT(phy_cnt <= 3) << "More than three phys provided";
// TODO(jpawlowski): tune parameters for different transports
for (int i = 0; i < phy_cnt; i++) {
phy_cfg[i].scan_int = scan_int;
phy_cfg[i].scan_win = scan_win;
phy_cfg[i].conn_int_min = conn_int_min;
phy_cfg[i].conn_int_max = conn_int_max;
phy_cfg[i].conn_latency = conn_latency;
phy_cfg[i].sup_timeout = conn_timeout;
phy_cfg[i].min_ce_len = min_ce_len;
phy_cfg[i].max_ce_len = max_ce_len;
}
addr_type_peer &= ~BLE_ADDR_TYPE_ID_BIT;
btsnd_hcic_ble_ext_create_conn(init_filter_policy, addr_type_own,
addr_type_peer, bda_peer, initiating_phys,
phy_cfg);
} else {
btsnd_hcic_ble_create_ll_conn(scan_int, scan_win, init_filter_policy,
addr_type_peer, bda_peer, addr_type_own,
conn_int_min, conn_int_max, conn_latency,
conn_timeout, min_ce_len, max_ce_len);
}
btm_ble_set_conn_st(BLE_CONNECTING);
}
/** LE connection complete. */
void btm_ble_create_ll_conn_complete(uint8_t status) {
if (status == HCI_SUCCESS) return;
LOG(WARNING) << "LE Create Connection attempt failed, status="
<< loghex(status);
if (status == HCI_ERR_COMMAND_DISALLOWED) {
btm_ble_set_conn_st(BLE_CONNECTING);
LOG(ERROR) << "LE Create Connection - command disallowed";
} else {
btm_ble_set_conn_st(BLE_CONN_IDLE);
btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, NULL, status);
}
}
/** LE connection complete. */
void btm_ble_conn_complete(uint8_t* p, UNUSED_ATTR uint16_t evt_len,
bool enhanced) {
#if (BLE_PRIVACY_SPT == TRUE)
uint8_t peer_addr_type;
#endif
RawAddress local_rpa, peer_rpa;
uint8_t role, status, bda_type;
uint16_t handle;
RawAddress bda;
uint16_t conn_interval, conn_latency, conn_timeout;
bool match = false;
STREAM_TO_UINT8(status, p);
STREAM_TO_UINT16(handle, p);
STREAM_TO_UINT8(role, p);
STREAM_TO_UINT8(bda_type, p);
STREAM_TO_BDADDR(bda, p);
if (enhanced) {
STREAM_TO_BDADDR(local_rpa, p);
STREAM_TO_BDADDR(peer_rpa, p);
}
STREAM_TO_UINT16(conn_interval, p);
STREAM_TO_UINT16(conn_latency, p);
STREAM_TO_UINT16(conn_timeout, p);
handle = HCID_GET_HANDLE(handle);
uint32_t hci_ble_event =
enhanced ? android::bluetooth::hci::BLE_EVT_ENHANCED_CONN_COMPLETE_EVT
: android::bluetooth::hci::BLE_EVT_CONN_COMPLETE_EVT;
if (status == HCI_SUCCESS) {
#if (BLE_PRIVACY_SPT == TRUE)
peer_addr_type = bda_type;
bool addr_is_rpa =
(peer_addr_type == BLE_ADDR_RANDOM && BTM_BLE_IS_RESOLVE_BDA(bda));
/* We must translate whatever address we received into the "pseudo" address.
* i.e. if we bonded with device that was using RPA for first connection,
* "pseudo" address is equal to this RPA. If it later decides to use Public
* address, or Random Static Address, we convert it into the "pseudo"
* address here. */
if (!addr_is_rpa || peer_addr_type & BLE_ADDR_TYPE_ID_BIT) {
match = btm_identity_addr_to_random_pseudo(&bda, &bda_type, true);
}
/* possiblly receive connection complete with resolvable random while
the device has been paired */
if (!match && addr_is_rpa) {
tBTM_SEC_DEV_REC* match_rec = btm_ble_resolve_random_addr(bda);
if (match_rec) {
LOG(INFO) << __func__ << ": matched and resolved random address";
match = true;
match_rec->ble.active_addr_type = BTM_BLE_ADDR_RRA;
match_rec->ble.cur_rand_addr = bda;
if (!btm_ble_init_pseudo_addr(match_rec, bda)) {
/* assign the original address to be the current report address */
bda = match_rec->ble.pseudo_addr;
} else {
bda = match_rec->bd_addr;
}
} else {
LOG(INFO) << __func__ << ": unable to match and resolve random address";
}
}
#endif
// Log for the HCI success case after resolving Bluetooth address
bluetooth::common::LogLinkLayerConnectionEvent(
&bda, handle, android::bluetooth::DIRECTION_UNKNOWN,
android::bluetooth::LINK_TYPE_ACL, android::bluetooth::hci::CMD_UNKNOWN,
android::bluetooth::hci::EVT_BLE_META, hci_ble_event, status,
android::bluetooth::hci::STATUS_UNKNOWN);
if (role == HCI_ROLE_MASTER) {
btm_ble_set_conn_st(BLE_CONN_IDLE);
}
connection_manager::on_connection_complete(bda);
btm_ble_connected(bda, handle, HCI_ENCRYPT_MODE_DISABLED, role, bda_type,
match);
l2cble_conn_comp(handle, role, bda, bda_type, conn_interval, conn_latency,
conn_timeout);
#if (BLE_PRIVACY_SPT == TRUE)
if (enhanced) {
btm_ble_refresh_local_resolvable_private_addr(bda, local_rpa);
if (peer_addr_type & BLE_ADDR_TYPE_ID_BIT)
btm_ble_refresh_peer_resolvable_private_addr(bda, peer_rpa,
BLE_ADDR_RANDOM);
}
#endif
} else {
// Log for non HCI success case
bluetooth::common::LogLinkLayerConnectionEvent(
&bda, handle, android::bluetooth::DIRECTION_UNKNOWN,
android::bluetooth::LINK_TYPE_ACL, android::bluetooth::hci::CMD_UNKNOWN,
android::bluetooth::hci::EVT_BLE_META, hci_ble_event, status,
android::bluetooth::hci::STATUS_UNKNOWN);
role = HCI_ROLE_UNKNOWN;
if (status != HCI_ERR_ADVERTISING_TIMEOUT) {
btm_ble_set_conn_st(BLE_CONN_IDLE);
#if (BLE_PRIVACY_SPT == TRUE)
btm_ble_disable_resolving_list(BTM_BLE_RL_INIT, true);
#endif
} else {
#if (BLE_PRIVACY_SPT == TRUE)
btm_cb.ble_ctr_cb.inq_var.adv_mode = BTM_BLE_ADV_DISABLE;
btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, true);
#endif
}
}
btm_ble_update_mode_operation(role, &bda, status);
if (role == HCI_ROLE_SLAVE)
btm_ble_advertiser_notify_terminated_legacy(status, handle);
}
void btm_ble_create_conn_cancel() {
btsnd_hcic_ble_create_conn_cancel();
btm_ble_set_conn_st(BLE_CONN_CANCEL);
}
void btm_ble_create_conn_cancel_complete(uint8_t* p) {
uint8_t status;
STREAM_TO_UINT8(status, p);
if (status != HCI_SUCCESS) {
// Only log errors to prevent log spam due to whitelist connections
bluetooth::common::LogLinkLayerConnectionEvent(
nullptr, bluetooth::common::kUnknownConnectionHandle,
android::bluetooth::DIRECTION_OUTGOING,
android::bluetooth::LINK_TYPE_ACL,
android::bluetooth::hci::CMD_BLE_CREATE_CONN_CANCEL,
android::bluetooth::hci::EVT_COMMAND_COMPLETE,
android::bluetooth::hci::BLE_EVT_UNKNOWN, status,
android::bluetooth::hci::STATUS_UNKNOWN);
}
if (status == HCI_ERR_COMMAND_DISALLOWED) {
/* This is a sign that logic around keeping connection state is broken */
LOG(ERROR)
<< "Attempt to cancel LE connection, when no connection is pending.";
if (btm_ble_get_conn_st() == BLE_CONN_CANCEL) {
btm_ble_set_conn_st(BLE_CONN_IDLE);
btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, nullptr, status);
}
}
}