| /****************************************************************************** |
| * |
| * 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); |
| } |
| } |
| } |