blob: ea0980060f96aeb4454ea0f0c2ea1605e2630726 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "adapter.h"
#include <endian.h>
#include "bredr_connection_manager.h"
#include "bredr_discovery_manager.h"
#include "low_energy_address_manager.h"
#include "low_energy_advertising_manager.h"
#include "low_energy_connection_manager.h"
#include "low_energy_discovery_manager.h"
#include "peer.h"
#include "src/connectivity/bluetooth/core/bt-host/common/log.h"
#include "src/connectivity/bluetooth/core/bt-host/common/random.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/connection.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/legacy_low_energy_advertiser.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/legacy_low_energy_scanner.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/low_energy_connector.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/sequential_command_runner.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/transport.h"
#include "src/connectivity/bluetooth/core/bt-host/hci/util.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/channel_manager.h"
namespace bt {
namespace gap {
Adapter::Adapter(fxl::RefPtr<hci::Transport> hci, fbl::RefPtr<gatt::GATT> gatt,
std::optional<fbl::RefPtr<data::Domain>> data_domain)
: inspector_(),
adapter_node_(inspector_.GetRoot().CreateChild("adapter")),
identifier_(Random<AdapterId>()),
dispatcher_(async_get_default_dispatcher()),
hci_(hci),
init_state_(State::kNotInitialized),
max_lmp_feature_page_index_(0),
peer_cache_(adapter_node_.CreateChild(PeerCache::kInspectNodeName)),
gatt_(gatt),
weak_ptr_factory_(this) {
ZX_DEBUG_ASSERT(hci_);
ZX_DEBUG_ASSERT(gatt_);
ZX_DEBUG_ASSERT_MSG(dispatcher_, "must create on a thread with a dispatcher");
init_seq_runner_ = std::make_unique<hci::SequentialCommandRunner>(dispatcher_, hci_);
if (data_domain.has_value()) {
data_domain_ = *data_domain;
}
auto self = weak_ptr_factory_.GetWeakPtr();
hci_->SetTransportClosedCallback(
[self] {
if (self)
self->OnTransportClosed();
},
dispatcher_);
}
Adapter::~Adapter() {
if (IsInitialized())
ShutDown();
}
bool Adapter::Initialize(InitializeCallback callback, fit::closure transport_closed_cb) {
ZX_DEBUG_ASSERT(thread_checker_.IsCreationThreadCurrent());
ZX_DEBUG_ASSERT(callback);
ZX_DEBUG_ASSERT(transport_closed_cb);
if (IsInitialized()) {
bt_log(WARN, "gap", "Adapter already initialized");
return false;
}
ZX_DEBUG_ASSERT(!IsInitializing());
init_state_ = State::kInitializing;
ZX_DEBUG_ASSERT(init_seq_runner_->IsReady());
ZX_DEBUG_ASSERT(!init_seq_runner_->HasQueuedCommands());
transport_closed_cb_ = std::move(transport_closed_cb);
// Start by resetting the controller to a clean state and then send
// informational parameter commands that are not specific to LE or BR/EDR. The
// commands sent here are mandatory for all LE controllers.
//
// NOTE: It's safe to pass capture |this| directly in the callbacks as
// |init_seq_runner_| will internally invalidate the callbacks if it ever gets
// deleted.
// HCI_Reset
init_seq_runner_->QueueCommand(hci::CommandPacket::New(hci::kReset));
// HCI_Read_Local_Version_Information
init_seq_runner_->QueueCommand(
hci::CommandPacket::New(hci::kReadLocalVersionInfo),
[this](const hci::EventPacket& cmd_complete) {
if (hci_is_error(cmd_complete, WARN, "gap", "read local version info failed")) {
return;
}
auto params = cmd_complete.return_params<hci::ReadLocalVersionInfoReturnParams>();
state_.hci_version_ = params->hci_version;
});
// HCI_Read_Local_Supported_Commands
init_seq_runner_->QueueCommand(
hci::CommandPacket::New(hci::kReadLocalSupportedCommands),
[this](const hci::EventPacket& cmd_complete) {
if (hci_is_error(cmd_complete, WARN, "gap", "read local supported commands failed")) {
return;
}
auto params = cmd_complete.return_params<hci::ReadLocalSupportedCommandsReturnParams>();
std::memcpy(state_.supported_commands_, params->supported_commands,
sizeof(params->supported_commands));
});
// HCI_Read_Local_Supported_Features
init_seq_runner_->QueueCommand(
hci::CommandPacket::New(hci::kReadLocalSupportedFeatures),
[this](const hci::EventPacket& cmd_complete) {
if (hci_is_error(cmd_complete, WARN, "gap", "read local supported features failed")) {
return;
}
auto params = cmd_complete.return_params<hci::ReadLocalSupportedFeaturesReturnParams>();
state_.features_.SetPage(0, le64toh(params->lmp_features));
});
// HCI_Read_BD_ADDR
init_seq_runner_->QueueCommand(
hci::CommandPacket::New(hci::kReadBDADDR), [this](const hci::EventPacket& cmd_complete) {
if (hci_is_error(cmd_complete, WARN, "gap", "read BR_ADDR failed")) {
return;
}
auto params = cmd_complete.return_params<hci::ReadBDADDRReturnParams>();
state_.controller_address_ = params->bd_addr;
});
init_seq_runner_->RunCommands([callback = std::move(callback), this](hci::Status status) mutable {
if (!status) {
bt_log(ERROR, "gap", "Failed to obtain initial controller information: %s",
status.ToString().c_str());
CleanUp();
callback(false);
return;
}
InitializeStep2(std::move(callback));
});
return true;
}
void Adapter::ShutDown() {
ZX_DEBUG_ASSERT(thread_checker_.IsCreationThreadCurrent());
bt_log(TRACE, "gap", "adapter shutting down");
if (IsInitializing()) {
ZX_DEBUG_ASSERT(!init_seq_runner_->IsReady());
init_seq_runner_->Cancel();
}
CleanUp();
}
bool Adapter::AddBondedPeer(BondingData bonding_data) {
return peer_cache()->AddBondedPeer(bonding_data);
}
void Adapter::SetPairingDelegate(fxl::WeakPtr<PairingDelegate> delegate) {
le_connection_manager()->SetPairingDelegate(delegate);
bredr_connection_manager()->SetPairingDelegate(delegate);
}
bool Adapter::IsDiscoverable() const {
return (le_advertising_manager_ && le_advertising_manager_->advertising()) ||
(bredr_discovery_manager_ && bredr_discovery_manager_->discoverable());
}
bool Adapter::IsDiscovering() const {
return (le_discovery_manager_ && le_discovery_manager_->discovering()) ||
(bredr_discovery_manager_ && bredr_discovery_manager_->discovering());
}
void Adapter::SetLocalName(std::string name, hci::StatusCallback callback) {
// TODO(40836): set the public LE advertisement name from |name|
// If BrEdr is not supported, skip the name update.
if (!bredr_discovery_manager()) {
callback(hci::Status(bt::HostError::kNotSupported));
return;
}
// Make a copy of |name| to move separately into the lambda.
std::string name_copy(name);
bredr_discovery_manager_->UpdateLocalName(
std::move(name),
[this, cb = std::move(callback), local_name = std::move(name_copy)](auto status) {
if (!bt_is_error(status, WARN, "gap", "set local name failed")) {
state_.local_name_ = local_name;
}
cb(status);
});
}
void Adapter::SetDeviceClass(DeviceClass dev_class, hci::StatusCallback callback) {
auto write_dev_class = hci::CommandPacket::New(hci::kWriteClassOfDevice,
sizeof(hci::WriteClassOfDeviceCommandParams));
write_dev_class->mutable_payload<hci::WriteClassOfDeviceCommandParams>()->class_of_device =
dev_class;
hci_->command_channel()->SendCommand(
std::move(write_dev_class), dispatcher_,
[cb = std::move(callback)](auto, const hci::EventPacket& event) {
hci_is_error(event, WARN, "gap", "set device class failed");
cb(event.ToStatus());
});
}
void Adapter::InitializeStep2(InitializeCallback callback) {
ZX_DEBUG_ASSERT(thread_checker_.IsCreationThreadCurrent());
ZX_DEBUG_ASSERT(IsInitializing());
// Low Energy MUST be supported. We don't support BR/EDR-only controllers.
if (!state_.IsLowEnergySupported()) {
bt_log(ERROR, "gap", "Bluetooth LE not supported by controller");
CleanUp();
callback(false);
return;
}
// Check the HCI version. We officially only support 4.2+ only but for now we
// just log a warning message if the version is legacy.
if (state_.hci_version() < hci::HCIVersion::k4_2) {
bt_log(WARN, "gap", "controller is using legacy HCI version %s",
hci::HCIVersionToString(state_.hci_version()).c_str());
}
ZX_DEBUG_ASSERT(init_seq_runner_->IsReady());
// If the controller supports the Read Buffer Size command then send it.
// Otherwise we'll default to 0 when initializing the ACLDataChannel.
if (state_.IsCommandSupported(14, hci::SupportedCommand::kReadBufferSize)) {
// HCI_Read_Buffer_Size
init_seq_runner_->QueueCommand(
hci::CommandPacket::New(hci::kReadBufferSize),
[this](const hci::EventPacket& cmd_complete) {
if (hci_is_error(cmd_complete, WARN, "gap", "read buffer size failed")) {
return;
}
auto params = cmd_complete.return_params<hci::ReadBufferSizeReturnParams>();
uint16_t mtu = le16toh(params->hc_acl_data_packet_length);
uint16_t max_count = le16toh(params->hc_total_num_acl_data_packets);
if (mtu && max_count) {
state_.bredr_data_buffer_info_ = hci::DataBufferInfo(mtu, max_count);
}
});
}
// HCI_LE_Read_Local_Supported_Features
init_seq_runner_->QueueCommand(
hci::CommandPacket::New(hci::kLEReadLocalSupportedFeatures),
[this](const hci::EventPacket& cmd_complete) {
if (hci_is_error(cmd_complete, WARN, "gap", "LE read local supported features failed")) {
return;
}
auto params = cmd_complete.return_params<hci::LEReadLocalSupportedFeaturesReturnParams>();
state_.le_state_.supported_features_ = le64toh(params->le_features);
});
// HCI_LE_Read_Supported_States
init_seq_runner_->QueueCommand(
hci::CommandPacket::New(hci::kLEReadSupportedStates),
[this](const hci::EventPacket& cmd_complete) {
if (hci_is_error(cmd_complete, WARN, "gap", "LE read local supported states failed")) {
return;
}
auto params = cmd_complete.return_params<hci::LEReadSupportedStatesReturnParams>();
state_.le_state_.supported_states_ = le64toh(params->le_states);
});
// HCI_LE_Read_Buffer_Size
init_seq_runner_->QueueCommand(
hci::CommandPacket::New(hci::kLEReadBufferSize),
[this](const hci::EventPacket& cmd_complete) {
if (hci_is_error(cmd_complete, WARN, "gap", "LE read buffer size failed")) {
return;
}
auto params = cmd_complete.return_params<hci::LEReadBufferSizeReturnParams>();
uint16_t mtu = le16toh(params->hc_le_acl_data_packet_length);
uint8_t max_count = params->hc_total_num_le_acl_data_packets;
if (mtu && max_count) {
state_.le_state_.data_buffer_info_ = hci::DataBufferInfo(mtu, max_count);
}
});
if (state_.features().HasBit(0u, hci::LMPFeature::kSecureSimplePairing)) {
// HCI_Write_Simple_Pairing_Mode
auto write_ssp = hci::CommandPacket::New(hci::kWriteSimplePairingMode,
sizeof(hci::WriteSimplePairingModeCommandParams));
write_ssp->mutable_payload<hci::WriteSimplePairingModeCommandParams>()->simple_pairing_mode =
hci::GenericEnableParam::kEnable;
init_seq_runner_->QueueCommand(std::move(write_ssp), [](const auto& event) {
// Warn if the command failed
hci_is_error(event, WARN, "gap", "write simple pairing mode failed");
});
}
// If there are extended features then try to read the first page of the
// extended features.
if (state_.features().HasBit(0u, hci::LMPFeature::kExtendedFeatures)) {
// Page index 1 must be available.
max_lmp_feature_page_index_ = 1;
// HCI_Read_Local_Extended_Features
auto cmd_packet = hci::CommandPacket::New(hci::kReadLocalExtendedFeatures,
sizeof(hci::ReadLocalExtendedFeaturesCommandParams));
// Try to read page 1.
cmd_packet->mutable_payload<hci::ReadLocalExtendedFeaturesCommandParams>()->page_number = 1;
init_seq_runner_->QueueCommand(
std::move(cmd_packet), [this](const hci::EventPacket& cmd_complete) {
if (hci_is_error(cmd_complete, WARN, "gap", "read local extended features failed")) {
return;
}
auto params = cmd_complete.return_params<hci::ReadLocalExtendedFeaturesReturnParams>();
state_.features_.SetPage(1, le64toh(params->extended_lmp_features));
max_lmp_feature_page_index_ = params->maximum_page_number;
});
}
init_seq_runner_->RunCommands([callback = std::move(callback), this](hci::Status status) mutable {
if (bt_is_error(status, ERROR, "gap",
"failed to obtain initial controller information (step 2)")) {
CleanUp();
callback(false);
return;
}
InitializeStep3(std::move(callback));
});
}
void Adapter::InitializeStep3(InitializeCallback callback) {
ZX_DEBUG_ASSERT(thread_checker_.IsCreationThreadCurrent());
ZX_DEBUG_ASSERT(IsInitializing());
if (!state_.bredr_data_buffer_info().IsAvailable() &&
!state_.low_energy_state().data_buffer_info().IsAvailable()) {
bt_log(ERROR, "gap", "Both BR/EDR and LE buffers are unavailable");
CleanUp();
callback(false);
return;
}
// Now that we have all the ACL data buffer information it's time to
// initialize the ACLDataChannel.
if (!hci_->InitializeACLDataChannel(state_.bredr_data_buffer_info(),
state_.low_energy_state().data_buffer_info())) {
bt_log(ERROR, "gap", "Failed to initialize ACLDataChannel (step 3)");
CleanUp();
callback(false);
return;
}
// Create the data domain, if we haven't been provided one. Doing so here lets us guarantee that
// AclDataChannel's lifetime is a superset of Data Domain's lifetime.
// TODO(35228) We currently allow tests to inject their own domain in the adapter constructor,
// as the adapter_unittests rely on injecting a fake domain to avoid concurrency in the unit
// tests. Once we move to a single threaded model, we would like to remove this and have the
// adapter always be responsible for creating the domain.
if (!data_domain_) {
// Initialize the data Domain to make L2CAP available for the next initialization step. The
// ACLDataChannel must be initialized before creating the data domain
auto data_domain =
data::Domain::Create(hci_, adapter_node_.CreateChild(data::Domain::kInspectNodeName));
if (!data_domain) {
bt_log(ERROR, "gap", "Failed to initialize Data Domain");
CleanUp();
callback(false);
return;
}
data_domain_ = data_domain;
}
ZX_DEBUG_ASSERT(init_seq_runner_->IsReady());
ZX_DEBUG_ASSERT(!init_seq_runner_->HasQueuedCommands());
// HCI_Set_Event_Mask
{
uint64_t event_mask = BuildEventMask();
auto cmd_packet =
hci::CommandPacket::New(hci::kSetEventMask, sizeof(hci::SetEventMaskCommandParams));
cmd_packet->mutable_payload<hci::SetEventMaskCommandParams>()->event_mask = htole64(event_mask);
init_seq_runner_->QueueCommand(std::move(cmd_packet), [](const auto& event) {
hci_is_error(event, WARN, "gap", "set event mask failed");
});
}
// HCI_LE_Set_Event_Mask
{
uint64_t event_mask = BuildLEEventMask();
auto cmd_packet =
hci::CommandPacket::New(hci::kLESetEventMask, sizeof(hci::LESetEventMaskCommandParams));
cmd_packet->mutable_payload<hci::LESetEventMaskCommandParams>()->le_event_mask =
htole64(event_mask);
init_seq_runner_->QueueCommand(std::move(cmd_packet), [](const auto& event) {
hci_is_error(event, WARN, "gap", "LE set event mask failed");
});
}
// HCI_Write_LE_Host_Support if the appropriate feature bit is not set AND if
// the controller supports this command.
if (!state_.features().HasBit(1, hci::LMPFeature::kLESupportedHost) &&
state_.IsCommandSupported(24, hci::SupportedCommand::kWriteLEHostSupport)) {
auto cmd_packet = hci::CommandPacket::New(hci::kWriteLEHostSupport,
sizeof(hci::WriteLEHostSupportCommandParams));
auto params = cmd_packet->mutable_payload<hci::WriteLEHostSupportCommandParams>();
params->le_supported_host = hci::GenericEnableParam::kEnable;
params->simultaneous_le_host = 0x00; // note: ignored
init_seq_runner_->QueueCommand(std::move(cmd_packet), [](const auto& event) {
hci_is_error(event, WARN, "gap", "write LE host support failed");
});
}
// If we know that Page 2 of the extended features bitfield is available, then
// request it.
if (max_lmp_feature_page_index_ > 1) {
auto cmd_packet = hci::CommandPacket::New(hci::kReadLocalExtendedFeatures,
sizeof(hci::ReadLocalExtendedFeaturesCommandParams));
// Try to read page 2.
cmd_packet->mutable_payload<hci::ReadLocalExtendedFeaturesCommandParams>()->page_number = 2;
// HCI_Read_Local_Extended_Features
init_seq_runner_->QueueCommand(
std::move(cmd_packet), [this](const hci::EventPacket& cmd_complete) {
if (hci_is_error(cmd_complete, WARN, "gap", "read local extended features failed")) {
return;
}
auto params = cmd_complete.return_params<hci::ReadLocalExtendedFeaturesReturnParams>();
state_.features_.SetPage(2, le64toh(params->extended_lmp_features));
max_lmp_feature_page_index_ = params->maximum_page_number;
});
}
init_seq_runner_->RunCommands([callback = std::move(callback), this](hci::Status status) mutable {
if (bt_is_error(status, ERROR, "gap",
"failed to obtain initial controller information (step 3)")) {
CleanUp();
callback(false);
return;
}
InitializeStep4(std::move(callback));
});
}
void Adapter::InitializeStep4(InitializeCallback callback) {
ZX_DEBUG_ASSERT(IsInitializing());
// Initialize the scan manager based on current feature support.
if (state_.low_energy_state().IsFeatureSupported(
hci::LESupportedFeature::kLEExtendedAdvertising)) {
bt_log(INFO, "gap", "controller supports extended advertising");
// TODO(armansito): Initialize |hci_le_*| objects here with extended-mode
// versions.
bt_log(WARN, "gap", "5.0 not yet supported; using legacy mode");
}
// We use the public controller address as the local LE identity address.
DeviceAddress adapter_identity(DeviceAddress::Type::kLEPublic, state_.controller_address());
// Initialize the LE local address manager.
le_address_manager_ = std::make_unique<LowEnergyAddressManager>(
adapter_identity, fit::bind_member(this, &Adapter::IsLeRandomAddressChangeAllowed), hci_);
// Initialize the HCI adapters.
hci_le_advertiser_ = std::make_unique<hci::LegacyLowEnergyAdvertiser>(hci_);
hci_le_connector_ = std::make_unique<hci::LowEnergyConnector>(
hci_, le_address_manager_.get(), dispatcher_,
fit::bind_member(hci_le_advertiser_.get(), &hci::LowEnergyAdvertiser::OnIncomingConnection));
hci_le_scanner_ =
std::make_unique<hci::LegacyLowEnergyScanner>(le_address_manager_.get(), hci_, dispatcher_);
// Initialize the LE manager objects
le_discovery_manager_ =
std::make_unique<LowEnergyDiscoveryManager>(hci_, hci_le_scanner_.get(), &peer_cache_);
le_discovery_manager_->set_peer_connectable_callback(
fit::bind_member(this, &Adapter::OnLeAutoConnectRequest));
le_connection_manager_ = std::make_unique<LowEnergyConnectionManager>(
hci_, le_address_manager_.get(), hci_le_connector_.get(), &peer_cache_, data_domain_, gatt_);
le_advertising_manager_ = std::make_unique<LowEnergyAdvertisingManager>(
hci_le_advertiser_.get(), le_address_manager_.get());
// Initialize the BR/EDR manager objects if the controller supports BR/EDR.
if (state_.IsBREDRSupported()) {
DeviceAddress local_bredr_address(DeviceAddress::Type::kBREDR, state_.controller_address());
bredr_connection_manager_ = std::make_unique<BrEdrConnectionManager>(
hci_, &peer_cache_, local_bredr_address, data_domain_,
state_.features().HasBit(0, hci::LMPFeature::kInterlacedPageScan));
hci::InquiryMode mode = hci::InquiryMode::kStandard;
if (state_.features().HasBit(0, hci::LMPFeature::kExtendedInquiryResponse)) {
mode = hci::InquiryMode::kExtended;
} else if (state_.features().HasBit(0, hci::LMPFeature::kRSSIwithInquiryResults)) {
mode = hci::InquiryMode::kRSSI;
}
bredr_discovery_manager_ = std::make_unique<BrEdrDiscoveryManager>(hci_, mode, &peer_cache_);
sdp_server_ = std::make_unique<sdp::Server>(data_domain_);
}
// Update properties before callback called so properties can be verified in unit tests.
UpdateInspectProperties();
// Assign a default name and device class before notifying completion.
auto self = weak_ptr_factory_.GetWeakPtr();
SetLocalName(kDefaultLocalName, [self, callback = std::move(callback)](auto status) mutable {
// Set the default device class - a computer with audio.
// TODO(BT-641): set this from a platform configuration file
DeviceClass dev_class(DeviceClass::MajorClass::kComputer);
dev_class.SetServiceClasses({DeviceClass::ServiceClass::kAudio});
self->SetDeviceClass(dev_class, [self, callback = std::move(callback)](const auto&) {
// This completes the initialization sequence.
self->init_state_ = State::kInitialized;
callback(true);
});
});
}
void Adapter::UpdateInspectProperties() {
inspect_properties_.adapter_id = adapter_node_.CreateString("adapter_id", identifier_.ToString());
inspect_properties_.hci_version =
adapter_node_.CreateString("hci_version", hci::HCIVersionToString(state_.hci_version()));
inspect_properties_.bredr_max_num_packets = adapter_node_.CreateUint(
"bredr_max_num_packets", state_.bredr_data_buffer_info().max_num_packets());
inspect_properties_.bredr_max_data_length = adapter_node_.CreateUint(
"bredr_max_data_length", state_.bredr_data_buffer_info().max_data_length());
inspect_properties_.le_max_num_packets = adapter_node_.CreateUint(
"le_max_num_packets", state_.low_energy_state().data_buffer_info().max_num_packets());
inspect_properties_.le_max_data_length = adapter_node_.CreateUint(
"le_max_data_length", state_.low_energy_state().data_buffer_info().max_data_length());
inspect_properties_.lmp_features =
adapter_node_.CreateString("lmp_features", state_.features().ToString());
auto le_features = fxl::StringPrintf("0x%016lx", state_.low_energy_state().supported_features());
inspect_properties_.le_features = adapter_node_.CreateString("le_features", le_features);
}
uint64_t Adapter::BuildEventMask() {
uint64_t event_mask = 0;
#define ENABLE_EVT(event) event_mask |= static_cast<uint64_t>(hci::EventMask::event)
// Enable events that are needed for basic functionality. (alphabetic)
ENABLE_EVT(kAuthenticationCompleteEvent);
ENABLE_EVT(kConnectionCompleteEvent);
ENABLE_EVT(kConnectionRequestEvent);
ENABLE_EVT(kDataBufferOverflowEvent);
ENABLE_EVT(kDisconnectionCompleteEvent);
ENABLE_EVT(kEncryptionChangeEvent);
ENABLE_EVT(kEncryptionKeyRefreshCompleteEvent);
ENABLE_EVT(kExtendedInquiryResultEvent);
ENABLE_EVT(kHardwareErrorEvent);
ENABLE_EVT(kInquiryCompleteEvent);
ENABLE_EVT(kInquiryResultEvent);
ENABLE_EVT(kInquiryResultWithRSSIEvent);
ENABLE_EVT(kIOCapabilityRequestEvent);
ENABLE_EVT(kIOCapabilityResponseEvent);
ENABLE_EVT(kLEMetaEvent);
ENABLE_EVT(kLinkKeyRequestEvent);
ENABLE_EVT(kLinkKeyNotificationEvent);
ENABLE_EVT(kRemoteOOBDataRequestEvent);
ENABLE_EVT(kRemoteNameRequestCompleteEvent);
ENABLE_EVT(kReadRemoteSupportedFeaturesCompleteEvent);
ENABLE_EVT(kReadRemoteVersionInformationCompleteEvent);
ENABLE_EVT(kReadRemoteExtendedFeaturesCompleteEvent);
ENABLE_EVT(kSimplePairingCompleteEvent);
ENABLE_EVT(kUserConfirmationRequestEvent);
ENABLE_EVT(kUserPasskeyRequestEvent);
ENABLE_EVT(kUserPasskeyNotificationEvent);
#undef ENABLE_EVT
return event_mask;
}
uint64_t Adapter::BuildLEEventMask() {
uint64_t event_mask = 0;
#define ENABLE_EVT(event) event_mask |= static_cast<uint64_t>(hci::LEEventMask::event)
ENABLE_EVT(kLEAdvertisingReport);
ENABLE_EVT(kLEConnectionComplete);
ENABLE_EVT(kLEConnectionUpdateComplete);
ENABLE_EVT(kLELongTermKeyRequest);
ENABLE_EVT(kLEReadRemoteFeaturesComplete);
#undef ENABLE_EVT
return event_mask;
}
void Adapter::CleanUp() {
ZX_DEBUG_ASSERT(thread_checker_.IsCreationThreadCurrent());
if (init_state_ == State::kNotInitialized) {
bt_log(TRACE, "gap", "clean up: not initialized");
return;
}
init_state_ = State::kNotInitialized;
state_ = AdapterState();
transport_closed_cb_ = nullptr;
// Destroy objects in reverse order of construction.
sdp_server_ = nullptr;
bredr_discovery_manager_ = nullptr;
le_advertising_manager_ = nullptr;
le_connection_manager_ = nullptr;
le_discovery_manager_ = nullptr;
hci_le_connector_ = nullptr;
hci_le_advertiser_ = nullptr;
hci_le_scanner_ = nullptr;
le_address_manager_ = nullptr;
data_domain_ = nullptr;
// TODO(armansito): hci::Transport::ShutDown() should send a shutdown message
// to the bt-hci device, which would be responsible for sending HCI_Reset upon
// exit.
if (hci_->IsInitialized())
hci_->ShutDown();
}
void Adapter::OnTransportClosed() {
bt_log(INFO, "gap", "HCI transport was closed");
if (transport_closed_cb_)
transport_closed_cb_();
}
void Adapter::OnLeAutoConnectRequest(PeerId peer_id) {
ZX_DEBUG_ASSERT(le_connection_manager_);
auto peer = peer_cache()->FindById(peer_id);
if (peer && peer->le() && !peer->le()->should_auto_connect()) {
bt_log(TRACE, "gap", "ignoring auto-connection (peer->should_autoconnect() is false)");
return;
}
auto self = weak_ptr_factory_.GetWeakPtr();
le_connection_manager_->Connect(peer_id, [self](auto status, auto conn) {
if (!self) {
bt_log(INFO, "gap", "ignoring auto-connection (adapter destroyed)");
return;
}
if (bt_is_error(status, INFO, "gap", "failed to auto-connect")) {
return;
}
ZX_DEBUG_ASSERT(conn);
PeerId id = conn->peer_identifier();
bt_log(INFO, "gap", "peer auto-connected (id: %s)", bt_str(id));
if (self->auto_conn_cb_) {
self->auto_conn_cb_(std::move(conn));
}
});
}
bool Adapter::IsLeRandomAddressChangeAllowed() {
return hci_le_advertiser_->AllowsRandomAddressChange() &&
hci_le_scanner_->AllowsRandomAddressChange() &&
hci_le_connector_->AllowsRandomAddressChange();
}
} // namespace gap
} // namespace bt