blob: 6ca6d9efb86297857fd2824f3c3181c11ea3b02a [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 "os/log.h"
namespace test_vendor_lib {
using ::bluetooth::hci::Address;
using ::bluetooth::hci::AddressType;
using ::bluetooth::hci::AddressWithType;
bool AclConnectionHandler::HasHandle(uint16_t handle) const {
return acl_connections_.count(handle) != 0;
}
uint16_t AclConnectionHandler::GetUnusedHandle() {
while (HasHandle(last_handle_) ||
isochronous_connection_handler_.HasHandle(last_handle_)) {
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) {
if (classic_connection_pending_) {
return false;
}
classic_connection_pending_ = true;
pending_connection_address_ = addr;
authenticate_pending_classic_connection_ = authenticate_on_connect;
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;
return true;
}
bool AclConnectionHandler::CreatePendingLeConnection(AddressWithType addr) {
bool device_connected = false;
for (auto pair : acl_connections_) {
auto connection = std::get<AclConnection>(pair);
if (connection.GetAddress() == addr) {
device_connected = true;
}
}
if (device_connected) {
LOG_INFO("%s: %s is already connected", __func__, addr.ToString().c_str());
return false;
}
if (le_connection_pending_) {
LOG_INFO("%s: connection already pending", __func__);
return false;
}
le_connection_pending_ = true;
pending_le_connection_address_ = addr;
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};
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},
Phy::Type::BR_EDR});
return handle;
}
return kReservedHandle;
}
uint16_t AclConnectionHandler::CreateLeConnection(AddressWithType addr,
AddressWithType own_addr) {
if (CancelPendingLeConnection(addr)) {
uint16_t handle = GetUnusedHandle();
acl_connections_.emplace(
handle, AclConnection{addr, own_addr, Phy::Type::LOW_ENERGY});
return handle;
}
return kReservedHandle;
}
bool AclConnectionHandler::Disconnect(uint16_t handle) {
return acl_connections_.erase(handle) > 0;
}
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;
}
AddressWithType AclConnectionHandler::GetAddress(uint16_t handle) const {
ASSERT_LOG(HasHandle(handle), "Handle unknown %hd", handle);
return acl_connections_.at(handle).GetAddress();
}
AddressWithType AclConnectionHandler::GetOwnAddress(uint16_t handle) const {
ASSERT_LOG(HasHandle(handle), "Handle unknown %hd", handle);
return acl_connections_.at(handle).GetOwnAddress();
}
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::SetAddress(uint16_t handle,
AddressWithType address) {
if (!HasHandle(handle)) {
return;
}
auto connection = acl_connections_.at(handle);
connection.SetAddress(address);
}
Phy::Type AclConnectionHandler::GetPhyType(uint16_t handle) const {
if (!HasHandle(handle)) {
return Phy::Type::BR_EDR;
}
return acl_connections_.at(handle).GetPhyType();
}
std::unique_ptr<bluetooth::hci::LeSetCigParametersCompleteBuilder>
AclConnectionHandler::SetCigParameters(
uint8_t id, uint32_t sdu_interval_m_to_s, uint32_t sdu_interval_s_to_m,
bluetooth::hci::ClockAccuracy /* accuracy */,
bluetooth::hci::Packing packing, bluetooth::hci::Enable framed,
uint16_t max_transport_latency_m_to_s_,
uint16_t max_transport_latency_s_to_m_,
std::vector<bluetooth::hci::CisParametersConfig>& streams) {
std::vector<uint16_t> handles;
GroupParameters group_parameters{
.id = id,
.sdu_interval_m_to_s = sdu_interval_m_to_s,
.sdu_interval_s_to_m = sdu_interval_s_to_m,
.interleaved = packing == bluetooth::hci::Packing::INTERLEAVED,
.framed = framed == bluetooth::hci::Enable::ENABLED,
.max_transport_latency_m_to_s = max_transport_latency_m_to_s_,
.max_transport_latency_s_to_m = max_transport_latency_s_to_m_};
std::vector<StreamParameters> stream_parameters;
for (size_t i = 0; i < streams.size(); i++) {
auto handle = GetUnusedHandle();
StreamParameters a{.group_id = group_parameters.id,
.stream_id = streams[i].cis_id_,
.max_sdu_m_to_s = streams[i].max_sdu_m_to_s_,
.max_sdu_s_to_m = streams[i].max_sdu_s_to_m_,
.rtn_m_to_s = streams[i].rtn_m_to_s_,
.rtn_s_to_m = streams[i].rtn_s_to_m_,
.handle = handle};
handles.push_back(handle);
stream_parameters.push_back(std::move(a));
}
return isochronous_connection_handler_.SetCigParameters(
group_parameters, stream_parameters, std::move(handles));
}
void AclConnectionHandler::CreatePendingCis(
bluetooth::hci::CreateCisConfig config) {
CisHandles handles;
handles.cis_handle_ = config.cis_connection_handle_;
handles.acl_handle_ = config.acl_connection_handle_;
handles.remote_cis_handle_ = kReservedHandle;
pending_streams_.emplace_back(std::move(handles));
}
bool AclConnectionHandler::ConnectCis(uint16_t handle) {
size_t position;
CisHandles connection;
for (position = 0; position < pending_streams_.size(); position++) {
if (handle == pending_streams_[position].cis_handle_) {
LOG_INFO("Found handle 0x%04hx", handle);
connection = pending_streams_[position];
pending_streams_.erase(pending_streams_.begin() + position);
connected_streams_.push_back(connection);
ASSERT(connection.cis_handle_ != kReservedHandle);
ASSERT(connection.acl_handle_ != kReservedHandle);
ASSERT(connection.remote_cis_handle_ != kReservedHandle);
return true;
}
}
LOG_INFO("No pending CIS connection with handle 0x%04hx", handle);
return false;
}
void AclConnectionHandler::SetRemoteCisHandle(uint16_t handle,
uint16_t remote_handle) {
for (size_t position = 0; position < pending_streams_.size(); position++) {
if (handle == pending_streams_[position].cis_handle_) {
LOG_INFO("Added remote handle 0x%04hx to handle 0x%04hx", remote_handle,
pending_streams_[position].cis_handle_);
pending_streams_[position].remote_cis_handle_ = remote_handle;
return;
}
}
LOG_INFO("Couldn't find CIS connection with handle 0x%04hx", handle);
}
bool AclConnectionHandler::RejectCis(uint16_t handle) {
size_t position;
for (position = 0; position < pending_streams_.size(); position++) {
if (handle == pending_streams_[position].cis_handle_) {
pending_streams_.erase(pending_streams_.begin() + position);
break;
}
}
if (position == pending_streams_.size()) {
LOG_INFO("No pending connection with handle 0x%hx", handle);
return false;
}
return true;
}
uint16_t AclConnectionHandler::GetPendingAclHandle(uint16_t cis_handle) const {
size_t position;
uint16_t handle = 0xffff;
for (position = 0; position < pending_streams_.size(); position++) {
if (cis_handle == pending_streams_[position].cis_handle_) {
handle = pending_streams_[position].acl_handle_;
break;
}
}
if (position == pending_streams_.size()) {
LOG_INFO("No pending connection with handle 0x%hx", cis_handle);
}
return handle;
}
bool AclConnectionHandler::DisconnectCis(uint16_t cis_handle) {
size_t position;
for (position = 0; position < connected_streams_.size(); position++) {
if (cis_handle == connected_streams_[position].cis_handle_) {
connected_streams_.erase(connected_streams_.begin() + position);
break;
}
}
if (position == connected_streams_.size()) {
LOG_INFO("No connected stream 0x%hx", cis_handle);
return false;
}
return true;
}
bluetooth::hci::ErrorCode AclConnectionHandler::RemoveCig(uint8_t cig_id) {
for (const auto& stream : connected_streams_) {
if (isochronous_connection_handler_.GetGroupId(stream.cis_handle_) ==
cig_id) {
return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
}
}
for (const auto& stream : pending_streams_) {
if (isochronous_connection_handler_.GetGroupId(stream.cis_handle_) ==
cig_id) {
return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
}
}
auto status = isochronous_connection_handler_.RemoveCig(cig_id);
if (status == bluetooth::hci::ErrorCode::SUCCESS) {
// Clean up?
}
return status;
}
bool AclConnectionHandler::HasPendingCisConnection(uint16_t handle) const {
for (const auto& config : pending_streams_) {
if (config.cis_handle_ == handle) {
return true;
}
}
return false;
}
bool AclConnectionHandler::HasPendingCis() const {
return !pending_streams_.empty();
}
bool AclConnectionHandler::HasConnectedCis(uint16_t handle) const {
for (const auto& cs : connected_streams_) {
if (handle == cs.cis_handle_) {
return true;
}
}
return false;
}
bool AclConnectionHandler::HasCisHandle(uint16_t handle) const {
for (const auto& cs : pending_streams_) {
if (handle == cs.cis_handle_) {
return true;
}
}
for (const auto& cs : connected_streams_) {
if (handle == cs.cis_handle_) {
return true;
}
}
return isochronous_connection_handler_.HasHandle(handle);
}
uint16_t AclConnectionHandler::GetAclHandleForCisHandle(
uint16_t cis_handle) const {
for (const auto& cs : connected_streams_) {
if (cis_handle == cs.cis_handle_) {
return cs.acl_handle_;
}
}
return kReservedHandle;
}
uint16_t AclConnectionHandler::GetRemoteCisHandleForCisHandle(
uint16_t cis_handle) const {
for (const auto& cs : connected_streams_) {
if (cis_handle == cs.cis_handle_) {
return cs.remote_cis_handle_;
}
}
return kReservedHandle;
}
GroupParameters AclConnectionHandler::GetGroupParameters(uint8_t id) const {
return isochronous_connection_handler_.GetGroupParameters(id);
}
StreamParameters AclConnectionHandler::GetStreamParameters(
uint16_t handle) const {
return isochronous_connection_handler_.GetStreamParameters(handle);
}
} // namespace test_vendor_lib