/* * Copyright 2022 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 "remote_name_request.h" #include #include #include #include #include "hci/acl_manager/acl_scheduler.h" #include "hci/acl_manager/event_checkers.h" #include "hci/hci_layer.h" namespace bluetooth { namespace hci { struct RemoteNameRequestModule::impl { public: impl(const RemoteNameRequestModule& module) : module_(module) {} void Start() { LOG_INFO("Starting RemoteNameRequestModule"); hci_layer_ = module_.GetDependency(); acl_scheduler_ = module_.GetDependency(); handler_ = module_.GetHandler(); hci_layer_->RegisterEventHandler( EventCode::REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION, handler_->BindOn( this, &RemoteNameRequestModule::impl::on_remote_host_supported_features_notification)); hci_layer_->RegisterEventHandler( EventCode::REMOTE_NAME_REQUEST_COMPLETE, handler_->BindOn(this, &RemoteNameRequestModule::impl::on_remote_name_request_complete)); } void Stop() { LOG_INFO("Stopping RemoteNameRequestModule"); hci_layer_->UnregisterEventHandler(EventCode::REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION); hci_layer_->UnregisterEventHandler(EventCode::REMOTE_NAME_REQUEST_COMPLETE); } void StartRemoteNameRequest( Address address, std::unique_ptr request, CompletionCallback on_completion, RemoteHostSupportedFeaturesCallback on_remote_host_supported_features_notification, RemoteNameCallback on_remote_name_complete) { LOG_INFO("Enqueuing remote name request to %s", address.ToRedactedStringForLogging().c_str()); // This callback needs to be shared between the *start* callback and the *cancel_completed* // callback, so we refcount it for safety. But since the scheduler guarantees that exactly one // of these callbacks will be invokes, this is safe. auto on_remote_name_complete_ptr = std::make_shared(std::move(on_remote_name_complete)); acl_scheduler_->EnqueueRemoteNameRequest( address, handler_->BindOnceOn( this, &impl::actually_start_remote_name_request, address, std::move(request), std::move(on_completion), std::move(on_remote_host_supported_features_notification), on_remote_name_complete_ptr), handler_->BindOnce( [&](Address address, std::shared_ptr on_remote_name_complete_ptr) { LOG_INFO( "Dequeued remote name request to %s since it was cancelled", address.ToRedactedStringForLogging().c_str()); on_remote_name_complete_ptr->Invoke(ErrorCode::PAGE_TIMEOUT, {}); }, address, on_remote_name_complete_ptr)); } void CancelRemoteNameRequest(Address address) { LOG_INFO( "Enqueuing cancel of remote name request to %s", address.ToRedactedStringForLogging().c_str()); acl_scheduler_->CancelRemoteNameRequest( address, handler_->BindOnceOn(this, &impl::actually_cancel_remote_name_request, address)); } void ReportRemoteNameRequestCancellation(Address address) { if (pending_) { LOG_INFO( "Received CONNECTION_COMPLETE (corresponding INCORRECTLY to an RNR cancellation) from %s", address.ToRedactedStringForLogging().c_str()); pending_ = false; on_remote_name_complete_.Invoke(ErrorCode::UNKNOWN_CONNECTION, {}); acl_scheduler_->ReportRemoteNameRequestCompletion(address); } else { LOG_ERROR( "Received unexpected CONNECTION_COMPLETE when no Remote Name Request OR ACL connection " "is outstanding"); } } private: void actually_start_remote_name_request( Address address, std::unique_ptr request, CompletionCallback on_completion, RemoteHostSupportedFeaturesCallback on_remote_host_supported_features_notification, std::shared_ptr on_remote_name_complete_ptr) { LOG_INFO("Starting remote name request to %s", address.ToRedactedStringForLogging().c_str()); ASSERT(pending_ == false); pending_ = true; on_remote_host_supported_features_notification_ = std::move(on_remote_host_supported_features_notification); on_remote_name_complete_ = std::move(*on_remote_name_complete_ptr.get()); hci_layer_->EnqueueCommand( std::move(request), handler_->BindOnceOn( this, &impl::on_start_remote_name_request_status, address, std::move(on_completion))); } void on_start_remote_name_request_status( Address address, CompletionCallback on_completion, CommandStatusView status) { ASSERT(pending_ == true); ASSERT(status.GetCommandOpCode() == OpCode::REMOTE_NAME_REQUEST); LOG_INFO( "Got status %hhu when starting remote name request to to %s", status.GetStatus(), address.ToString().c_str()); on_completion.Invoke(status.GetStatus()); if (status.GetStatus() != ErrorCode::SUCCESS /* pending */) { pending_ = false; acl_scheduler_->ReportRemoteNameRequestCompletion(address); } } void actually_cancel_remote_name_request(Address address) { ASSERT(pending_ == true); LOG_INFO("Cancelling remote name request to %s", address.ToRedactedStringForLogging().c_str()); hci_layer_->EnqueueCommand( RemoteNameRequestCancelBuilder::Create(address), handler_->BindOnce( &acl_manager::check_command_complete)); } void on_remote_host_supported_features_notification(EventView view) { auto packet = RemoteHostSupportedFeaturesNotificationView::Create(view); ASSERT(packet.IsValid()); if (pending_) { LOG_INFO( "Received REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION from %s", packet.GetBdAddr().ToRedactedStringForLogging().c_str()); on_remote_host_supported_features_notification_.Invoke(packet.GetHostSupportedFeatures()); } else { LOG_ERROR( "Received unexpected REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION when no Remote Name " "Request is outstanding"); } } void on_remote_name_request_complete(EventView view) { auto packet = RemoteNameRequestCompleteView::Create(view); ASSERT(packet.IsValid()); if (pending_) { LOG_INFO( "Received REMOTE_NAME_REQUEST_COMPLETE from %s", packet.GetBdAddr().ToRedactedStringForLogging().c_str()); pending_ = false; on_remote_name_complete_.Invoke(packet.GetStatus(), packet.GetRemoteName()); acl_scheduler_->ReportRemoteNameRequestCompletion(packet.GetBdAddr()); } else { LOG_ERROR( "Received unexpected REMOTE_NAME_REQUEST_COMPLETE when no Remote Name Request is " "outstanding"); } } const RemoteNameRequestModule& module_; HciLayer* hci_layer_; acl_manager::AclScheduler* acl_scheduler_; os::Handler* handler_; bool pending_ = false; RemoteHostSupportedFeaturesCallback on_remote_host_supported_features_notification_; RemoteNameCallback on_remote_name_complete_; }; const ModuleFactory RemoteNameRequestModule::Factory = ModuleFactory([]() { return new RemoteNameRequestModule(); }); RemoteNameRequestModule::RemoteNameRequestModule() : pimpl_(std::make_unique(*this)){}; RemoteNameRequestModule::~RemoteNameRequestModule() = default; void RemoteNameRequestModule::StartRemoteNameRequest( Address address, std::unique_ptr request, CompletionCallback on_completion, RemoteHostSupportedFeaturesCallback on_remote_host_supported_features_notification, RemoteNameCallback on_remote_name_complete) { CallOn( pimpl_.get(), &impl::StartRemoteNameRequest, address, std::move(request), std::move(on_completion), std::move(on_remote_host_supported_features_notification), std::move(on_remote_name_complete)); } void RemoteNameRequestModule::CancelRemoteNameRequest(Address address) { CallOn(pimpl_.get(), &impl::CancelRemoteNameRequest, address); } void RemoteNameRequestModule::ReportRemoteNameRequestCancellation(Address address) { CallOn(pimpl_.get(), &impl::ReportRemoteNameRequestCancellation, address); } void RemoteNameRequestModule::ListDependencies(ModuleList* list) const { list->add(); list->add(); } void RemoteNameRequestModule::Start() { pimpl_->Start(); } void RemoteNameRequestModule::Stop() { pimpl_->Stop(); } } // namespace hci } // namespace bluetooth