/* * Copyright 2020 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. */ #pragma once #include #include #include #include #include #include #include #include "common/bind.h" #include "common/init_flags.h" #include "hci/acl_manager/assembler.h" #include "hci/acl_manager/le_acceptlist_callbacks.h" #include "hci/acl_manager/le_acl_connection.h" #include "hci/acl_manager/le_connection_callbacks.h" #include "hci/acl_manager/le_connection_management_callbacks.h" #include "hci/acl_manager/round_robin_scheduler.h" #include "hci/controller.h" #include "hci/hci_layer.h" #include "hci/hci_packets.h" #include "hci/le_address_manager.h" #include "macros.h" #include "os/alarm.h" #include "os/handler.h" #include "os/system_properties.h" namespace bluetooth { namespace hci { namespace acl_manager { using common::BindOnce; constexpr uint16_t kConnIntervalMin = 0x0018; constexpr uint16_t kConnIntervalMax = 0x0028; constexpr uint16_t kConnLatency = 0x0000; constexpr uint16_t kSupervisionTimeout = 0x01f4; constexpr uint16_t kScanIntervalFast = 0x0060; /* 30 ~ 60 ms (use 60) = 96 *0.625 */ constexpr uint16_t kScanWindowFast = 0x0030; /* 30 ms = 48 *0.625 */ constexpr uint16_t kScanWindow2mFast = 0x0018; /* 15 ms = 24 *0.625 */ constexpr uint16_t kScanWindowCodedFast = 0x0018; /* 15 ms = 24 *0.625 */ constexpr uint16_t kScanIntervalSlow = 0x0800; /* 1.28 s = 2048 *0.625 */ constexpr uint16_t kScanWindowSlow = 0x0030; /* 30 ms = 48 *0.625 */ constexpr uint16_t kScanIntervalSystemSuspend = 0x0400; /* 640 ms = 1024 * 0.625 */ constexpr uint16_t kScanWindowSystemSuspend = 0x0012; /* 11.25ms = 18 * 0.625 */ constexpr uint32_t kCreateConnectionTimeoutMs = 30 * 1000; constexpr uint8_t PHY_LE_NO_PACKET = 0x00; constexpr uint8_t PHY_LE_1M = 0x01; constexpr uint8_t PHY_LE_2M = 0x02; constexpr uint8_t PHY_LE_CODED = 0x04; constexpr bool kEnableBlePrivacy = true; constexpr bool kEnableBleOnlyInit1mPhy = false; static const std::string kPropertyMinConnInterval = "bluetooth.core.le.min_connection_interval"; static const std::string kPropertyMaxConnInterval = "bluetooth.core.le.max_connection_interval"; static const std::string kPropertyConnLatency = "bluetooth.core.le.connection_latency"; static const std::string kPropertyConnSupervisionTimeout = "bluetooth.core.le.connection_supervision_timeout"; static const std::string kPropertyDirectConnTimeout = "bluetooth.core.le.direct_connection_timeout"; static const std::string kPropertyConnScanIntervalFast = "bluetooth.core.le.connection_scan_interval_fast"; static const std::string kPropertyConnScanWindowFast = "bluetooth.core.le.connection_scan_window_fast"; static const std::string kPropertyConnScanWindow2mFast = "bluetooth.core.le.connection_scan_window_2m_fast"; static const std::string kPropertyConnScanWindowCodedFast = "bluetooth.core.le.connection_scan_window_coded_fast"; static const std::string kPropertyConnScanIntervalSlow = "bluetooth.core.le.connection_scan_interval_slow"; static const std::string kPropertyConnScanWindowSlow = "bluetooth.core.le.connection_scan_window_slow"; static const std::string kPropertyConnScanIntervalSystemSuspend = "bluetooth.core.le.connection_scan_interval_system_suspend"; static const std::string kPropertyConnScanWindowSystemSuspend = "bluetooth.core.le.connection_scan_window_system_suspend"; static const std::string kPropertyEnableBlePrivacy = "bluetooth.core.gap.le.privacy.enabled"; static const std::string kPropertyEnableBleOnlyInit1mPhy = "bluetooth.core.gap.le.conn.only_init_1m_phy.enabled"; enum class ConnectabilityState { DISARMED = 0, ARMING = 1, ARMED = 2, DISARMING = 3, }; inline std::string connectability_state_machine_text(const ConnectabilityState& state) { switch (state) { CASE_RETURN_TEXT(ConnectabilityState::DISARMED); CASE_RETURN_TEXT(ConnectabilityState::ARMING); CASE_RETURN_TEXT(ConnectabilityState::ARMED); CASE_RETURN_TEXT(ConnectabilityState::DISARMING); } } struct le_acl_connection { le_acl_connection( AddressWithType remote_address, std::unique_ptr pending_connection, AclConnection::QueueDownEnd* queue_down_end, os::Handler* handler) : remote_address_(remote_address), pending_connection_(std::move(pending_connection)), assembler_(new acl_manager::assembler(remote_address, queue_down_end, handler)) {} ~le_acl_connection() { delete assembler_; } AddressWithType remote_address_; std::unique_ptr pending_connection_; acl_manager::assembler* assembler_; LeConnectionManagementCallbacks* le_connection_management_callbacks_ = nullptr; }; struct le_impl : public bluetooth::hci::LeAddressManagerCallback { le_impl( HciLayer* hci_layer, Controller* controller, os::Handler* handler, RoundRobinScheduler* round_robin_scheduler, bool crash_on_unknown_handle) : hci_layer_(hci_layer), controller_(controller), round_robin_scheduler_(round_robin_scheduler) { hci_layer_ = hci_layer; controller_ = controller; handler_ = handler; connections.crash_on_unknown_handle_ = crash_on_unknown_handle; le_acl_connection_interface_ = hci_layer_->GetLeAclConnectionInterface( handler_->BindOn(this, &le_impl::on_le_event), handler_->BindOn(this, &le_impl::on_le_disconnect), handler_->BindOn(this, &le_impl::on_le_read_remote_version_information)); le_address_manager_ = new LeAddressManager( common::Bind(&le_impl::enqueue_command, common::Unretained(this)), handler_, controller->GetMacAddress(), controller->GetLeFilterAcceptListSize(), controller->GetLeResolvingListSize()); } ~le_impl() { if (address_manager_registered) { le_address_manager_->UnregisterSync(this); } delete le_address_manager_; hci_layer_->PutLeAclConnectionInterface(); connections.reset(); } void on_le_event(LeMetaEventView event_packet) { SubeventCode code = event_packet.GetSubeventCode(); switch (code) { case SubeventCode::CONNECTION_COMPLETE: case SubeventCode::ENHANCED_CONNECTION_COMPLETE: on_le_connection_complete(event_packet); break; case SubeventCode::CONNECTION_UPDATE_COMPLETE: on_le_connection_update_complete(event_packet); break; case SubeventCode::PHY_UPDATE_COMPLETE: on_le_phy_update_complete(event_packet); break; case SubeventCode::DATA_LENGTH_CHANGE: on_data_length_change(event_packet); break; case SubeventCode::REMOTE_CONNECTION_PARAMETER_REQUEST: on_remote_connection_parameter_request(event_packet); break; case SubeventCode::LE_SUBRATE_CHANGE: on_le_subrate_change(event_packet); break; default: log::fatal("Unhandled event code {}", SubeventCodeText(code)); } } private: static constexpr uint16_t kIllegalConnectionHandle = 0xffff; struct { private: std::map le_acl_connections_; mutable std::mutex le_acl_connections_guard_; LeConnectionManagementCallbacks* find_callbacks(uint16_t handle) { auto connection = le_acl_connections_.find(handle); if (connection == le_acl_connections_.end()) return nullptr; return connection->second.le_connection_management_callbacks_; } void remove(uint16_t handle) { auto connection = le_acl_connections_.find(handle); if (connection != le_acl_connections_.end()) { connection->second.le_connection_management_callbacks_ = nullptr; le_acl_connections_.erase(handle); } } public: bool crash_on_unknown_handle_ = false; bool is_empty() const { std::unique_lock lock(le_acl_connections_guard_); return le_acl_connections_.empty(); } void reset() { std::map le_acl_connections{}; { std::unique_lock lock(le_acl_connections_guard_); le_acl_connections = std::move(le_acl_connections_); } le_acl_connections.clear(); } void invalidate(uint16_t handle) { std::unique_lock lock(le_acl_connections_guard_); remove(handle); } void execute( uint16_t handle, std::function execute, bool remove_afterwards = false) { std::unique_lock lock(le_acl_connections_guard_); auto callbacks = find_callbacks(handle); if (callbacks != nullptr) execute(callbacks); else log::assert_that( !crash_on_unknown_handle_, "Received command for unknown handle:0x{:x}", handle); if (remove_afterwards) remove(handle); } bool send_packet_upward(uint16_t handle, std::function cb) { std::unique_lock lock(le_acl_connections_guard_); auto connection = le_acl_connections_.find(handle); if (connection != le_acl_connections_.end()) cb(connection->second.assembler_); return connection != le_acl_connections_.end(); } void add( uint16_t handle, const AddressWithType& remote_address, std::unique_ptr pending_connection, AclConnection::QueueDownEnd* queue_end, os::Handler* handler, LeConnectionManagementCallbacks* le_connection_management_callbacks) { std::unique_lock lock(le_acl_connections_guard_); auto emplace_pair = le_acl_connections_.emplace( std::piecewise_construct, std::forward_as_tuple(handle), std::forward_as_tuple(remote_address, std::move(pending_connection), queue_end, handler)); log::assert_that( emplace_pair.second, "assert failed: emplace_pair.second"); // Make sure the connection is unique emplace_pair.first->second.le_connection_management_callbacks_ = le_connection_management_callbacks; } std::unique_ptr record_peripheral_data_and_extract_pending_connection( uint16_t handle, DataAsPeripheral data) { std::unique_lock lock(le_acl_connections_guard_); auto connection = le_acl_connections_.find(handle); if (connection != le_acl_connections_.end() && connection->second.pending_connection_.get()) { connection->second.pending_connection_->UpdateRoleSpecificData(data); return std::move(connection->second.pending_connection_); } else { return nullptr; } } uint16_t HACK_get_handle(Address address) const { std::unique_lock lock(le_acl_connections_guard_); for (auto it = le_acl_connections_.begin(); it != le_acl_connections_.end(); it++) { if (it->second.remote_address_.GetAddress() == address) { return it->first; } } return kIllegalConnectionHandle; } AddressWithType getAddressWithType(uint16_t handle) { std::unique_lock lock(le_acl_connections_guard_); auto it = le_acl_connections_.find(handle); if (it != le_acl_connections_.end()) { return it->second.remote_address_; } AddressWithType empty(Address::kEmpty, AddressType::RANDOM_DEVICE_ADDRESS); return empty; } bool alreadyConnected(AddressWithType address_with_type) { for (auto it = le_acl_connections_.begin(); it != le_acl_connections_.end(); it++) { if (it->second.remote_address_ == address_with_type) { return true; } } return false; } } connections; public: void enqueue_command(std::unique_ptr command_packet) { hci_layer_->EnqueueCommand( std::move(command_packet), handler_->BindOnce(&LeAddressManager::OnCommandComplete, common::Unretained(le_address_manager_))); } bool send_packet_upward(uint16_t handle, std::function cb) { return connections.send_packet_upward(handle, cb); } void report_le_connection_failure(AddressWithType address, ErrorCode status) { le_client_handler_->Post(common::BindOnce( &LeConnectionCallbacks::OnLeConnectFail, common::Unretained(le_client_callbacks_), address, status)); if (le_acceptlist_callbacks_ != nullptr) { le_acceptlist_callbacks_->OnLeConnectFail(address, status); } } // connection canceled by LeAddressManager.OnPause(), will auto reconnect by LeAddressManager.OnResume() void on_le_connection_canceled_on_pause() { log::assert_that(pause_connection, "Connection must be paused to ack the le address manager"); arm_on_resume_ = true; connectability_state_ = ConnectabilityState::DISARMED; le_address_manager_->AckPause(this); } void on_common_le_connection_complete(AddressWithType address_with_type) { auto connecting_addr_with_type = connecting_le_.find(address_with_type); if (connecting_addr_with_type == connecting_le_.end()) { log::warn("No prior connection request for {}", address_with_type); } connecting_le_.clear(); direct_connect_remove(address_with_type); } void on_le_connection_complete(LeMetaEventView packet) { ErrorCode status; Address address; AddressType peer_address_type; Role role; AddressWithType remote_address; uint16_t handle, conn_interval, conn_latency, supervision_timeout; if (packet.GetSubeventCode() == SubeventCode::CONNECTION_COMPLETE) { LeConnectionCompleteView connection_complete = LeConnectionCompleteView::Create(packet); log::assert_that( connection_complete.IsValid(), "assert failed: connection_complete.IsValid()"); status = connection_complete.GetStatus(); address = connection_complete.GetPeerAddress(); peer_address_type = connection_complete.GetPeerAddressType(); role = connection_complete.GetRole(); handle = connection_complete.GetConnectionHandle(); conn_interval = connection_complete.GetConnInterval(); conn_latency = connection_complete.GetConnLatency(); supervision_timeout = connection_complete.GetSupervisionTimeout(); remote_address = AddressWithType(address, peer_address_type); } else if (packet.GetSubeventCode() == SubeventCode::ENHANCED_CONNECTION_COMPLETE) { LeEnhancedConnectionCompleteView connection_complete = LeEnhancedConnectionCompleteView::Create(packet); log::assert_that( connection_complete.IsValid(), "assert failed: connection_complete.IsValid()"); status = connection_complete.GetStatus(); address = connection_complete.GetPeerAddress(); peer_address_type = connection_complete.GetPeerAddressType(); role = connection_complete.GetRole(); handle = connection_complete.GetConnectionHandle(); conn_interval = connection_complete.GetConnInterval(); conn_latency = connection_complete.GetConnLatency(); supervision_timeout = connection_complete.GetSupervisionTimeout(); AddressType remote_address_type; switch (peer_address_type) { case AddressType::PUBLIC_DEVICE_ADDRESS: case AddressType::PUBLIC_IDENTITY_ADDRESS: remote_address_type = AddressType::PUBLIC_DEVICE_ADDRESS; break; case AddressType::RANDOM_DEVICE_ADDRESS: case AddressType::RANDOM_IDENTITY_ADDRESS: remote_address_type = AddressType::RANDOM_DEVICE_ADDRESS; break; } remote_address = AddressWithType(address, remote_address_type); } else { log::fatal("Bad subevent code:{:02x}", packet.GetSubeventCode()); return; } const bool in_filter_accept_list = is_device_in_accept_list(remote_address); if (role == hci::Role::CENTRAL) { connectability_state_ = ConnectabilityState::DISARMED; if (status == ErrorCode::UNKNOWN_CONNECTION && pause_connection) { on_le_connection_canceled_on_pause(); return; } if (status == ErrorCode::UNKNOWN_CONNECTION && arm_on_disarm_) { arm_on_disarm_ = false; arm_connectability(); return; } on_common_le_connection_complete(remote_address); if (status == ErrorCode::UNKNOWN_CONNECTION) { if (remote_address.GetAddress() != Address::kEmpty) { log::info("Controller send non-empty address field:{}", remote_address.GetAddress()); } // direct connect canceled due to connection timeout, start background connect create_le_connection(remote_address, false, false); return; } arm_on_resume_ = false; ready_to_unregister = true; remove_device_from_accept_list(remote_address); if (!accept_list.empty()) { AddressWithType empty(Address::kEmpty, AddressType::RANDOM_DEVICE_ADDRESS); handler_->Post(common::BindOnce(&le_impl::create_le_connection, common::Unretained(this), empty, false, false)); } if (le_client_handler_ == nullptr) { log::error("No callbacks to call"); return; } if (status != ErrorCode::SUCCESS) { report_le_connection_failure(remote_address, status); return; } } else { log::info("Received connection complete with Peripheral role"); if (le_client_handler_ == nullptr) { log::error("No callbacks to call"); return; } if (status != ErrorCode::SUCCESS) { std::string error_code = ErrorCodeText(status); log::warn("Received on_le_connection_complete with error code {}", error_code); report_le_connection_failure(remote_address, status); return; } if (in_filter_accept_list) { log::info( "Received incoming connection of device in filter accept_list, {}", remote_address); direct_connect_remove(remote_address); remove_device_from_accept_list(remote_address); } } if (!check_connection_parameters(conn_interval, conn_interval, conn_latency, supervision_timeout)) { log::error("Receive connection complete with invalid connection parameters"); return; } auto role_specific_data = initialize_role_specific_data(role); auto queue = std::make_shared(10); auto queue_down_end = queue->GetDownEnd(); round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, handle, queue); std::unique_ptr connection(new LeAclConnection( std::move(queue), le_acl_connection_interface_, handle, role_specific_data, remote_address)); connection->peer_address_with_type_ = AddressWithType(address, peer_address_type); connection->interval_ = conn_interval; connection->latency_ = conn_latency; connection->supervision_timeout_ = supervision_timeout; connection->in_filter_accept_list_ = in_filter_accept_list; connection->locally_initiated_ = (role == hci::Role::CENTRAL); if (packet.GetSubeventCode() == SubeventCode::ENHANCED_CONNECTION_COMPLETE) { LeEnhancedConnectionCompleteView connection_complete = LeEnhancedConnectionCompleteView::Create(packet); log::assert_that( connection_complete.IsValid(), "assert failed: connection_complete.IsValid()"); connection->local_resolvable_private_address_ = connection_complete.GetLocalResolvablePrivateAddress(); connection->peer_resolvable_private_address_ = connection_complete.GetPeerResolvablePrivateAddress(); } auto connection_callbacks = connection->GetEventCallbacks( [this](uint16_t handle) { this->connections.invalidate(handle); }); if (std::holds_alternative(role_specific_data)) { // the OnLeConnectSuccess event will be sent after receiving the On Advertising Set Terminated // event, since we need it to know what local_address / advertising set the peer connected to. // In the meantime, we store it as a pending_connection. connections.add( handle, remote_address, std::move(connection), queue_down_end, handler_, connection_callbacks); } else { connections.add( handle, remote_address, nullptr, queue_down_end, handler_, connection_callbacks); le_client_handler_->Post(common::BindOnce( &LeConnectionCallbacks::OnLeConnectSuccess, common::Unretained(le_client_callbacks_), remote_address, std::move(connection))); if (le_acceptlist_callbacks_ != nullptr) { le_acceptlist_callbacks_->OnLeConnectSuccess(remote_address); } } } RoleSpecificData initialize_role_specific_data(Role role) { if (role == hci::Role::CENTRAL) { return DataAsCentral{le_address_manager_->GetInitiatorAddress()}; } else if ( controller_->SupportsBleExtendedAdvertising() || controller_->IsSupported(hci::OpCode::LE_MULTI_ADVT)) { // when accepting connection, we must obtain the address from the advertiser. // When we receive "set terminated event", we associate connection handle with advertiser // address return DataAsUninitializedPeripheral{}; } else { // the exception is if we only support legacy advertising - here, our current address is also // our advertised address return DataAsPeripheral{ le_address_manager_->GetInitiatorAddress(), {}, true /* For now, ignore non-discoverable legacy advertising TODO(b/254314964) */}; } } static constexpr bool kRemoveConnectionAfterwards = true; void on_le_disconnect(uint16_t handle, ErrorCode reason) { AddressWithType remote_address = connections.getAddressWithType(handle); bool event_also_routes_to_other_receivers = connections.crash_on_unknown_handle_; connections.crash_on_unknown_handle_ = false; connections.execute( handle, [=, this](LeConnectionManagementCallbacks* callbacks) { round_robin_scheduler_->Unregister(handle); callbacks->OnDisconnection(reason); }, kRemoveConnectionAfterwards); if (le_acceptlist_callbacks_ != nullptr) { le_acceptlist_callbacks_->OnLeDisconnection(remote_address); } connections.crash_on_unknown_handle_ = event_also_routes_to_other_receivers; if (background_connections_.count(remote_address) == 1) { log::info("re-add device to accept list"); arm_on_resume_ = true; add_device_to_accept_list(remote_address); } } void on_le_connection_update_complete(LeMetaEventView view) { auto complete_view = LeConnectionUpdateCompleteView::Create(view); if (!complete_view.IsValid()) { log::error("Received on_le_connection_update_complete with invalid packet"); return; } auto handle = complete_view.GetConnectionHandle(); connections.execute(handle, [=](LeConnectionManagementCallbacks* callbacks) { callbacks->OnConnectionUpdate( complete_view.GetStatus(), complete_view.GetConnInterval(), complete_view.GetConnLatency(), complete_view.GetSupervisionTimeout()); }); } void on_le_phy_update_complete(LeMetaEventView view) { auto complete_view = LePhyUpdateCompleteView::Create(view); if (!complete_view.IsValid()) { log::error("Received on_le_phy_update_complete with invalid packet"); return; } auto handle = complete_view.GetConnectionHandle(); connections.execute(handle, [=](LeConnectionManagementCallbacks* callbacks) { callbacks->OnPhyUpdate(complete_view.GetStatus(), complete_view.GetTxPhy(), complete_view.GetRxPhy()); }); } void on_le_read_remote_version_information( hci::ErrorCode hci_status, uint16_t handle, uint8_t version, uint16_t manufacturer_name, uint16_t sub_version) { connections.execute(handle, [=](LeConnectionManagementCallbacks* callbacks) { callbacks->OnReadRemoteVersionInformationComplete(hci_status, version, manufacturer_name, sub_version); }); } void on_data_length_change(LeMetaEventView view) { auto data_length_view = LeDataLengthChangeView::Create(view); if (!data_length_view.IsValid()) { log::error("Invalid packet"); return; } auto handle = data_length_view.GetConnectionHandle(); connections.execute(handle, [=](LeConnectionManagementCallbacks* callbacks) { callbacks->OnDataLengthChange( data_length_view.GetMaxTxOctets(), data_length_view.GetMaxTxTime(), data_length_view.GetMaxRxOctets(), data_length_view.GetMaxRxTime()); }); } void on_remote_connection_parameter_request(LeMetaEventView view) { auto request_view = LeRemoteConnectionParameterRequestView::Create(view); if (!request_view.IsValid()) { log::error("Invalid packet"); return; } auto handle = request_view.GetConnectionHandle(); connections.execute(handle, [=, this](LeConnectionManagementCallbacks* /* callbacks */) { // TODO: this is blindly accepting any parameters, just so we don't hang connection // have proper parameter negotiation le_acl_connection_interface_->EnqueueCommand( LeRemoteConnectionParameterRequestReplyBuilder::Create( handle, request_view.GetIntervalMin(), request_view.GetIntervalMax(), request_view.GetLatency(), request_view.GetTimeout(), 0, 0), handler_->BindOnce([](CommandCompleteView /* status */) {})); }); } void on_le_subrate_change(LeMetaEventView view) { auto subrate_change_view = LeSubrateChangeView::Create(view); if (!subrate_change_view.IsValid()) { log::error("Invalid packet"); return; } auto handle = subrate_change_view.GetConnectionHandle(); connections.execute(handle, [=](LeConnectionManagementCallbacks* callbacks) { callbacks->OnLeSubrateChange( subrate_change_view.GetStatus(), subrate_change_view.GetSubrateFactor(), subrate_change_view.GetPeripheralLatency(), subrate_change_view.GetContinuationNumber(), subrate_change_view.GetSupervisionTimeout()); }); } uint16_t HACK_get_handle(Address address) { return connections.HACK_get_handle(address); } Address HACK_get_address(uint16_t connection_handle) { return connections.getAddressWithType(connection_handle).GetAddress(); } void OnAdvertisingSetTerminated( uint16_t conn_handle, uint8_t adv_set_id, hci::AddressWithType adv_set_address, bool is_discoverable) { auto connection = connections.record_peripheral_data_and_extract_pending_connection( conn_handle, DataAsPeripheral{adv_set_address, adv_set_id, is_discoverable}); if (connection != nullptr) { if (le_acceptlist_callbacks_ != nullptr) { le_acceptlist_callbacks_->OnLeConnectSuccess(connection->GetRemoteAddress()); } le_client_handler_->Post(common::BindOnce( &LeConnectionCallbacks::OnLeConnectSuccess, common::Unretained(le_client_callbacks_), connection->GetRemoteAddress(), std::move(connection))); } } void direct_connect_add(AddressWithType address_with_type) { direct_connections_.insert(address_with_type); if (create_connection_timeout_alarms_.find(address_with_type) != create_connection_timeout_alarms_.end()) { return; } auto emplace_result = create_connection_timeout_alarms_.emplace( std::piecewise_construct, std::forward_as_tuple(address_with_type.GetAddress(), address_with_type.GetAddressType()), std::forward_as_tuple(handler_)); uint32_t connection_timeout = os::GetSystemPropertyUint32(kPropertyDirectConnTimeout, kCreateConnectionTimeoutMs); emplace_result.first->second.Schedule( common::BindOnce(&le_impl::on_create_connection_timeout, common::Unretained(this), address_with_type), std::chrono::milliseconds(connection_timeout)); } void direct_connect_remove(AddressWithType address_with_type) { auto it = create_connection_timeout_alarms_.find(address_with_type); if (it != create_connection_timeout_alarms_.end()) { it->second.Cancel(); create_connection_timeout_alarms_.erase(it); } direct_connections_.erase(address_with_type); } void add_device_to_accept_list(AddressWithType address_with_type) { if (connections.alreadyConnected(address_with_type)) { log::info("Device already connected, return"); return; } if (accept_list.find(address_with_type) != accept_list.end()) { log::warn("Device already exists in acceptlist and cannot be added: {}", address_with_type); return; } accept_list.insert(address_with_type); register_with_address_manager(); le_address_manager_->AddDeviceToFilterAcceptList( address_with_type.ToFilterAcceptListAddressType(), address_with_type.GetAddress()); } bool is_device_in_accept_list(AddressWithType address_with_type) { return (accept_list.find(address_with_type) != accept_list.end()); } void remove_device_from_accept_list(AddressWithType address_with_type) { if (accept_list.find(address_with_type) == accept_list.end()) { log::warn("Device not in acceptlist and cannot be removed: {}", address_with_type); return; } accept_list.erase(address_with_type); connecting_le_.erase(address_with_type); register_with_address_manager(); le_address_manager_->RemoveDeviceFromFilterAcceptList( address_with_type.ToFilterAcceptListAddressType(), address_with_type.GetAddress()); } void clear_filter_accept_list() { accept_list.clear(); register_with_address_manager(); le_address_manager_->ClearFilterAcceptList(); } void add_device_to_resolving_list( AddressWithType address_with_type, const std::array& peer_irk, const std::array& local_irk) { register_with_address_manager(); le_address_manager_->AddDeviceToResolvingList( address_with_type.ToPeerAddressType(), address_with_type.GetAddress(), peer_irk, local_irk); if (le_acceptlist_callbacks_ != nullptr) { le_acceptlist_callbacks_->OnResolvingListChange(); } } void remove_device_from_resolving_list(AddressWithType address_with_type) { register_with_address_manager(); le_address_manager_->RemoveDeviceFromResolvingList( address_with_type.ToPeerAddressType(), address_with_type.GetAddress()); if (le_acceptlist_callbacks_ != nullptr) { le_acceptlist_callbacks_->OnResolvingListChange(); } } void update_connectability_state_after_armed(const ErrorCode& status) { switch (connectability_state_) { case ConnectabilityState::DISARMED: case ConnectabilityState::ARMED: case ConnectabilityState::DISARMING: log::error( "Received connectability arm notification for unexpected state:{} status:{}", connectability_state_machine_text(connectability_state_), ErrorCodeText(status)); break; case ConnectabilityState::ARMING: if (status != ErrorCode::SUCCESS) { log::error("Le connection state machine armed failed status:{}", ErrorCodeText(status)); } connectability_state_ = (status == ErrorCode::SUCCESS) ? ConnectabilityState::ARMED : ConnectabilityState::DISARMED; log::info( "Le connection state machine armed state:{} status:{}", connectability_state_machine_text(connectability_state_), ErrorCodeText(status)); if (disarmed_while_arming_) { disarmed_while_arming_ = false; disarm_connectability(); } } } void on_extended_create_connection(CommandStatusView status) { log::assert_that(status.IsValid(), "assert failed: status.IsValid()"); log::assert_that( status.GetCommandOpCode() == OpCode::LE_EXTENDED_CREATE_CONNECTION, "assert failed: status.GetCommandOpCode() == OpCode::LE_EXTENDED_CREATE_CONNECTION"); update_connectability_state_after_armed(status.GetStatus()); } void on_create_connection(CommandStatusView status) { log::assert_that(status.IsValid(), "assert failed: status.IsValid()"); log::assert_that( status.GetCommandOpCode() == OpCode::LE_CREATE_CONNECTION, "assert failed: status.GetCommandOpCode() == OpCode::LE_CREATE_CONNECTION"); update_connectability_state_after_armed(status.GetStatus()); } void arm_connectability() { if (connectability_state_ != ConnectabilityState::DISARMED) { log::error( "Attempting to re-arm le connection state machine in unexpected state:{}", connectability_state_machine_text(connectability_state_)); return; } if (accept_list.empty()) { log::info( "Ignored request to re-arm le connection state machine when filter accept list is empty"); return; } AddressWithType empty(Address::kEmpty, AddressType::RANDOM_DEVICE_ADDRESS); connectability_state_ = ConnectabilityState::ARMING; connecting_le_ = accept_list; uint16_t le_scan_interval = os::GetSystemPropertyUint32(kPropertyConnScanIntervalSlow, kScanIntervalSlow); uint16_t le_scan_window = os::GetSystemPropertyUint32(kPropertyConnScanWindowSlow, kScanWindowSlow); uint16_t le_scan_window_2m = le_scan_window; uint16_t le_scan_window_coded = le_scan_window; // If there is any direct connection in the connection list, use the fast parameter if (!direct_connections_.empty()) { le_scan_interval = os::GetSystemPropertyUint32(kPropertyConnScanIntervalFast, kScanIntervalFast); le_scan_window = os::GetSystemPropertyUint32(kPropertyConnScanWindowFast, kScanWindowFast); le_scan_window_2m = os::GetSystemPropertyUint32(kPropertyConnScanWindow2mFast, kScanWindow2mFast); le_scan_window_coded = os::GetSystemPropertyUint32(kPropertyConnScanWindowCodedFast, kScanWindowCodedFast); } // Use specific parameters when in system suspend. if (system_suspend_) { le_scan_interval = os::GetSystemPropertyUint32( kPropertyConnScanIntervalSystemSuspend, kScanIntervalSystemSuspend); le_scan_window = os::GetSystemPropertyUint32( kPropertyConnScanWindowSystemSuspend, kScanWindowSystemSuspend); le_scan_window_2m = le_scan_window; le_scan_window_coded = le_scan_window; } InitiatorFilterPolicy initiator_filter_policy = InitiatorFilterPolicy::USE_FILTER_ACCEPT_LIST; OwnAddressType own_address_type = static_cast(le_address_manager_->GetInitiatorAddress().GetAddressType()); uint16_t conn_interval_min = os::GetSystemPropertyUint32(kPropertyMinConnInterval, kConnIntervalMin); uint16_t conn_interval_max = os::GetSystemPropertyUint32(kPropertyMaxConnInterval, kConnIntervalMax); uint16_t conn_latency = os::GetSystemPropertyUint32(kPropertyConnLatency, kConnLatency); uint16_t supervision_timeout = os::GetSystemPropertyUint32(kPropertyConnSupervisionTimeout, kSupervisionTimeout); log::assert_that( check_connection_parameters( conn_interval_min, conn_interval_max, conn_latency, supervision_timeout), "assert failed: check_connection_parameters(conn_interval_min, conn_interval_max, " "conn_latency, supervision_timeout)"); AddressWithType address_with_type = connection_peer_address_with_type_; if (initiator_filter_policy == InitiatorFilterPolicy::USE_FILTER_ACCEPT_LIST) { address_with_type = AddressWithType(); } if (controller_->IsSupported(OpCode::LE_EXTENDED_CREATE_CONNECTION)) { bool only_init_1m_phy = os::GetSystemPropertyBool(kPropertyEnableBleOnlyInit1mPhy, kEnableBleOnlyInit1mPhy); uint8_t initiating_phys = PHY_LE_1M; std::vector parameters = {}; LeCreateConnPhyScanParameters scan_parameters; scan_parameters.scan_interval_ = le_scan_interval; scan_parameters.scan_window_ = le_scan_window; scan_parameters.conn_interval_min_ = conn_interval_min; scan_parameters.conn_interval_max_ = conn_interval_max; scan_parameters.conn_latency_ = conn_latency; scan_parameters.supervision_timeout_ = supervision_timeout; scan_parameters.min_ce_length_ = 0x00; scan_parameters.max_ce_length_ = 0x00; parameters.push_back(scan_parameters); if (controller_->SupportsBle2mPhy() && !only_init_1m_phy) { LeCreateConnPhyScanParameters scan_parameters_2m; scan_parameters_2m.scan_interval_ = le_scan_interval; scan_parameters_2m.scan_window_ = le_scan_window_2m; scan_parameters_2m.conn_interval_min_ = conn_interval_min; scan_parameters_2m.conn_interval_max_ = conn_interval_max; scan_parameters_2m.conn_latency_ = conn_latency; scan_parameters_2m.supervision_timeout_ = supervision_timeout; scan_parameters_2m.min_ce_length_ = 0x00; scan_parameters_2m.max_ce_length_ = 0x00; parameters.push_back(scan_parameters_2m); initiating_phys |= PHY_LE_2M; } if (controller_->SupportsBleCodedPhy() && !only_init_1m_phy) { LeCreateConnPhyScanParameters scan_parameters_coded; scan_parameters_coded.scan_interval_ = le_scan_interval; scan_parameters_coded.scan_window_ = le_scan_window_coded; scan_parameters_coded.conn_interval_min_ = conn_interval_min; scan_parameters_coded.conn_interval_max_ = conn_interval_max; scan_parameters_coded.conn_latency_ = conn_latency; scan_parameters_coded.supervision_timeout_ = supervision_timeout; scan_parameters_coded.min_ce_length_ = 0x00; scan_parameters_coded.max_ce_length_ = 0x00; parameters.push_back(scan_parameters_coded); initiating_phys |= PHY_LE_CODED; } le_acl_connection_interface_->EnqueueCommand( LeExtendedCreateConnectionBuilder::Create( initiator_filter_policy, own_address_type, address_with_type.GetAddressType(), address_with_type.GetAddress(), initiating_phys, parameters), handler_->BindOnce(&le_impl::on_extended_create_connection, common::Unretained(this))); } else { le_acl_connection_interface_->EnqueueCommand( LeCreateConnectionBuilder::Create( le_scan_interval, le_scan_window, initiator_filter_policy, address_with_type.GetAddressType(), address_with_type.GetAddress(), own_address_type, conn_interval_min, conn_interval_max, conn_latency, supervision_timeout, 0x00, 0x00), handler_->BindOnce(&le_impl::on_create_connection, common::Unretained(this))); } } void disarm_connectability() { switch (connectability_state_) { case ConnectabilityState::ARMED: log::info("Disarming LE connection state machine with create connection cancel"); connectability_state_ = ConnectabilityState::DISARMING; le_acl_connection_interface_->EnqueueCommand( LeCreateConnectionCancelBuilder::Create(), handler_->BindOnce(&le_impl::on_create_connection_cancel_complete, common::Unretained(this))); break; case ConnectabilityState::ARMING: log::info("Queueing cancel connect until after connection state machine is armed"); disarmed_while_arming_ = true; break; case ConnectabilityState::DISARMING: case ConnectabilityState::DISARMED: log::error( "Attempting to disarm le connection state machine in unexpected state:{}", connectability_state_machine_text(connectability_state_)); break; } } void create_le_connection(AddressWithType address_with_type, bool add_to_accept_list, bool is_direct) { if (le_client_callbacks_ == nullptr) { log::error("No callbacks to call"); return; } if (connections.alreadyConnected(address_with_type)) { log::info("Device already connected, return"); return; } bool already_in_accept_list = accept_list.find(address_with_type) != accept_list.end(); // TODO: Configure default LE connection parameters? if (add_to_accept_list) { if (!already_in_accept_list) { add_device_to_accept_list(address_with_type); } if (is_direct) { direct_connect_add(address_with_type); } } if (!address_manager_registered) { auto policy = le_address_manager_->Register(this); address_manager_registered = true; // Pause connection, wait for set random address complete if (policy == LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS || policy == LeAddressManager::AddressPolicy::USE_NON_RESOLVABLE_ADDRESS) { pause_connection = true; } } if (pause_connection) { arm_on_resume_ = true; return; } switch (connectability_state_) { case ConnectabilityState::ARMED: case ConnectabilityState::ARMING: if (already_in_accept_list) { arm_on_disarm_ = true; disarm_connectability(); } else { // Ignored, if we add new device to the filter accept list, create connection command will // be sent by OnResume. log::debug( "Deferred until filter accept list updated create connection state {}", connectability_state_machine_text(connectability_state_)); } break; default: // If we added to filter accept list then the arming of the le state machine // must wait until the filter accept list command as completed if (add_to_accept_list) { arm_on_resume_ = true; log::debug("Deferred until filter accept list has completed"); } else { handler_->CallOn(this, &le_impl::arm_connectability); } break; } } void on_create_connection_timeout(AddressWithType address_with_type) { log::info("on_create_connection_timeout, address: {}", address_with_type); direct_connect_remove(address_with_type); if (background_connections_.find(address_with_type) != background_connections_.end()) { disarm_connectability(); } else { remove_device_from_accept_list(address_with_type); } le_client_handler_->Post(common::BindOnce( &LeConnectionCallbacks::OnLeConnectFail, common::Unretained(le_client_callbacks_), address_with_type, ErrorCode::CONNECTION_ACCEPT_TIMEOUT)); } void cancel_connect(AddressWithType address_with_type) { direct_connect_remove(address_with_type); // the connection will be canceled by LeAddressManager.OnPause() remove_device_from_accept_list(address_with_type); } void set_le_suggested_default_data_parameters(uint16_t length, uint16_t time) { auto packet = LeWriteSuggestedDefaultDataLengthBuilder::Create(length, time); le_acl_connection_interface_->EnqueueCommand( std::move(packet), handler_->BindOnce([](CommandCompleteView /* complete */) {})); } void LeSetDefaultSubrate( uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, uint16_t cont_num, uint16_t sup_tout) { le_acl_connection_interface_->EnqueueCommand( LeSetDefaultSubrateBuilder::Create(subrate_min, subrate_max, max_latency, cont_num, sup_tout), handler_->BindOnce([](CommandCompleteView complete) { auto complete_view = LeSetDefaultSubrateCompleteView::Create(complete); log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); ErrorCode status = complete_view.GetStatus(); log::assert_that(status == ErrorCode::SUCCESS, "Status = {}", ErrorCodeText(status)); })); } void clear_resolving_list() { le_address_manager_->ClearResolvingList(); } void set_privacy_policy_for_initiator_address( LeAddressManager::AddressPolicy address_policy, AddressWithType fixed_address, Octet16 rotation_irk, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time) { le_address_manager_->SetPrivacyPolicyForInitiatorAddress( address_policy, fixed_address, rotation_irk, controller_->SupportsBlePrivacy() && os::GetSystemPropertyBool(kPropertyEnableBlePrivacy, kEnableBlePrivacy), minimum_rotation_time, maximum_rotation_time); } // TODO(jpawlowski): remove once we have config file abstraction in cert tests void set_privacy_policy_for_initiator_address_for_test( LeAddressManager::AddressPolicy address_policy, AddressWithType fixed_address, Octet16 rotation_irk, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time) { le_address_manager_->SetPrivacyPolicyForInitiatorAddressForTest( address_policy, fixed_address, rotation_irk, minimum_rotation_time, maximum_rotation_time); } void handle_register_le_callbacks(LeConnectionCallbacks* callbacks, os::Handler* handler) { log::assert_that( le_client_callbacks_ == nullptr, "assert failed: le_client_callbacks_ == nullptr"); log::assert_that(le_client_handler_ == nullptr, "assert failed: le_client_handler_ == nullptr"); le_client_callbacks_ = callbacks; le_client_handler_ = handler; } void handle_register_le_acceptlist_callbacks(LeAcceptlistCallbacks* callbacks) { log::assert_that( le_acceptlist_callbacks_ == nullptr, "assert failed: le_acceptlist_callbacks_ == nullptr"); le_acceptlist_callbacks_ = callbacks; } void handle_unregister_le_callbacks(LeConnectionCallbacks* callbacks, std::promise promise) { log::assert_that( le_client_callbacks_ == callbacks, "Registered le callback entity is different then unregister request"); le_client_callbacks_ = nullptr; le_client_handler_ = nullptr; promise.set_value(); } void handle_unregister_le_acceptlist_callbacks( LeAcceptlistCallbacks* callbacks, std::promise promise) { log::assert_that( le_acceptlist_callbacks_ == callbacks, "Registered le callback entity is different then unregister request"); le_acceptlist_callbacks_ = nullptr; promise.set_value(); } bool check_connection_parameters( uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout) { if (conn_interval_min < 0x0006 || conn_interval_min > 0x0C80 || conn_interval_max < 0x0006 || conn_interval_max > 0x0C80 || conn_latency > 0x01F3 || supervision_timeout < 0x000A || supervision_timeout > 0x0C80) { log::error("Invalid parameter"); return false; } // The Maximum interval in milliseconds will be conn_interval_max * 1.25 ms // The Timeout in milliseconds will be expected_supervision_timeout * 10 ms // The Timeout in milliseconds shall be larger than (1 + Latency) * Interval_Max * 2, where Interval_Max is given in // milliseconds. uint32_t supervision_timeout_min = (uint32_t)(1 + conn_latency) * conn_interval_max * 2 + 1; if (supervision_timeout * 8 < supervision_timeout_min || conn_interval_max < conn_interval_min) { log::error("Invalid parameter"); return false; } return true; } void add_device_to_background_connection_list(AddressWithType address_with_type) { background_connections_.insert(address_with_type); } void remove_device_from_background_connection_list(AddressWithType address_with_type) { background_connections_.erase(address_with_type); } void is_on_background_connection_list(AddressWithType address_with_type, std::promise promise) { promise.set_value(background_connections_.find(address_with_type) != background_connections_.end()); } void OnPause() override { // bluetooth::hci::LeAddressManagerCallback if (!address_manager_registered) { log::warn("Unregistered!"); return; } pause_connection = true; if (connectability_state_ == ConnectabilityState::DISARMED) { le_address_manager_->AckPause(this); return; } arm_on_resume_ = !connecting_le_.empty(); disarm_connectability(); } void OnResume() override { // bluetooth::hci::LeAddressManagerCallback if (!address_manager_registered) { log::warn("Unregistered!"); return; } pause_connection = false; if (arm_on_resume_) { arm_connectability(); } arm_on_resume_ = false; le_address_manager_->AckResume(this); check_for_unregister(); } void on_create_connection_cancel_complete(CommandCompleteView view) { auto complete_view = LeCreateConnectionCancelCompleteView::Create(view); log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); if (complete_view.GetStatus() != ErrorCode::SUCCESS) { auto status = complete_view.GetStatus(); std::string error_code = ErrorCodeText(status); log::warn("Received on_create_connection_cancel_complete with error code {}", error_code); if (pause_connection) { log::warn("AckPause"); le_address_manager_->AckPause(this); return; } } if (connectability_state_ != ConnectabilityState::DISARMING) { log::error( "Attempting to disarm le connection state machine in unexpected state:{}", connectability_state_machine_text(connectability_state_)); } } void register_with_address_manager() { if (!address_manager_registered) { le_address_manager_->Register(this); address_manager_registered = true; pause_connection = true; } } void check_for_unregister() { if (connections.is_empty() && connecting_le_.empty() && address_manager_registered && ready_to_unregister) { le_address_manager_->Unregister(this); address_manager_registered = false; pause_connection = false; ready_to_unregister = false; } } void set_system_suspend_state(bool suspended) { system_suspend_ = suspended; } HciLayer* hci_layer_ = nullptr; Controller* controller_ = nullptr; os::Handler* handler_ = nullptr; RoundRobinScheduler* round_robin_scheduler_ = nullptr; LeAddressManager* le_address_manager_ = nullptr; LeAclConnectionInterface* le_acl_connection_interface_ = nullptr; LeConnectionCallbacks* le_client_callbacks_ = nullptr; os::Handler* le_client_handler_ = nullptr; LeAcceptlistCallbacks* le_acceptlist_callbacks_ = nullptr; std::unordered_set connecting_le_{}; bool arm_on_resume_{}; bool arm_on_disarm_{}; std::unordered_set direct_connections_{}; // Set of devices that will not be removed from accept list after direct connect timeout std::unordered_set background_connections_; /* This is content of controller "Filter Accept List"*/ std::unordered_set accept_list; AddressWithType connection_peer_address_with_type_; // Direct peer address UNSUPPORTEDD bool address_manager_registered = false; bool ready_to_unregister = false; bool pause_connection = false; bool disarmed_while_arming_ = false; bool system_suspend_ = false; ConnectabilityState connectability_state_{ConnectabilityState::DISARMED}; std::map create_connection_timeout_alarms_{}; }; } // namespace acl_manager } // namespace hci } // namespace bluetooth