| /* |
| * 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. |
| */ |
| #pragma once |
| |
| #include <chrono> |
| #include <memory> |
| #include <utility> |
| |
| #include "common/callback.h" |
| #include "common/init_flags.h" |
| #include "hci/address_with_type.h" |
| #include "hci/hci_packets.h" |
| #include "hci/le_scanning_callback.h" |
| #include "hci/le_scanning_interface.h" |
| #include "hci/uuid.h" |
| #include "module.h" |
| #include "os/alarm.h" |
| #include "os/log.h" |
| |
| namespace bluetooth { |
| namespace hci { |
| |
| constexpr std::chrono::duration kPeriodicSyncTimeout = std::chrono::seconds(30); |
| constexpr int kMaxSyncTransactions = 16; |
| |
| enum PeriodicSyncState : int { |
| PERIODIC_SYNC_STATE_IDLE = 0, |
| PERIODIC_SYNC_STATE_PENDING, |
| PERIODIC_SYNC_STATE_ESTABLISHED, |
| }; |
| |
| struct PeriodicSyncTransferStates { |
| int pa_source; |
| int connection_handle; |
| Address addr; |
| }; |
| |
| struct PeriodicSyncStates { |
| int request_id; |
| uint8_t advertiser_sid; |
| AddressWithType address_with_type; |
| uint16_t sync_handle; |
| PeriodicSyncState sync_state; |
| }; |
| |
| struct PendingPeriodicSyncRequest { |
| PendingPeriodicSyncRequest( |
| uint8_t advertiser_sid, |
| AddressWithType address_with_type, |
| uint16_t skip, |
| uint16_t sync_timeout, |
| os::Handler* handler) |
| : advertiser_sid(advertiser_sid), |
| address_with_type(std::move(address_with_type)), |
| skip(skip), |
| sync_timeout(sync_timeout), |
| sync_timeout_alarm(handler) {} |
| bool busy = false; |
| uint8_t advertiser_sid; |
| AddressWithType address_with_type; |
| uint16_t skip; |
| uint16_t sync_timeout; |
| os::Alarm sync_timeout_alarm; |
| }; |
| |
| class PeriodicSyncManager { |
| public: |
| explicit PeriodicSyncManager(ScanningCallback* callbacks) |
| : le_scanning_interface_(nullptr), handler_(nullptr), callbacks_(callbacks), sync_received_callback_id(0) {} |
| |
| void Init(hci::LeScanningInterface* le_scanning_interface, os::Handler* handler) { |
| le_scanning_interface_ = le_scanning_interface; |
| handler_ = handler; |
| } |
| |
| void SetScanningCallback(ScanningCallback* callbacks) { |
| callbacks_ = callbacks; |
| } |
| |
| void StartSync(const PeriodicSyncStates& request, uint16_t skip, uint16_t sync_timeout) { |
| if (periodic_syncs_.size() >= kMaxSyncTransactions) { |
| int status = static_cast<int>(ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES); |
| callbacks_->OnPeriodicSyncStarted( |
| request.request_id, status, 0, request.advertiser_sid, request.address_with_type, 0, 0); |
| return; |
| } |
| auto address_type = request.address_with_type.GetAddressType(); |
| ASSERT_LOG( |
| (address_type == AddressType::PUBLIC_DEVICE_ADDRESS || address_type == AddressType::RANDOM_DEVICE_ADDRESS), |
| "Invalid address type %s", |
| AddressTypeText(address_type).c_str()); |
| periodic_syncs_.emplace_back(request); |
| LOG_DEBUG("address = %s, sid = %d", request.address_with_type.ToString().c_str(), request.advertiser_sid); |
| pending_sync_requests_.emplace_back( |
| request.advertiser_sid, request.address_with_type, skip, sync_timeout, handler_); |
| HandleNextRequest(); |
| } |
| |
| void StopSync(uint16_t handle) { |
| LOG_DEBUG("[PSync]: handle = %u", handle); |
| auto periodic_sync = GetEstablishedSyncFromHandle(handle); |
| if (periodic_sync == periodic_syncs_.end()) { |
| LOG_ERROR("[PSync]: invalid index for handle %u", handle); |
| le_scanning_interface_->EnqueueCommand( |
| hci::LePeriodicAdvertisingTerminateSyncBuilder::Create(handle), |
| handler_->BindOnceOn( |
| this, &PeriodicSyncManager::check_status<LePeriodicAdvertisingTerminateSyncCompleteView>)); |
| return; |
| }; |
| periodic_syncs_.erase(periodic_sync); |
| le_scanning_interface_->EnqueueCommand( |
| hci::LePeriodicAdvertisingTerminateSyncBuilder::Create(handle), |
| handler_->BindOnceOn(this, &PeriodicSyncManager::check_status<LePeriodicAdvertisingTerminateSyncCompleteView>)); |
| } |
| |
| void CancelCreateSync(uint8_t adv_sid, Address address) { |
| LOG_DEBUG("[PSync]"); |
| auto periodic_sync = GetSyncFromAddressAndSid(address, adv_sid); |
| if (periodic_sync == periodic_syncs_.end()) { |
| LOG_ERROR("[PSync]:Invalid index for sid=%u", adv_sid); |
| return; |
| } |
| |
| if (periodic_sync->sync_state == PERIODIC_SYNC_STATE_PENDING) { |
| LOG_WARN("[PSync]: Sync state is pending"); |
| le_scanning_interface_->EnqueueCommand( |
| hci::LePeriodicAdvertisingCreateSyncCancelBuilder::Create(), |
| handler_->BindOnceOn(this, &PeriodicSyncManager::HandlePeriodicAdvertisingCreateSyncCancelStatus)); |
| } else if (periodic_sync->sync_state == PERIODIC_SYNC_STATE_IDLE) { |
| LOG_DEBUG("[PSync]: Removing Sync request from queue"); |
| CleanUpRequest(adv_sid, address); |
| } |
| periodic_syncs_.erase(periodic_sync); |
| } |
| |
| void TransferSync( |
| const Address& address, uint16_t service_data, uint16_t sync_handle, int pa_source, uint16_t connection_handle) { |
| if (periodic_sync_transfers_.size() >= kMaxSyncTransactions) { |
| int status = static_cast<int>(ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES); |
| callbacks_->OnPeriodicSyncTransferred(pa_source, status, address); |
| return; |
| } |
| |
| PeriodicSyncTransferStates request{pa_source, connection_handle, address}; |
| periodic_sync_transfers_.emplace_back(request); |
| le_scanning_interface_->EnqueueCommand( |
| hci::LePeriodicAdvertisingSyncTransferBuilder::Create(connection_handle, service_data, sync_handle), |
| handler_->BindOnceOn( |
| this, |
| &PeriodicSyncManager::HandlePeriodicAdvertisingSyncTransferComplete< |
| LePeriodicAdvertisingSyncTransferCompleteView>, |
| connection_handle)); |
| } |
| |
| void SyncSetInfo( |
| const Address& address, uint16_t service_data, uint8_t adv_handle, int pa_source, uint16_t connection_handle) { |
| if (periodic_sync_transfers_.size() >= kMaxSyncTransactions) { |
| int status = static_cast<int>(ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES); |
| callbacks_->OnPeriodicSyncTransferred(pa_source, status, address); |
| return; |
| } |
| PeriodicSyncTransferStates request{pa_source, connection_handle, address}; |
| periodic_sync_transfers_.emplace_back(request); |
| le_scanning_interface_->EnqueueCommand( |
| hci::LePeriodicAdvertisingSetInfoTransferBuilder::Create(connection_handle, service_data, adv_handle), |
| handler_->BindOnceOn( |
| this, |
| &PeriodicSyncManager::HandlePeriodicAdvertisingSyncTransferComplete< |
| LePeriodicAdvertisingSetInfoTransferCompleteView>, |
| connection_handle)); |
| } |
| |
| void SyncTxParameters(const Address& address, uint8_t mode, uint16_t skip, uint16_t timeout, int reg_id) { |
| LOG_DEBUG("[PAST]: mode=%u, skip=%u, timeout=%u", mode, skip, timeout); |
| auto sync_cte_type = static_cast<CteType>( |
| static_cast<uint8_t>(PeriodicSyncCteType::AVOID_AOA_CONSTANT_TONE_EXTENSION) | |
| static_cast<uint8_t>(PeriodicSyncCteType::AVOID_AOD_CONSTANT_TONE_EXTENSION_WITH_ONE_US_SLOTS) | |
| static_cast<uint8_t>(PeriodicSyncCteType::AVOID_AOD_CONSTANT_TONE_EXTENSION_WITH_TWO_US_SLOTS)); |
| sync_received_callback_registered_ = true; |
| sync_received_callback_id = reg_id; |
| |
| le_scanning_interface_->EnqueueCommand( |
| hci::LeSetDefaultPeriodicAdvertisingSyncTransferParametersBuilder::Create( |
| static_cast<SyncTransferMode>(mode), skip, timeout, sync_cte_type), |
| handler_->BindOnceOn( |
| this, |
| &PeriodicSyncManager::check_status<LeSetDefaultPeriodicAdvertisingSyncTransferParametersCompleteView>)); |
| } |
| |
| void HandlePeriodicAdvertisingCreateSyncStatus(CommandStatusView) {} |
| |
| void HandlePeriodicAdvertisingCreateSyncCancelStatus(CommandCompleteView) {} |
| |
| template <class View> |
| void HandlePeriodicAdvertisingSyncTransferComplete(uint16_t connection_handle, CommandCompleteView view) { |
| ASSERT(view.IsValid()); |
| auto status_view = View::Create(view); |
| ASSERT(status_view.IsValid()); |
| if (status_view.GetStatus() != ErrorCode::SUCCESS) { |
| LOG_WARN( |
| "Got a Command complete %s, status %s, connection_handle %d", |
| OpCodeText(view.GetCommandOpCode()).c_str(), |
| ErrorCodeText(status_view.GetStatus()).c_str(), |
| connection_handle); |
| } else { |
| LOG_DEBUG( |
| "Got a Command complete %s, status %s, connection_handle %d", |
| OpCodeText(view.GetCommandOpCode()).c_str(), |
| ErrorCodeText(status_view.GetStatus()).c_str(), |
| connection_handle); |
| } |
| |
| auto periodic_sync_transfer = GetSyncTransferRequestFromConnectionHandle(connection_handle); |
| if (periodic_sync_transfer == periodic_sync_transfers_.end()) { |
| LOG_ERROR("[PAST]:Invalid, conn_handle %u not found in DB", connection_handle); |
| return; |
| }; |
| |
| callbacks_->OnPeriodicSyncTransferred( |
| periodic_sync_transfer->pa_source, (uint16_t)status_view.GetStatus(), periodic_sync_transfer->addr); |
| periodic_sync_transfers_.erase(periodic_sync_transfer); |
| } |
| |
| template <class View> |
| void check_status(CommandCompleteView view) { |
| ASSERT(view.IsValid()); |
| auto status_view = View::Create(view); |
| ASSERT(status_view.IsValid()); |
| if (status_view.GetStatus() != ErrorCode::SUCCESS) { |
| LOG_WARN( |
| "Got a Command complete %s, status %s", |
| OpCodeText(view.GetCommandOpCode()).c_str(), |
| ErrorCodeText(status_view.GetStatus()).c_str()); |
| } else { |
| LOG_DEBUG( |
| "Got a Command complete %s, status %s", |
| OpCodeText(view.GetCommandOpCode()).c_str(), |
| ErrorCodeText(status_view.GetStatus()).c_str()); |
| } |
| } |
| |
| void HandleLePeriodicAdvertisingSyncEstablished(LePeriodicAdvertisingSyncEstablishedView event_view) { |
| ASSERT(event_view.IsValid()); |
| LOG_DEBUG( |
| "[PSync]: status=%d, sync_handle=%d, s_id=%d, " |
| "address_type=%d, adv_phy=%d,adv_interval=%d, clock_acc=%d", |
| (uint16_t)event_view.GetStatus(), |
| event_view.GetSyncHandle(), |
| event_view.GetAdvertisingSid(), |
| (uint16_t)event_view.GetAdvertiserAddressType(), |
| (uint16_t)event_view.GetAdvertiserPhy(), |
| event_view.GetPeriodicAdvertisingInterval(), |
| (uint16_t)event_view.GetAdvertiserClockAccuracy()); |
| |
| auto pending_sync_request = |
| GetPendingSyncFromAddressAndSid(event_view.GetAdvertiserAddress(), event_view.GetAdvertisingSid()); |
| if (pending_sync_request != pending_sync_requests_.end()) { |
| pending_sync_request->sync_timeout_alarm.Cancel(); |
| } |
| |
| auto address_with_type = AddressWithType(event_view.GetAdvertiserAddress(), event_view.GetAdvertiserAddressType()); |
| |
| auto temp_address_type = address_with_type.GetAddressType(); |
| // If the create sync command uses 0x01, Random or Random ID, the result can be 0x01, 0x02, or 0x03, |
| // because a Random Address, if it is an RPA, can be resolved to either Public Identity or Random Identity. |
| if (temp_address_type != AddressType::PUBLIC_DEVICE_ADDRESS) { |
| temp_address_type = AddressType::RANDOM_DEVICE_ADDRESS; |
| } |
| auto periodic_sync = GetSyncFromAddressWithTypeAndSid( |
| AddressWithType(event_view.GetAdvertiserAddress(), temp_address_type), event_view.GetAdvertisingSid()); |
| if (periodic_sync == periodic_syncs_.end()) { |
| LOG_WARN("[PSync]: Invalid address and sid for sync established"); |
| if (event_view.GetStatus() == ErrorCode::SUCCESS) { |
| LOG_WARN("Terminate sync"); |
| le_scanning_interface_->EnqueueCommand( |
| hci::LePeriodicAdvertisingTerminateSyncBuilder::Create(event_view.GetSyncHandle()), |
| handler_->BindOnceOn( |
| this, &PeriodicSyncManager::check_status<LePeriodicAdvertisingTerminateSyncCompleteView>)); |
| } |
| AdvanceRequest(); |
| return; |
| } |
| periodic_sync->sync_handle = event_view.GetSyncHandle(); |
| periodic_sync->sync_state = PERIODIC_SYNC_STATE_ESTABLISHED; |
| callbacks_->OnPeriodicSyncStarted( |
| periodic_sync->request_id, |
| (uint8_t)event_view.GetStatus(), |
| event_view.GetSyncHandle(), |
| event_view.GetAdvertisingSid(), |
| address_with_type, |
| (uint16_t)event_view.GetAdvertiserPhy(), |
| event_view.GetPeriodicAdvertisingInterval()); |
| AdvanceRequest(); |
| } |
| |
| void HandleLePeriodicAdvertisingReport(LePeriodicAdvertisingReportView event_view) { |
| ASSERT(event_view.IsValid()); |
| LOG_DEBUG( |
| "[PSync]: sync_handle = %u, tx_power = %d, rssi = %d," |
| "cte_type = %u, data_status = %u, data_len = %u", |
| event_view.GetSyncHandle(), |
| event_view.GetTxPower(), |
| event_view.GetRssi(), |
| (uint16_t)event_view.GetCteType(), |
| (uint16_t)event_view.GetDataStatus(), |
| (uint16_t)event_view.GetData().size()); |
| |
| uint16_t sync_handle = event_view.GetSyncHandle(); |
| auto periodic_sync = GetEstablishedSyncFromHandle(sync_handle); |
| if (periodic_sync == periodic_syncs_.end()) { |
| LOG_ERROR("[PSync]: index not found for handle %u", sync_handle); |
| return; |
| } |
| LOG_DEBUG("%s", "[PSync]: invoking callback"); |
| callbacks_->OnPeriodicSyncReport( |
| sync_handle, |
| event_view.GetTxPower(), |
| event_view.GetRssi(), |
| (uint16_t)event_view.GetDataStatus(), |
| event_view.GetData()); |
| } |
| |
| void HandleLePeriodicAdvertisingSyncLost(LePeriodicAdvertisingSyncLostView event_view) { |
| ASSERT(event_view.IsValid()); |
| uint16_t sync_handle = event_view.GetSyncHandle(); |
| LOG_DEBUG("[PSync]: sync_handle = %d", sync_handle); |
| callbacks_->OnPeriodicSyncLost(sync_handle); |
| auto periodic_sync = GetEstablishedSyncFromHandle(sync_handle); |
| periodic_syncs_.erase(periodic_sync); |
| } |
| |
| void HandleLePeriodicAdvertisingSyncTransferReceived(LePeriodicAdvertisingSyncTransferReceivedView event_view) { |
| ASSERT(event_view.IsValid()); |
| uint8_t status = (uint8_t)event_view.GetStatus(); |
| uint8_t advertiser_phy = (uint8_t)event_view.GetAdvertiserPhy(); |
| LOG_DEBUG( |
| "[PAST]: status = %u, connection_handle = %u, service_data = %u," |
| " sync_handle = %u, adv_sid = %u, address_type = %u, address = %s," |
| " advertiser_phy = %u, periodic_advertising_interval = %u, clock_accuracy = %u", |
| status, |
| event_view.GetConnectionHandle(), |
| event_view.GetServiceData(), |
| event_view.GetSyncHandle(), |
| event_view.GetAdvertisingSid(), |
| (uint8_t)event_view.GetAdvertiserAddressType(), |
| event_view.GetAdvertiserAddress().ToString().c_str(), |
| advertiser_phy, |
| event_view.GetPeriodicAdvertisingInterval(), |
| (uint8_t)event_view.GetAdvertiserClockAccuracy()); |
| if (sync_received_callback_registered_) { |
| callbacks_->OnPeriodicSyncStarted( |
| sync_received_callback_id, |
| status, |
| event_view.GetSyncHandle(), |
| event_view.GetAdvertisingSid(), |
| AddressWithType(event_view.GetAdvertiserAddress(), event_view.GetAdvertiserAddressType()), |
| advertiser_phy, |
| event_view.GetPeriodicAdvertisingInterval()); |
| } |
| } |
| |
| void OnStartSyncTimeout() { |
| auto& request = pending_sync_requests_.front(); |
| LOG_WARN( |
| "%s: sync timeout SID=%04X, bd_addr=%s", |
| __func__, |
| request.advertiser_sid, |
| request.address_with_type.ToString().c_str()); |
| uint8_t adv_sid = request.advertiser_sid; |
| AddressWithType address_with_type = request.address_with_type; |
| auto sync = GetSyncFromAddressWithTypeAndSid(address_with_type, adv_sid); |
| le_scanning_interface_->EnqueueCommand( |
| hci::LePeriodicAdvertisingCreateSyncCancelBuilder::Create(), |
| handler_->BindOnceOn(this, &PeriodicSyncManager::HandlePeriodicAdvertisingCreateSyncCancelStatus)); |
| int status = static_cast<int>(ErrorCode::ADVERTISING_TIMEOUT); |
| callbacks_->OnPeriodicSyncStarted( |
| sync->request_id, status, 0, sync->advertiser_sid, request.address_with_type, 0, 0); |
| RemoveSyncRequest(sync); |
| } |
| |
| private: |
| std::list<PeriodicSyncStates>::iterator GetEstablishedSyncFromHandle(uint16_t handle) { |
| for (auto it = periodic_syncs_.begin(); it != periodic_syncs_.end(); it++) { |
| if (it->sync_handle == handle && it->sync_state == PeriodicSyncState::PERIODIC_SYNC_STATE_ESTABLISHED) { |
| return it; |
| } |
| } |
| return periodic_syncs_.end(); |
| } |
| |
| std::list<PeriodicSyncStates>::iterator GetSyncFromAddressWithTypeAndSid( |
| const AddressWithType& address_with_type, uint8_t adv_sid) { |
| for (auto it = periodic_syncs_.begin(); it != periodic_syncs_.end(); it++) { |
| if (it->advertiser_sid == adv_sid && it->address_with_type == address_with_type) { |
| return it; |
| } |
| } |
| return periodic_syncs_.end(); |
| } |
| |
| std::list<PeriodicSyncStates>::iterator GetSyncFromAddressAndSid(const Address& address, uint8_t adv_sid) { |
| for (auto it = periodic_syncs_.begin(); it != periodic_syncs_.end(); it++) { |
| if (it->advertiser_sid == adv_sid && it->address_with_type.GetAddress() == address) { |
| return it; |
| } |
| } |
| return periodic_syncs_.end(); |
| } |
| |
| std::list<PendingPeriodicSyncRequest>::iterator GetPendingSyncFromAddressAndSid( |
| const Address& address, uint8_t adv_sid) { |
| for (auto it = pending_sync_requests_.begin(); it != pending_sync_requests_.end(); it++) { |
| if (it->advertiser_sid == adv_sid && it->address_with_type.GetAddress() == address) { |
| return it; |
| } |
| } |
| return pending_sync_requests_.end(); |
| } |
| |
| void RemoveSyncRequest(std::list<PeriodicSyncStates>::iterator it) { |
| periodic_syncs_.erase(it); |
| } |
| |
| std::list<PeriodicSyncTransferStates>::iterator GetSyncTransferRequestFromConnectionHandle( |
| uint16_t connection_handle) { |
| for (auto it = periodic_sync_transfers_.begin(); it != periodic_sync_transfers_.end(); it++) { |
| if (it->connection_handle == connection_handle) { |
| return it; |
| } |
| } |
| return periodic_sync_transfers_.end(); |
| } |
| |
| void HandleStartSyncRequest(uint8_t sid, const AddressWithType& address_with_type, uint16_t skip, uint16_t timeout) { |
| auto options = static_cast<PeriodicAdvertisingOptions>(0); |
| auto sync_cte_type = static_cast<PeriodicSyncCteType>( |
| static_cast<uint8_t>(PeriodicSyncCteType::AVOID_AOA_CONSTANT_TONE_EXTENSION) | |
| static_cast<uint8_t>(PeriodicSyncCteType::AVOID_AOD_CONSTANT_TONE_EXTENSION_WITH_ONE_US_SLOTS) | |
| static_cast<uint8_t>(PeriodicSyncCteType::AVOID_AOD_CONSTANT_TONE_EXTENSION_WITH_TWO_US_SLOTS)); |
| auto sync = GetSyncFromAddressWithTypeAndSid(address_with_type, sid); |
| sync->sync_state = PERIODIC_SYNC_STATE_PENDING; |
| AdvertisingAddressType advertisingAddressType = |
| static_cast<AdvertisingAddressType>(address_with_type.GetAddressType()); |
| le_scanning_interface_->EnqueueCommand( |
| hci::LePeriodicAdvertisingCreateSyncBuilder::Create( |
| options, sid, advertisingAddressType, address_with_type.GetAddress(), skip, timeout, sync_cte_type), |
| handler_->BindOnceOn(this, &PeriodicSyncManager::HandlePeriodicAdvertisingCreateSyncStatus)); |
| } |
| |
| void HandleNextRequest() { |
| if (pending_sync_requests_.empty()) { |
| LOG_DEBUG("pending_sync_requests_ empty"); |
| return; |
| } |
| auto& request = pending_sync_requests_.front(); |
| LOG_INFO( |
| "executing sync request SID=%04X, bd_addr=%s", |
| request.advertiser_sid, |
| request.address_with_type.ToString().c_str()); |
| if (request.busy) { |
| LOG_INFO("Request is already busy"); |
| return; |
| } |
| request.busy = true; |
| request.sync_timeout_alarm.Cancel(); |
| HandleStartSyncRequest(request.advertiser_sid, request.address_with_type, request.skip, request.sync_timeout); |
| request.sync_timeout_alarm.Schedule( |
| base::BindOnce(&PeriodicSyncManager::OnStartSyncTimeout, base::Unretained(this)), kPeriodicSyncTimeout); |
| } |
| |
| void AdvanceRequest() { |
| LOG_DEBUG("AdvanceRequest"); |
| if (pending_sync_requests_.empty()) { |
| LOG_DEBUG("pending_sync_requests_ empty"); |
| return; |
| } |
| auto it = pending_sync_requests_.begin(); |
| pending_sync_requests_.erase(it); |
| HandleNextRequest(); |
| } |
| |
| void CleanUpRequest(uint8_t advertiser_sid, Address address) { |
| auto it = pending_sync_requests_.begin(); |
| while (it != pending_sync_requests_.end()) { |
| if (it->advertiser_sid == advertiser_sid && it->address_with_type.GetAddress() == address) { |
| LOG_INFO( |
| "removing connection request SID=%04X, bd_addr=%s, busy=%d", |
| it->advertiser_sid, |
| it->address_with_type.GetAddress().ToString().c_str(), |
| it->busy); |
| it = pending_sync_requests_.erase(it); |
| } else { |
| ++it; |
| } |
| } |
| } |
| |
| hci::LeScanningInterface* le_scanning_interface_; |
| os::Handler* handler_; |
| ScanningCallback* callbacks_; |
| std::list<PendingPeriodicSyncRequest> pending_sync_requests_; |
| std::list<PeriodicSyncStates> periodic_syncs_; |
| std::list<PeriodicSyncTransferStates> periodic_sync_transfers_; |
| bool sync_received_callback_registered_ = false; |
| int sync_received_callback_id{}; |
| }; |
| |
| } // namespace hci |
| } // namespace bluetooth |