blob: 755fb3aab278d06dc874aa9ef6e8abbdbeac4318 [file] [log] [blame]
/*
* Copyright 2018 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 "acl_connection_handler.h"
#include <hci/hci_packets.h>
#include "hci/address.h"
#include "log.h"
namespace rootcanal {
using ::bluetooth::hci::Address;
using ::bluetooth::hci::AddressType;
using ::bluetooth::hci::AddressWithType;
void AclConnectionHandler::Reset(std::function<void(TaskId)> stopStream) {
// Leave no dangling periodic task.
for (auto& [_, sco_connection] : sco_connections_) {
sco_connection.StopStream(stopStream);
}
sco_connections_.clear();
acl_connections_.clear();
}
bool AclConnectionHandler::HasHandle(uint16_t handle) const {
return acl_connections_.count(handle) != 0;
}
bool AclConnectionHandler::HasScoHandle(uint16_t handle) const {
return sco_connections_.count(handle) != 0;
}
uint16_t AclConnectionHandler::GetUnusedHandle() {
// Keep a reserved range of handles for CIS connections implemented
// in the rust module.
while (HasHandle(last_handle_) || HasScoHandle(last_handle_) ||
(last_handle_ >= kCisHandleRangeStart &&
last_handle_ < kCisHandleRangeEnd)) {
last_handle_ = (last_handle_ + 1) % kReservedHandle;
}
uint16_t unused_handle = last_handle_;
last_handle_ = (last_handle_ + 1) % kReservedHandle;
return unused_handle;
}
bool AclConnectionHandler::CreatePendingConnection(Address addr,
bool authenticate_on_connect,
bool allow_role_switch) {
if (classic_connection_pending_) {
return false;
}
classic_connection_pending_ = true;
pending_connection_address_ = addr;
authenticate_pending_classic_connection_ = authenticate_on_connect;
pending_classic_connection_allow_role_switch_ = allow_role_switch;
return true;
}
bool AclConnectionHandler::HasPendingConnection(Address addr) const {
return classic_connection_pending_ && pending_connection_address_ == addr;
}
bool AclConnectionHandler::AuthenticatePendingConnection() const {
return authenticate_pending_classic_connection_;
}
bool AclConnectionHandler::CancelPendingConnection(Address addr) {
if (!classic_connection_pending_ || pending_connection_address_ != addr) {
return false;
}
classic_connection_pending_ = false;
pending_connection_address_ = Address::kEmpty;
pending_le_connection_resolved_address_ = AddressWithType();
return true;
}
bool AclConnectionHandler::CreatePendingLeConnection(
AddressWithType peer, AddressWithType resolved_peer,
AddressWithType local_address) {
for (auto pair : acl_connections_) {
auto connection = std::get<AclConnection>(pair);
if (connection.GetAddress() == peer ||
connection.GetResolvedAddress() == resolved_peer) {
INFO("{}: {} is already connected", __func__, peer);
if (connection.GetResolvedAddress() == resolved_peer) {
INFO("{}: allowing a second connection with {}", __func__,
resolved_peer);
} else {
return false;
}
}
}
if (le_connection_pending_) {
INFO("{}: connection already pending", __func__);
return false;
}
le_connection_pending_ = true;
pending_le_connection_address_ = peer;
pending_le_connection_own_address_ = local_address;
pending_le_connection_resolved_address_ = resolved_peer;
return true;
}
bool AclConnectionHandler::HasPendingLeConnection(AddressWithType addr) const {
return le_connection_pending_ && pending_le_connection_address_ == addr;
}
bool AclConnectionHandler::CancelPendingLeConnection(AddressWithType addr) {
if (!le_connection_pending_ || pending_le_connection_address_ != addr) {
return false;
}
le_connection_pending_ = false;
pending_le_connection_address_ =
AddressWithType{Address::kEmpty, AddressType::PUBLIC_DEVICE_ADDRESS};
pending_le_connection_resolved_address_ =
AddressWithType{Address::kEmpty, AddressType::PUBLIC_DEVICE_ADDRESS};
return true;
}
uint16_t AclConnectionHandler::CreateConnection(Address addr,
Address own_addr) {
if (CancelPendingConnection(addr)) {
uint16_t handle = GetUnusedHandle();
acl_connections_.emplace(
handle,
AclConnection{
AddressWithType{addr, AddressType::PUBLIC_DEVICE_ADDRESS},
AddressWithType{own_addr, AddressType::PUBLIC_DEVICE_ADDRESS},
AddressWithType(), Phy::Type::BR_EDR,
bluetooth::hci::Role::CENTRAL});
return handle;
}
return kReservedHandle;
}
uint16_t AclConnectionHandler::CreateLeConnection(AddressWithType addr,
AddressWithType own_addr,
bluetooth::hci::Role role) {
AddressWithType resolved_peer = pending_le_connection_resolved_address_;
if (CancelPendingLeConnection(addr)) {
uint16_t handle = GetUnusedHandle();
acl_connections_.emplace(handle,
AclConnection{addr, own_addr, resolved_peer,
Phy::Type::LOW_ENERGY, role});
return handle;
}
return kReservedHandle;
}
bool AclConnectionHandler::Disconnect(uint16_t handle,
std::function<void(TaskId)> stopStream) {
if (HasScoHandle(handle)) {
sco_connections_.at(handle).StopStream(std::move(stopStream));
sco_connections_.erase(handle);
return true;
}
if (HasHandle(handle)) {
// It is the responsibility of the caller to remove SCO connections
// with connected peer first.
uint16_t sco_handle = GetScoHandle(GetAddress(handle).GetAddress());
ASSERT(!HasScoHandle(sco_handle));
acl_connections_.erase(handle);
return true;
}
return false;
}
uint16_t AclConnectionHandler::GetHandle(AddressWithType addr) const {
for (auto pair : acl_connections_) {
if (std::get<AclConnection>(pair).GetAddress() == addr) {
return std::get<0>(pair);
}
}
return kReservedHandle;
}
uint16_t AclConnectionHandler::GetHandleOnlyAddress(
bluetooth::hci::Address addr) const {
for (auto pair : acl_connections_) {
if (std::get<AclConnection>(pair).GetAddress().GetAddress() == addr) {
return std::get<0>(pair);
}
}
return kReservedHandle;
}
AclConnection& AclConnectionHandler::GetAclConnection(uint16_t handle) {
ASSERT_LOG(HasHandle(handle), "Unknown handle %d", handle);
return acl_connections_.at(handle);
}
AddressWithType AclConnectionHandler::GetAddress(uint16_t handle) const {
ASSERT_LOG(HasHandle(handle), "Unknown handle %hd", handle);
return acl_connections_.at(handle).GetAddress();
}
std::optional<AddressWithType> AclConnectionHandler::GetAddressSafe(
uint16_t handle) const {
return HasHandle(handle) ? acl_connections_.at(handle).GetAddress()
: std::optional<AddressWithType>();
}
Address AclConnectionHandler::GetScoAddress(uint16_t handle) const {
ASSERT_LOG(HasScoHandle(handle), "Unknown SCO handle %hd", handle);
return sco_connections_.at(handle).GetAddress();
}
AddressWithType AclConnectionHandler::GetOwnAddress(uint16_t handle) const {
ASSERT_LOG(HasHandle(handle), "Unknown handle %hd", handle);
return acl_connections_.at(handle).GetOwnAddress();
}
AddressWithType AclConnectionHandler::GetResolvedAddress(
uint16_t handle) const {
ASSERT_LOG(HasHandle(handle), "Unknown handle %hd", handle);
return acl_connections_.at(handle).GetResolvedAddress();
}
void AclConnectionHandler::Encrypt(uint16_t handle) {
if (!HasHandle(handle)) {
return;
}
acl_connections_.at(handle).Encrypt();
}
bool AclConnectionHandler::IsEncrypted(uint16_t handle) const {
if (!HasHandle(handle)) {
return false;
}
return acl_connections_.at(handle).IsEncrypted();
}
void AclConnectionHandler::SetRssi(uint16_t handle, int8_t rssi) {
if (HasHandle(handle)) {
acl_connections_.at(handle).SetRssi(rssi);
}
}
int8_t AclConnectionHandler::GetRssi(uint16_t handle) const {
return HasHandle(handle) ? acl_connections_.at(handle).GetRssi() : 0;
}
Phy::Type AclConnectionHandler::GetPhyType(uint16_t handle) const {
if (!HasHandle(handle)) {
return Phy::Type::BR_EDR;
}
return acl_connections_.at(handle).GetPhyType();
}
uint16_t AclConnectionHandler::GetAclLinkPolicySettings(uint16_t handle) const {
return acl_connections_.at(handle).GetLinkPolicySettings();
};
void AclConnectionHandler::SetAclLinkPolicySettings(uint16_t handle,
uint16_t settings) {
acl_connections_.at(handle).SetLinkPolicySettings(settings);
}
bluetooth::hci::Role AclConnectionHandler::GetAclRole(uint16_t handle) const {
return acl_connections_.at(handle).GetRole();
};
void AclConnectionHandler::SetAclRole(uint16_t handle,
bluetooth::hci::Role role) {
acl_connections_.at(handle).SetRole(role);
}
void AclConnectionHandler::CreateScoConnection(
bluetooth::hci::Address addr, ScoConnectionParameters const& parameters,
ScoState state, ScoDatapath datapath, bool legacy) {
uint16_t sco_handle = GetUnusedHandle();
sco_connections_.emplace(
sco_handle, ScoConnection(addr, parameters, state, datapath, legacy));
}
bool AclConnectionHandler::HasPendingScoConnection(
bluetooth::hci::Address addr) const {
for (const auto& pair : sco_connections_) {
if (std::get<ScoConnection>(pair).GetAddress() == addr) {
ScoState state = std::get<ScoConnection>(pair).GetState();
return state == SCO_STATE_PENDING ||
state == SCO_STATE_SENT_ESCO_CONNECTION_REQUEST ||
state == SCO_STATE_SENT_SCO_CONNECTION_REQUEST;
}
}
return false;
}
ScoState AclConnectionHandler::GetScoConnectionState(
bluetooth::hci::Address addr) const {
for (const auto& pair : sco_connections_) {
if (std::get<ScoConnection>(pair).GetAddress() == addr) {
return std::get<ScoConnection>(pair).GetState();
}
}
return SCO_STATE_CLOSED;
}
bool AclConnectionHandler::IsLegacyScoConnection(
bluetooth::hci::Address addr) const {
for (const auto& pair : sco_connections_) {
if (std::get<ScoConnection>(pair).GetAddress() == addr) {
return std::get<ScoConnection>(pair).IsLegacy();
}
}
return false;
}
void AclConnectionHandler::CancelPendingScoConnection(
bluetooth::hci::Address addr) {
for (auto it = sco_connections_.begin(); it != sco_connections_.end(); it++) {
if (std::get<ScoConnection>(*it).GetAddress() == addr) {
sco_connections_.erase(it);
return;
}
}
}
bool AclConnectionHandler::AcceptPendingScoConnection(
bluetooth::hci::Address addr, ScoLinkParameters const& parameters,
std::function<TaskId()> startStream) {
for (auto& pair : sco_connections_) {
if (std::get<ScoConnection>(pair).GetAddress() == addr) {
std::get<ScoConnection>(pair).SetLinkParameters(parameters);
std::get<ScoConnection>(pair).SetState(ScoState::SCO_STATE_OPENED);
std::get<ScoConnection>(pair).StartStream(std::move(startStream));
return true;
}
}
return false;
}
bool AclConnectionHandler::AcceptPendingScoConnection(
bluetooth::hci::Address addr, ScoConnectionParameters const& parameters,
std::function<TaskId()> startStream) {
for (auto& pair : sco_connections_) {
if (std::get<ScoConnection>(pair).GetAddress() == addr) {
bool ok =
std::get<ScoConnection>(pair).NegotiateLinkParameters(parameters);
std::get<ScoConnection>(pair).SetState(ok ? ScoState::SCO_STATE_OPENED
: ScoState::SCO_STATE_CLOSED);
if (ok) {
std::get<ScoConnection>(pair).StartStream(std::move(startStream));
}
return ok;
}
}
return false;
}
uint16_t AclConnectionHandler::GetScoHandle(
bluetooth::hci::Address addr) const {
for (const auto& pair : sco_connections_) {
if (std::get<ScoConnection>(pair).GetAddress() == addr) {
return std::get<0>(pair);
}
}
return kReservedHandle;
}
ScoConnectionParameters AclConnectionHandler::GetScoConnectionParameters(
bluetooth::hci::Address addr) const {
for (const auto& pair : sco_connections_) {
if (std::get<ScoConnection>(pair).GetAddress() == addr) {
return std::get<ScoConnection>(pair).GetConnectionParameters();
}
}
return {};
}
ScoLinkParameters AclConnectionHandler::GetScoLinkParameters(
bluetooth::hci::Address addr) const {
for (const auto& pair : sco_connections_) {
if (std::get<ScoConnection>(pair).GetAddress() == addr) {
return std::get<ScoConnection>(pair).GetLinkParameters();
}
}
return {};
}
std::vector<uint16_t> AclConnectionHandler::GetAclHandles() const {
std::vector<uint16_t> keys;
for (const auto& pair : acl_connections_) {
keys.push_back(pair.first);
}
return keys;
}
void AclConnectionHandler::ResetLinkTimer(uint16_t handle) {
acl_connections_.at(handle).ResetLinkTimer();
}
std::chrono::steady_clock::duration
AclConnectionHandler::TimeUntilLinkNearExpiring(uint16_t handle) const {
return acl_connections_.at(handle).TimeUntilNearExpiring();
}
bool AclConnectionHandler::IsLinkNearExpiring(uint16_t handle) const {
return acl_connections_.at(handle).IsNearExpiring();
}
std::chrono::steady_clock::duration AclConnectionHandler::TimeUntilLinkExpired(
uint16_t handle) const {
return acl_connections_.at(handle).TimeUntilExpired();
}
bool AclConnectionHandler::HasLinkExpired(uint16_t handle) const {
return acl_connections_.at(handle).HasExpired();
}
bool AclConnectionHandler::IsRoleSwitchAllowedForPendingConnection() const {
return pending_classic_connection_allow_role_switch_;
}
} // namespace rootcanal