/* * Copyright 2019 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 "hci/le_scanning_manager.h" #include #include #include #include #include "hci/acl_manager.h" #include "hci/controller.h" #include "hci/event_checkers.h" #include "hci/hci_layer.h" #include "hci/hci_packets.h" #include "hci/le_periodic_sync_manager.h" #include "hci/le_scanning_interface.h" #include "hci/le_scanning_reassembler.h" #include "module.h" #include "os/handler.h" #include "os/log.h" #include "os/system_properties.h" #include "storage/storage_module.h" namespace bluetooth { namespace hci { constexpr uint16_t kLeScanWindowMin = 0x0004; constexpr uint16_t kLeScanWindowMax = 0x4000; constexpr int64_t kLeScanRssiMin = -127; constexpr int64_t kLeScanRssiMax = 20; constexpr int64_t kLeScanRssiUnknown = 127; constexpr int64_t kLeRxPathLossCompMin = -128; constexpr int64_t kLeRxPathLossCompMax = 127; constexpr uint16_t kDefaultLeExtendedScanWindow = 4800; constexpr uint16_t kLeExtendedScanWindowMax = 0xFFFF; constexpr uint16_t kLeScanIntervalMin = 0x0004; constexpr uint16_t kLeScanIntervalMax = 0x4000; constexpr uint16_t kDefaultLeExtendedScanInterval = 4800; constexpr uint16_t kLeExtendedScanIntervalMax = 0xFFFF; constexpr uint8_t kScannableBit = 1; constexpr uint8_t kDirectedBit = 2; constexpr uint8_t kScanResponseBit = 3; constexpr uint8_t kLegacyBit = 4; constexpr uint8_t kDataStatusBits = 5; // system properties const std::string kLeRxPathLossCompProperty = "bluetooth.hardware.radio.le_rx_path_loss_comp_db"; const ModuleFactory LeScanningManager::Factory = ModuleFactory([]() { return new LeScanningManager(); }); enum class ScanApiType { LEGACY = 1, ANDROID_HCI = 2, EXTENDED = 3, }; struct Scanner { Uuid app_uuid; bool in_use; }; class NullScanningCallback : public ScanningCallback { void OnScannerRegistered( const Uuid /* app_uuid */, ScannerId /* scanner_id */, ScanningStatus /* status */) override { log::info("OnScannerRegistered in NullScanningCallback"); } void OnSetScannerParameterComplete( ScannerId /* scanner_id */, ScanningStatus /* status */) override { log::info("OnSetScannerParameterComplete in NullScanningCallback"); } void OnScanResult( uint16_t /* event_type */, uint8_t /* address_type */, Address /* address */, uint8_t /* primary_phy */, uint8_t /* secondary_phy */, uint8_t /* advertising_sid */, int8_t /* tx_power */, int8_t /* rssi */, uint16_t /* periodic_advertising_interval */, std::vector /* advertising_data */) override { log::info("OnScanResult in NullScanningCallback"); } void OnTrackAdvFoundLost( AdvertisingFilterOnFoundOnLostInfo /* on_found_on_lost_info */) override { log::info("OnTrackAdvFoundLost in NullScanningCallback"); } void OnBatchScanReports( int /* client_if */, int /* status */, int /* report_format */, int /* num_records */, std::vector /* data */) override { log::info("OnBatchScanReports in NullScanningCallback"); } void OnBatchScanThresholdCrossed(int /* client_if */) override { log::info("OnBatchScanThresholdCrossed in NullScanningCallback"); } void OnTimeout() override { log::info("OnTimeout in NullScanningCallback"); } void OnFilterEnable(Enable /* enable */, uint8_t /* status */) override { log::info("OnFilterEnable in NullScanningCallback"); } void OnFilterParamSetup( uint8_t /* available_spaces */, ApcfAction /* action */, uint8_t /* status */) override { log::info("OnFilterParamSetup in NullScanningCallback"); } void OnFilterConfigCallback( ApcfFilterType /* filter_type */, uint8_t /* available_spaces */, ApcfAction /* action */, uint8_t /* status */) override { log::info("OnFilterConfigCallback in NullScanningCallback"); } void OnPeriodicSyncStarted( int /* reg_id */, uint8_t /* status */, uint16_t /* sync_handle */, uint8_t /* advertising_sid */, AddressWithType /* address_with_type */, uint8_t /* phy */, uint16_t /* interval */) override { log::info("OnPeriodicSyncStarted in NullScanningCallback"); }; void OnPeriodicSyncReport( uint16_t /* sync_handle */, int8_t /* tx_power */, int8_t /* rssi */, uint8_t /* status */, std::vector /* data */) override { log::info("OnPeriodicSyncReport in NullScanningCallback"); }; void OnPeriodicSyncLost(uint16_t /* sync_handle */) override { log::info("OnPeriodicSyncLost in NullScanningCallback"); }; void OnPeriodicSyncTransferred( int /* pa_source */, uint8_t /* status */, Address /* address */) override { log::info("OnPeriodicSyncTransferred in NullScanningCallback"); }; void OnBigInfoReport(uint16_t /* sync_handle */, bool /* encrypted */) { log::info("OnBigInfoReport in NullScanningCallback"); }; }; enum class BatchScanState { ERROR_STATE = 0, ENABLE_CALLED = 1, ENABLED_STATE = 2, DISABLE_CALLED = 3, DISABLED_STATE = 4, }; #define BTM_BLE_BATCH_SCAN_MODE_DISABLE 0 #define BTM_BLE_BATCH_SCAN_MODE_PASS 1 #define BTM_BLE_BATCH_SCAN_MODE_ACTI 2 #define BTM_BLE_BATCH_SCAN_MODE_PASS_ACTI 3 struct BatchScanConfig { BatchScanState current_state; BatchScanMode scan_mode; uint32_t scan_interval; uint32_t scan_window; BatchScanDiscardRule discard_rule; ScannerId ref_value; }; struct LeScanningManager::impl : public LeAddressManagerCallback { impl(Module* module) : module_(module), le_scanning_interface_(nullptr) {} ~impl() { if (address_manager_registered_) { le_address_manager_->Unregister(this); } } void start( os::Handler* handler, HciLayer* hci_layer, Controller* controller, AclManager* acl_manager, storage::StorageModule* storage_module) { module_handler_ = handler; hci_layer_ = hci_layer; controller_ = controller; acl_manager_ = acl_manager; storage_module_ = storage_module; le_address_manager_ = acl_manager->GetLeAddressManager(); le_scanning_interface_ = hci_layer_->GetLeScanningInterface( module_handler_->BindOn(this, &LeScanningManager::impl::handle_scan_results)); periodic_sync_manager_.Init(le_scanning_interface_, module_handler_); /* Check to see if the opcode is supported and C19 (support for extended advertising). */ if (controller_->IsSupported(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS) && controller->SupportsBleExtendedAdvertising()) { api_type_ = ScanApiType::EXTENDED; interval_ms_ = kDefaultLeExtendedScanInterval; window_ms_ = kDefaultLeExtendedScanWindow; phy_ = static_cast(PhyType::LE_1M); } else if (controller_->IsSupported(OpCode::LE_EXTENDED_SCAN_PARAMS)) { api_type_ = ScanApiType::ANDROID_HCI; } else { api_type_ = ScanApiType::LEGACY; } is_filter_supported_ = controller_->IsSupported(OpCode::LE_ADV_FILTER); if (is_filter_supported_) { le_scanning_interface_->EnqueueCommand( LeAdvFilterReadExtendedFeaturesBuilder::Create(), module_handler_->BindOnceOn(this, &impl::on_apcf_read_extended_features_complete)); } is_batch_scan_supported_ = controller->IsSupported(OpCode::LE_BATCH_SCAN); is_periodic_advertising_sync_transfer_sender_supported_ = controller_->SupportsBlePeriodicAdvertisingSyncTransferSender(); total_num_of_advt_tracked_ = controller->GetVendorCapabilities().total_num_of_advt_tracked_; if (is_batch_scan_supported_) { hci_layer_->RegisterVendorSpecificEventHandler( VseSubeventCode::BLE_THRESHOLD, handler->BindOn(this, &LeScanningManager::impl::on_storage_threshold_breach)); hci_layer_->RegisterVendorSpecificEventHandler( VseSubeventCode::BLE_TRACKING, handler->BindOn(this, &LeScanningManager::impl::on_advertisement_tracking)); } scanners_ = std::vector(kMaxAppNum + 1); for (size_t i = 0; i < scanners_.size(); i++) { scanners_[i].app_uuid = Uuid::kEmpty; scanners_[i].in_use = false; } batch_scan_config_.current_state = BatchScanState::DISABLED_STATE; batch_scan_config_.ref_value = kInvalidScannerId; le_rx_path_loss_comp_ = get_rx_path_loss_compensation(); } void stop() { for (auto subevent_code : LeScanningEvents) { hci_layer_->UnregisterLeEventHandler(subevent_code); } if (is_batch_scan_supported_) { // TODO implete vse module // hci_layer_->UnregisterVesEventHandler(VseSubeventCode::BLE_THRESHOLD); // hci_layer_->UnregisterVesEventHandler(VseSubeventCode::BLE_TRACKING); } batch_scan_config_.current_state = BatchScanState::DISABLED_STATE; batch_scan_config_.ref_value = kInvalidScannerId; scanning_callbacks_ = &null_scanning_callback_; periodic_sync_manager_.SetScanningCallback(scanning_callbacks_); } void handle_scan_results(LeMetaEventView event) { switch (event.GetSubeventCode()) { case SubeventCode::ADVERTISING_REPORT: handle_advertising_report(LeAdvertisingReportRawView::Create(event)); break; case SubeventCode::DIRECTED_ADVERTISING_REPORT: handle_directed_advertising_report(LeDirectedAdvertisingReportView::Create(event)); break; case SubeventCode::EXTENDED_ADVERTISING_REPORT: handle_extended_advertising_report(LeExtendedAdvertisingReportRawView::Create(event)); break; case SubeventCode::PERIODIC_ADVERTISING_SYNC_ESTABLISHED: LePeriodicAdvertisingSyncEstablishedView::Create(event); periodic_sync_manager_.HandleLePeriodicAdvertisingSyncEstablished( LePeriodicAdvertisingSyncEstablishedView::Create(event)); break; case SubeventCode::PERIODIC_ADVERTISING_REPORT: periodic_sync_manager_.HandleLePeriodicAdvertisingReport(LePeriodicAdvertisingReportView::Create(event)); break; case SubeventCode::PERIODIC_ADVERTISING_SYNC_LOST: periodic_sync_manager_.HandleLePeriodicAdvertisingSyncLost(LePeriodicAdvertisingSyncLostView::Create(event)); break; case SubeventCode::PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED: periodic_sync_manager_.HandleLePeriodicAdvertisingSyncTransferReceived( LePeriodicAdvertisingSyncTransferReceivedView::Create(event)); break; case SubeventCode::SCAN_TIMEOUT: scanning_callbacks_->OnTimeout(); break; case SubeventCode::BIG_INFO_ADVERTISING_REPORT: periodic_sync_manager_.HandleLeBigInfoAdvertisingReport( LeBigInfoAdvertisingReportView::Create(event)); break; default: log::fatal("Unknown advertising subevent {}", SubeventCodeText(event.GetSubeventCode())); } } struct ExtendedEventTypeOptions { bool connectable{false}; bool scannable{false}; bool directed{false}; bool scan_response{false}; bool legacy{false}; bool continuing{false}; bool truncated{false}; }; int8_t get_rx_path_loss_compensation() { int8_t compensation = 0; auto compensation_prop = os::GetSystemProperty(kLeRxPathLossCompProperty); if (compensation_prop) { auto compensation_number = common::Int64FromString(compensation_prop.value()); if (compensation_number) { int64_t number = compensation_number.value(); if (number < kLeRxPathLossCompMin || number > kLeRxPathLossCompMax) { log::error("Invalid number for rx path loss compensation: {}", number); } else { compensation = number; } } } log::info("Rx path loss compensation: {}", compensation); return compensation; } int8_t get_rssi_after_calibration(int8_t rssi) { if (le_rx_path_loss_comp_ == 0 || rssi == kLeScanRssiUnknown) { return rssi; } int8_t calibrated_rssi = rssi; int64_t number = rssi + le_rx_path_loss_comp_; if (number < kLeScanRssiMin || number > kLeScanRssiMax) { log::error("Invalid number for calibrated rssi: {}", number); } else { calibrated_rssi = number; } return calibrated_rssi; } uint16_t transform_to_extended_event_type(ExtendedEventTypeOptions o) { return (o.connectable ? 0x0001 << 0 : 0) | (o.scannable ? 0x0001 << 1 : 0) | (o.directed ? 0x0001 << 2 : 0) | (o.scan_response ? 0x0001 << 3 : 0) | (o.legacy ? 0x0001 << 4 : 0) | (o.continuing ? 0x0001 << 5 : 0) | (o.truncated ? 0x0001 << 6 : 0); } void handle_advertising_report(LeAdvertisingReportRawView event_view) { if (!event_view.IsValid()) { log::info("Dropping invalid advertising event"); return; } std::vector reports = event_view.GetResponses(); if (reports.empty()) { log::info("Zero results in advertising event"); return; } for (LeAdvertisingResponseRaw report : reports) { uint16_t extended_event_type = 0; switch (report.event_type_) { case AdvertisingEventType::ADV_IND: extended_event_type = transform_to_extended_event_type( {.connectable = true, .scannable = true, .legacy = true}); break; case AdvertisingEventType::ADV_DIRECT_IND: extended_event_type = transform_to_extended_event_type( {.connectable = true, .directed = true, .legacy = true}); break; case AdvertisingEventType::ADV_SCAN_IND: extended_event_type = transform_to_extended_event_type({.scannable = true, .legacy = true}); break; case AdvertisingEventType::ADV_NONCONN_IND: extended_event_type = transform_to_extended_event_type({.legacy = true}); break; case AdvertisingEventType::SCAN_RESPONSE: if (com::android::bluetooth::flags::fix_nonconnectable_scannable_advertisement()) { // We don't know if the initial advertising report was connectable or not. // LeScanningReassembler fixes the connectable field. extended_event_type = transform_to_extended_event_type( {.scannable = true, .scan_response = true, .legacy = true}); } else { extended_event_type = transform_to_extended_event_type( {.connectable = true, .scannable = true, .scan_response = true, .legacy = true}); } break; default: log::warn("Unsupported event type:{}", (uint16_t)report.event_type_); return; } process_advertising_package_content( extended_event_type, (uint8_t)report.address_type_, report.address_, (uint8_t)PrimaryPhyType::LE_1M, (uint8_t)SecondaryPhyType::NO_PACKETS, kAdvertisingDataInfoNotPresent, kTxPowerInformationNotPresent, report.rssi_, kNotPeriodicAdvertisement, report.advertising_data_); } } void handle_directed_advertising_report(LeDirectedAdvertisingReportView /*event_view*/) { log::warn("HCI Directed Advertising Report events are not supported"); } void handle_extended_advertising_report(LeExtendedAdvertisingReportRawView event_view) { if (!event_view.IsValid()) { log::info("Dropping invalid advertising event"); return; } std::vector reports = event_view.GetResponses(); if (reports.empty()) { log::info("Zero results in advertising event"); return; } for (LeExtendedAdvertisingResponseRaw& report : reports) { uint16_t event_type = report.connectable_ | (report.scannable_ << kScannableBit) | (report.directed_ << kDirectedBit) | (report.scan_response_ << kScanResponseBit) | (report.legacy_ << kLegacyBit) | ((uint16_t)report.data_status_ << kDataStatusBits); process_advertising_package_content( event_type, (uint8_t)report.address_type_, report.address_, (uint8_t)report.primary_phy_, (uint8_t)report.secondary_phy_, report.advertising_sid_, report.tx_power_, report.rssi_, report.periodic_advertising_interval_, report.advertising_data_); } } void process_advertising_package_content( uint16_t event_type, uint8_t address_type, Address address, uint8_t primary_phy, uint8_t secondary_phy, uint8_t advertising_sid, int8_t tx_power, int8_t rssi, uint16_t periodic_advertising_interval, const std::vector& advertising_data) { // When using the vendor command Le Set Extended Params to // configure a filter accept list based e.g. on the service UUIDs // found in the report, we ignore the scan responses as we cannot be // certain that they will not be dropped by the filter. // TODO(b/275754998): Improve the decision on what to do with scan responses: Only when used // with hardware-filtering features should we ignore waiting for scan response, and make sure // scan responses are still reported too. scanning_reassembler_.SetIgnoreScanResponses( le_scan_type_ == LeScanType::PASSIVE || filter_policy_ == LeScanningFilterPolicy::FILTER_ACCEPT_LIST_ONLY); std::optional processed_report = scanning_reassembler_.ProcessAdvertisingReport( event_type, address_type, address, advertising_sid, advertising_data); if (processed_report.has_value()) { switch (address_type) { case (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS: case (uint8_t)AddressType::PUBLIC_IDENTITY_ADDRESS: address_type = (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS; break; case (uint8_t)AddressType::RANDOM_DEVICE_ADDRESS: case (uint8_t)AddressType::RANDOM_IDENTITY_ADDRESS: address_type = (uint8_t)AddressType::RANDOM_DEVICE_ADDRESS; break; } const uint16_t result_event_type = com::android::bluetooth::flags::fix_nonconnectable_scannable_advertisement() ? processed_report->extended_event_type : event_type; scanning_callbacks_->OnScanResult( result_event_type, address_type, address, primary_phy, secondary_phy, advertising_sid, tx_power, get_rssi_after_calibration(rssi), periodic_advertising_interval, std::move(processed_report->data)); } } void configure_scan() { std::vector parameter_vector; for (int i = 0; i < 7; i++) { if ((phy_ & 1 << i) != 0) { PhyScanParameters phy_scan_parameters; phy_scan_parameters.le_scan_window_ = window_ms_; phy_scan_parameters.le_scan_interval_ = interval_ms_; phy_scan_parameters.le_scan_type_ = le_scan_type_; parameter_vector.push_back(phy_scan_parameters); } } uint8_t phys_in_use = phy_; // The Host shall not issue set scan parameter command when scanning is enabled stop_scan(); if (le_address_manager_->GetAddressPolicy() != LeAddressManager::USE_PUBLIC_ADDRESS) { own_address_type_ = OwnAddressType::RANDOM_DEVICE_ADDRESS; } else { own_address_type_ = OwnAddressType::PUBLIC_DEVICE_ADDRESS; } switch (api_type_) { case ScanApiType::EXTENDED: le_scanning_interface_->EnqueueCommand( LeSetExtendedScanParametersBuilder::Create( own_address_type_, filter_policy_, phys_in_use, parameter_vector), module_handler_->BindOnceOn(this, &impl::on_set_scan_parameter_complete)); break; case ScanApiType::ANDROID_HCI: le_scanning_interface_->EnqueueCommand( LeExtendedScanParamsBuilder::Create( le_scan_type_, interval_ms_, window_ms_, own_address_type_, filter_policy_), module_handler_->BindOnceOn(this, &impl::on_set_scan_parameter_complete)); break; case ScanApiType::LEGACY: le_scanning_interface_->EnqueueCommand( LeSetScanParametersBuilder::Create( le_scan_type_, interval_ms_, window_ms_, own_address_type_, filter_policy_), module_handler_->BindOnceOn(this, &impl::on_set_scan_parameter_complete)); break; } } void register_scanner(const Uuid app_uuid) { for (uint8_t i = 1; i <= kMaxAppNum; i++) { if (scanners_[i].in_use && scanners_[i].app_uuid == app_uuid) { log::error("Application already registered {}", app_uuid.ToString()); scanning_callbacks_->OnScannerRegistered(app_uuid, 0x00, ScanningCallback::ScanningStatus::INTERNAL_ERROR); return; } } // valid value of scanner id : 1 ~ kMaxAppNum for (uint8_t i = 1; i <= kMaxAppNum; i++) { if (!scanners_[i].in_use) { scanners_[i].app_uuid = app_uuid; scanners_[i].in_use = true; scanning_callbacks_->OnScannerRegistered(app_uuid, i, ScanningCallback::ScanningStatus::SUCCESS); return; } } log::error("Unable to register scanner, max client reached:{}", kMaxAppNum); scanning_callbacks_->OnScannerRegistered(app_uuid, 0x00, ScanningCallback::ScanningStatus::NO_RESOURCES); } void unregister_scanner(ScannerId scanner_id) { if (scanner_id <= 0 || scanner_id > kMaxAppNum) { log::warn("Invalid scanner id"); return; } if (scanners_[scanner_id].in_use) { scanners_[scanner_id].in_use = false; scanners_[scanner_id].app_uuid = Uuid::kEmpty; log::debug("Unregister scanner successful, scannerId={}", scanner_id); } else { log::warn("Unregister scanner with unused scanner id"); } } void scan(bool start) { // On-resume flag should always be reset if there is an explicit start/stop call. scan_on_resume_ = false; if (start) { configure_scan(); start_scan(); } else { if (address_manager_registered_) { le_address_manager_->Unregister(this); address_manager_registered_ = false; paused_ = false; } stop_scan(); } } void start_scan() { // If we receive start_scan during paused, set scan_on_resume_ to true if (paused_ && address_manager_registered_) { scan_on_resume_ = true; return; } is_scanning_ = true; if (!address_manager_registered_) { le_address_manager_->Register(this); address_manager_registered_ = true; } switch (api_type_) { case ScanApiType::EXTENDED: le_scanning_interface_->EnqueueCommand( LeSetExtendedScanEnableBuilder::Create( Enable::ENABLED, #if TARGET_FLOSS FilterDuplicates::ENABLED /* filter duplicates */, #else FilterDuplicates::DISABLED /* filter duplicates */, #endif 0, 0), module_handler_->BindOnce(check_complete)); break; case ScanApiType::ANDROID_HCI: case ScanApiType::LEGACY: le_scanning_interface_->EnqueueCommand( LeSetScanEnableBuilder::Create( Enable::ENABLED, Enable::DISABLED /* filter duplicates */), module_handler_->BindOnce(check_complete)); break; } } void stop_scan() { if (!is_scanning_) { log::info("Scanning already stopped, return!"); return; } is_scanning_ = false; switch (api_type_) { case ScanApiType::EXTENDED: le_scanning_interface_->EnqueueCommand( LeSetExtendedScanEnableBuilder::Create( Enable::DISABLED, #if TARGET_FLOSS FilterDuplicates::ENABLED /* filter duplicates */, #else FilterDuplicates::DISABLED /* filter duplicates */, #endif 0, 0), module_handler_->BindOnce(check_complete)); break; case ScanApiType::ANDROID_HCI: case ScanApiType::LEGACY: le_scanning_interface_->EnqueueCommand( LeSetScanEnableBuilder::Create( Enable::DISABLED, Enable::DISABLED /* filter duplicates */), module_handler_->BindOnce(check_complete)); break; } } void set_scan_parameters( ScannerId scanner_id, LeScanType scan_type, uint16_t scan_interval, uint16_t scan_window, uint8_t scan_phy) { uint32_t max_scan_interval = kLeScanIntervalMax; uint32_t max_scan_window = kLeScanWindowMax; if (api_type_ == ScanApiType::EXTENDED) { max_scan_interval = kLeExtendedScanIntervalMax; max_scan_window = kLeExtendedScanWindowMax; } if (scan_type != LeScanType::ACTIVE && scan_type != LeScanType::PASSIVE) { log::error("Invalid scan type"); scanning_callbacks_->OnSetScannerParameterComplete( scanner_id, ScanningCallback::ScanningStatus::ILLEGAL_PARAMETER); return; } if (scan_interval > max_scan_interval || scan_interval < kLeScanIntervalMin) { log::error("Invalid scan_interval {}", scan_interval); scanning_callbacks_->OnSetScannerParameterComplete( scanner_id, ScanningCallback::ScanningStatus::ILLEGAL_PARAMETER); return; } if (scan_window > max_scan_window || scan_window < kLeScanWindowMin) { log::error("Invalid scan_window {}", scan_window); scanning_callbacks_->OnSetScannerParameterComplete( scanner_id, ScanningCallback::ScanningStatus::ILLEGAL_PARAMETER); return; } le_scan_type_ = scan_type; interval_ms_ = scan_interval; window_ms_ = scan_window; if (com::android::bluetooth::flags::phy_to_native()) phy_ = scan_phy; scanning_callbacks_->OnSetScannerParameterComplete(scanner_id, ScanningCallback::SUCCESS); } void set_scan_filter_policy(LeScanningFilterPolicy filter_policy) { filter_policy_ = filter_policy; } void scan_filter_enable(bool enable) { if (!is_filter_supported_) { log::warn("Advertising filter is not supported"); return; } Enable apcf_enable = enable ? Enable::ENABLED : Enable::DISABLED; le_scanning_interface_->EnqueueCommand( LeAdvFilterEnableBuilder::Create(apcf_enable), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); } bool is_bonded(Address target_address) { for (auto device : storage_module_->GetBondedDevices()) { if (device.GetAddress() == target_address) { log::debug("Addresses match!"); return true; } } log::debug("Addresse DON'Ts match!"); return false; } void scan_filter_parameter_setup( ApcfAction action, uint8_t filter_index, AdvertisingFilterParameter advertising_filter_parameter) { if (!is_filter_supported_) { log::warn("Advertising filter is not supported"); return; } auto entry = remove_me_later_map_.find(filter_index); switch (action) { case ApcfAction::ADD: le_scanning_interface_->EnqueueCommand( LeAdvFilterAddFilteringParametersBuilder::Create( filter_index, advertising_filter_parameter.feature_selection, advertising_filter_parameter.list_logic_type, advertising_filter_parameter.filter_logic_type, advertising_filter_parameter.rssi_high_thresh, advertising_filter_parameter.delivery_mode, advertising_filter_parameter.onfound_timeout, advertising_filter_parameter.onfound_timeout_cnt, advertising_filter_parameter.rssi_low_thresh, advertising_filter_parameter.onlost_timeout, advertising_filter_parameter.num_of_tracking_entries), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); break; case ApcfAction::DELETE: tracker_id_map_.erase(filter_index); le_scanning_interface_->EnqueueCommand( LeAdvFilterDeleteFilteringParametersBuilder::Create(filter_index), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); // IRK Scanning if (entry != remove_me_later_map_.end()) { // Don't want to remove for a bonded device if (!is_bonded(entry->second.GetAddress())) { le_address_manager_->RemoveDeviceFromResolvingList( static_cast(entry->second.GetAddressType()), entry->second.GetAddress()); } remove_me_later_map_.erase(filter_index); } break; case ApcfAction::CLEAR: le_scanning_interface_->EnqueueCommand( LeAdvFilterClearFilteringParametersBuilder::Create(), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); // IRK Scanning if (entry != remove_me_later_map_.end()) { // Don't want to remove for a bonded device if (!is_bonded(entry->second.GetAddress())) { le_address_manager_->RemoveDeviceFromResolvingList( static_cast(entry->second.GetAddressType()), entry->second.GetAddress()); } remove_me_later_map_.erase(filter_index); } break; default: log::error("Unknown action type: {}", (uint16_t)action); break; } } void scan_filter_add(uint8_t filter_index, std::vector filters) { if (!is_filter_supported_) { log::warn("Advertising filter is not supported"); return; } ApcfAction apcf_action = ApcfAction::ADD; for (auto filter : filters) { /* If data is passed, both mask and data have to be the same length */ if (filter.data.size() != filter.data_mask.size() && filter.data.size() != 0 && filter.data_mask.size() != 0) { log::error("data and data_mask are of different size"); continue; } switch (filter.filter_type) { case ApcfFilterType::BROADCASTER_ADDRESS: { update_address_filter(apcf_action, filter_index, filter.address, filter.application_address_type, filter.irk); break; } case ApcfFilterType::SERVICE_UUID: case ApcfFilterType::SERVICE_SOLICITATION_UUID: { update_uuid_filter(apcf_action, filter_index, filter.filter_type, filter.uuid, filter.uuid_mask); break; } case ApcfFilterType::LOCAL_NAME: { update_local_name_filter(apcf_action, filter_index, filter.name); break; } case ApcfFilterType::MANUFACTURER_DATA: { update_manufacturer_data_filter( apcf_action, filter_index, filter.company, filter.company_mask, filter.data, filter.data_mask); break; } case ApcfFilterType::SERVICE_DATA: { update_service_data_filter(apcf_action, filter_index, filter.data, filter.data_mask); break; } case ApcfFilterType::TRANSPORT_DISCOVERY_DATA: { update_transport_discovery_data_filter( apcf_action, filter_index, filter.org_id, filter.tds_flags, filter.tds_flags_mask, filter.data, filter.data_mask, filter.meta_data_type, filter.meta_data); break; } case ApcfFilterType::AD_TYPE: { update_ad_type_filter(apcf_action, filter_index, filter.ad_type, filter.data, filter.data_mask); break; } default: log::error("Unknown filter type: {}", (uint16_t)filter.filter_type); break; } } } std::unordered_map remove_me_later_map_; void update_address_filter( ApcfAction action, uint8_t filter_index, Address address, ApcfApplicationAddressType address_type, std::array irk) { if (action != ApcfAction::CLEAR) { /* * The vendor command (APCF Filtering 0x0157) takes Public (0) or Random (1) * or Addresses type not applicable (2). * * Advertising results have four types: *  - Public = 0 *  - Random = 1 *  - Public ID = 2 *  - Random ID = 3 * * e.g. specifying PUBLIC (0) will only return results with a public * address. It will ignore resolved addresses, since they return PUBLIC * IDENTITY (2). For this, Addresses type not applicable (0x02) must be specified. * This should also cover if the RPA is derived from RANDOM STATIC. */ le_scanning_interface_->EnqueueCommand( LeAdvFilterBroadcasterAddressBuilder::Create( action, filter_index, address, ApcfApplicationAddressType::NOT_APPLICABLE), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); if (!is_empty_128bit(irk)) { // If an entry exists for this filter index, replace data because the filter has been // updated. auto entry = remove_me_later_map_.find(filter_index); // IRK Scanning if (entry != remove_me_later_map_.end()) { // Don't want to remove for a bonded device if (!is_bonded(entry->second.GetAddress())) { le_address_manager_->RemoveDeviceFromResolvingList( static_cast(entry->second.GetAddressType()), entry->second.GetAddress()); } remove_me_later_map_.erase(filter_index); } // Now replace it with a new one std::array empty_irk; le_address_manager_->AddDeviceToResolvingList( static_cast(address_type), address, irk, empty_irk); remove_me_later_map_.emplace(filter_index, AddressWithType(address, static_cast(address_type))); } } else { le_scanning_interface_->EnqueueCommand( LeAdvFilterClearBroadcasterAddressBuilder::Create(filter_index), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); auto entry = remove_me_later_map_.find(filter_index); if (entry != remove_me_later_map_.end()) { // TODO(optedoblivion): If not bonded le_address_manager_->RemoveDeviceFromResolvingList(static_cast(address_type), address); remove_me_later_map_.erase(filter_index); } } } bool is_empty_128bit(const std::array data) { for (int i = 0; i < 16; i++) { if (data[i] != (uint8_t)0) { return false; } } return true; } void update_uuid_filter( ApcfAction action, uint8_t filter_index, ApcfFilterType filter_type, Uuid uuid, Uuid uuid_mask) { std::vector combined_data = {}; if (action != ApcfAction::CLEAR) { uint8_t uuid_len = uuid.GetShortestRepresentationSize(); if (uuid_len == Uuid::kNumBytes16) { uint16_t data = uuid.As16Bit(); combined_data.push_back((uint8_t)data); combined_data.push_back((uint8_t)(data >> 8)); } else if (uuid_len == Uuid::kNumBytes32) { uint32_t data = uuid.As32Bit(); combined_data.push_back((uint8_t)data); combined_data.push_back((uint8_t)(data >> 8)); combined_data.push_back((uint8_t)(data >> 16)); combined_data.push_back((uint8_t)(data >> 24)); } else if (uuid_len == Uuid::kNumBytes128) { auto data = uuid.To128BitLE(); combined_data.insert(combined_data.end(), data.begin(), data.end()); } else { log::error("illegal UUID length: {}", (uint16_t)uuid_len); return; } if (!uuid_mask.IsEmpty()) { if (uuid_len == Uuid::kNumBytes16) { uint16_t data = uuid_mask.As16Bit(); combined_data.push_back((uint8_t)data); combined_data.push_back((uint8_t)(data >> 8)); } else if (uuid_len == Uuid::kNumBytes32) { uint32_t data = uuid_mask.As32Bit(); combined_data.push_back((uint8_t)data); combined_data.push_back((uint8_t)(data >> 8)); combined_data.push_back((uint8_t)(data >> 16)); combined_data.push_back((uint8_t)(data >> 24)); } else if (uuid_len == Uuid::kNumBytes128) { auto data = uuid_mask.To128BitLE(); combined_data.insert(combined_data.end(), data.begin(), data.end()); } } else { std::vector data(uuid_len, 0xFF); combined_data.insert(combined_data.end(), data.begin(), data.end()); } } if (filter_type == ApcfFilterType::SERVICE_UUID) { le_scanning_interface_->EnqueueCommand( LeAdvFilterServiceUuidBuilder::Create(action, filter_index, combined_data), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); } else { le_scanning_interface_->EnqueueCommand( LeAdvFilterSolicitationUuidBuilder::Create(action, filter_index, combined_data), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); } } void update_local_name_filter(ApcfAction action, uint8_t filter_index, std::vector name) { le_scanning_interface_->EnqueueCommand( LeAdvFilterLocalNameBuilder::Create(action, filter_index, name), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); } void update_manufacturer_data_filter( ApcfAction action, uint8_t filter_index, uint16_t company_id, uint16_t company_id_mask, std::vector data, std::vector data_mask) { if (data.size() != data_mask.size()) { log::error("manufacturer data mask should have the same length as manufacturer data"); return; } std::vector combined_data = {}; if (action != ApcfAction::CLEAR) { combined_data.push_back((uint8_t)company_id); combined_data.push_back((uint8_t)(company_id >> 8)); if (data.size() != 0) { combined_data.insert(combined_data.end(), data.begin(), data.end()); } if (company_id_mask != 0) { combined_data.push_back((uint8_t)company_id_mask); combined_data.push_back((uint8_t)(company_id_mask >> 8)); } else { combined_data.push_back(0xFF); combined_data.push_back(0xFF); } if (data_mask.size() != 0) { combined_data.insert(combined_data.end(), data_mask.begin(), data_mask.end()); } } le_scanning_interface_->EnqueueCommand( LeAdvFilterManufacturerDataBuilder::Create(action, filter_index, combined_data), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); } void update_service_data_filter( ApcfAction action, uint8_t filter_index, std::vector data, std::vector data_mask) { if (data.size() != data_mask.size()) { log::error("service data mask should have the same length as service data"); return; } std::vector combined_data = {}; if (action != ApcfAction::CLEAR && data.size() != 0) { combined_data.insert(combined_data.end(), data.begin(), data.end()); combined_data.insert(combined_data.end(), data_mask.begin(), data_mask.end()); } le_scanning_interface_->EnqueueCommand( LeAdvFilterServiceDataBuilder::Create(action, filter_index, combined_data), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); } void update_transport_discovery_data_filter( ApcfAction action, uint8_t filter_index, uint8_t org_id, uint8_t tds_flags, uint8_t tds_flags_mask, std::vector transport_data, std::vector transport_data_mask, ApcfMetaDataType meta_data_type, std::vector meta_data) { LocalVersionInformation local_version_information = controller_->GetLocalVersionInformation(); // In QTI controller, transport discovery data filter are supported by default. Check is added // to keep backward compatibility. if (!is_transport_discovery_data_filter_supported_ && !(local_version_information.manufacturer_name_ == LMP_COMPID_QTI)) { log::warn("transport discovery data filter isn't supported"); return; } log::info( "org id: {}, tds_flags: {}, tds_flags_mask: {}, transport_data size: {}, " "transport_data_mask size: {}, meta_data_type: {}, meta_data size: {}", org_id, tds_flags, tds_flags_mask, transport_data.size(), transport_data_mask.size(), (uint8_t)meta_data_type, meta_data.size()); // 0x02 Wi-Fi Alliance Neighbor Awareness Networking & meta_data_type is 0x01 for NAN Hash. if (org_id == 0x02) { // meta data contains WIFI NAN hash, reverse it before sending controller. switch (meta_data_type) { case ApcfMetaDataType::WIFI_NAN_HASH: std::reverse(meta_data.begin(), meta_data.end()); break; default: break; } } if (is_transport_discovery_data_filter_supported_) { le_scanning_interface_->EnqueueCommand( LeAdvFilterTransportDiscoveryDataBuilder::Create( action, filter_index, org_id, tds_flags, tds_flags_mask, transport_data, transport_data_mask, meta_data_type, meta_data), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); } else { // In QTI controller, transport discovery data filter are supported by default. // keeping old version for backward compatibility std::vector combined_data = {}; if (action != ApcfAction::CLEAR) { combined_data.push_back((uint8_t)org_id); combined_data.push_back((uint8_t)tds_flags); combined_data.push_back((uint8_t)tds_flags_mask); if (org_id == 0x02 && meta_data_type == ApcfMetaDataType::WIFI_NAN_HASH) { // meta data contains WIFI NAN hash combined_data.insert(combined_data.end(), meta_data.begin(), meta_data.end()); } } le_scanning_interface_->EnqueueCommand( LeAdvFilterTransportDiscoveryDataOldBuilder::Create(action, filter_index, combined_data), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); } } void update_ad_type_filter( ApcfAction action, uint8_t filter_index, uint8_t ad_type, std::vector data, std::vector data_mask) { if (!is_ad_type_filter_supported_) { log::error("AD type filter isn't supported"); return; } if (data.size() != data_mask.size()) { log::error("ad type mask should have the same length as ad type data"); return; } std::vector combined_data = {}; if (action != ApcfAction::CLEAR) { combined_data.push_back((uint8_t)ad_type); combined_data.push_back((uint8_t)(data.size())); if (data.size() != 0) { combined_data.insert(combined_data.end(), data.begin(), data.end()); combined_data.insert(combined_data.end(), data_mask.begin(), data_mask.end()); } } le_scanning_interface_->EnqueueCommand( LeAdvFilterADTypeBuilder::Create(action, filter_index, combined_data), module_handler_->BindOnceOn(this, &impl::on_advertising_filter_complete)); } void batch_scan_set_storage_parameter( uint8_t batch_scan_full_max, uint8_t batch_scan_truncated_max, uint8_t batch_scan_notify_threshold, ScannerId scanner_id) { if (!is_batch_scan_supported_) { log::warn("Batch scan is not supported"); return; } // scanner id for OnBatchScanThresholdCrossed batch_scan_config_.ref_value = scanner_id; if (batch_scan_config_.current_state == BatchScanState::ERROR_STATE || batch_scan_config_.current_state == BatchScanState::DISABLED_STATE || batch_scan_config_.current_state == BatchScanState::DISABLE_CALLED) { batch_scan_config_.current_state = BatchScanState::ENABLE_CALLED; le_scanning_interface_->EnqueueCommand( LeBatchScanEnableBuilder::Create(Enable::ENABLED), module_handler_->BindOnceOn(this, &impl::on_batch_scan_enable_complete)); } le_scanning_interface_->EnqueueCommand( LeBatchScanSetStorageParametersBuilder::Create( batch_scan_full_max, batch_scan_truncated_max, batch_scan_notify_threshold), module_handler_->BindOnceOn(this, &impl::on_batch_scan_complete)); } void batch_scan_enable( BatchScanMode scan_mode, uint32_t duty_cycle_scan_window_slots, uint32_t duty_cycle_scan_interval_slots, BatchScanDiscardRule batch_scan_discard_rule) { if (!is_batch_scan_supported_) { log::warn("Batch scan is not supported"); return; } if (batch_scan_config_.current_state == BatchScanState::ERROR_STATE || batch_scan_config_.current_state == BatchScanState::DISABLED_STATE || batch_scan_config_.current_state == BatchScanState::DISABLE_CALLED) { batch_scan_config_.current_state = BatchScanState::ENABLE_CALLED; le_scanning_interface_->EnqueueCommand( LeBatchScanEnableBuilder::Create(Enable::ENABLED), module_handler_->BindOnceOn(this, &impl::on_batch_scan_enable_complete)); } batch_scan_config_.scan_mode = scan_mode; batch_scan_config_.scan_interval = duty_cycle_scan_interval_slots; batch_scan_config_.scan_window = duty_cycle_scan_window_slots; batch_scan_config_.discard_rule = batch_scan_discard_rule; /* This command starts batch scanning, if enabled */ batch_scan_set_scan_parameter( scan_mode, duty_cycle_scan_window_slots, duty_cycle_scan_interval_slots, batch_scan_discard_rule); } void batch_scan_disable() { if (!is_batch_scan_supported_) { log::warn("Batch scan is not supported"); return; } batch_scan_config_.current_state = BatchScanState::DISABLE_CALLED; batch_scan_set_scan_parameter( BatchScanMode::DISABLE, batch_scan_config_.scan_window, batch_scan_config_.scan_interval, batch_scan_config_.discard_rule); } void batch_scan_set_scan_parameter( BatchScanMode scan_mode, uint32_t duty_cycle_scan_window_slots, uint32_t duty_cycle_scan_interval_slots, BatchScanDiscardRule batch_scan_discard_rule) { if (!is_batch_scan_supported_) { log::warn("Batch scan is not supported"); return; } PeerAddressType own_address_type = PeerAddressType::PUBLIC_DEVICE_OR_IDENTITY_ADDRESS; if (own_address_type_ == OwnAddressType::RANDOM_DEVICE_ADDRESS || own_address_type_ == OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS) { own_address_type = PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS; } uint8_t truncated_mode_enabled = 0x00; uint8_t full_mode_enabled = 0x00; if (scan_mode == BatchScanMode::TRUNCATED || scan_mode == BatchScanMode::TRUNCATED_AND_FULL) { truncated_mode_enabled = 0x01; } if (scan_mode == BatchScanMode::FULL || scan_mode == BatchScanMode::TRUNCATED_AND_FULL) { full_mode_enabled = 0x01; } if (scan_mode == BatchScanMode::DISABLE) { le_scanning_interface_->EnqueueCommand( LeBatchScanSetScanParametersBuilder::Create( truncated_mode_enabled, full_mode_enabled, duty_cycle_scan_window_slots, duty_cycle_scan_interval_slots, own_address_type, batch_scan_discard_rule), module_handler_->BindOnceOn(this, &impl::on_batch_scan_disable_complete)); } else { le_scanning_interface_->EnqueueCommand( LeBatchScanSetScanParametersBuilder::Create( truncated_mode_enabled, full_mode_enabled, duty_cycle_scan_window_slots, duty_cycle_scan_interval_slots, own_address_type, batch_scan_discard_rule), module_handler_->BindOnceOn(this, &impl::on_batch_scan_complete)); } } void batch_scan_read_results(ScannerId scanner_id, uint16_t total_num_of_records, BatchScanMode scan_mode) { if (!is_batch_scan_supported_) { log::warn("Batch scan is not supported"); int status = static_cast(ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); scanning_callbacks_->OnBatchScanReports(scanner_id, status, 0, 0, {}); return; } if (scan_mode != BatchScanMode::FULL && scan_mode != BatchScanMode::TRUNCATED) { log::warn("Invalid scan mode {}", (uint16_t)scan_mode); int status = static_cast(ErrorCode::INVALID_HCI_COMMAND_PARAMETERS); scanning_callbacks_->OnBatchScanReports(scanner_id, status, 0, 0, {}); return; } if (batch_scan_result_cache_.find(scanner_id) == batch_scan_result_cache_.end()) { std::vector empty_data = {}; batch_scan_result_cache_.emplace(scanner_id, empty_data); } le_scanning_interface_->EnqueueCommand( LeBatchScanReadResultParametersBuilder::Create(static_cast(scan_mode)), module_handler_->BindOnceOn(this, &impl::on_batch_scan_read_result_complete, scanner_id, total_num_of_records)); } void start_sync( uint8_t sid, const AddressWithType& address_with_type, uint16_t skip, uint16_t timeout, int request_id) { if (!is_periodic_advertising_sync_transfer_sender_supported_) { log::warn("PAST sender not supported on this device"); int status = static_cast(ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); scanning_callbacks_->OnPeriodicSyncStarted(request_id, status, -1, sid, address_with_type, 0, 0); return; } PeriodicSyncStates request{ .request_id = request_id, .advertiser_sid = sid, .address_with_type = address_with_type, .sync_handle = 0, .sync_state = PeriodicSyncState::PERIODIC_SYNC_STATE_IDLE, }; periodic_sync_manager_.StartSync(request, skip, timeout); } void stop_sync(uint16_t handle) { if (!is_periodic_advertising_sync_transfer_sender_supported_) { log::warn("PAST sender not supported on this device"); return; } periodic_sync_manager_.StopSync(handle); } void cancel_create_sync(uint8_t sid, const Address& address) { if (!is_periodic_advertising_sync_transfer_sender_supported_) { log::warn("PAST sender not supported on this device"); return; } periodic_sync_manager_.CancelCreateSync(sid, address); } void transfer_sync( const Address& address, uint16_t connection_handle, uint16_t service_data, uint16_t sync_handle, int pa_source) { if (!is_periodic_advertising_sync_transfer_sender_supported_) { log::warn("PAST sender not supported on this device"); int status = static_cast(ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); scanning_callbacks_->OnPeriodicSyncTransferred(pa_source, status, address); return; } if (connection_handle == 0xFFFF) { log::error("[PAST]: Invalid connection handle or no LE ACL link"); int status = static_cast(ErrorCode::UNKNOWN_CONNECTION); scanning_callbacks_->OnPeriodicSyncTransferred(pa_source, status, address); return; } periodic_sync_manager_.TransferSync(address, service_data, sync_handle, pa_source, connection_handle); } void transfer_set_info( const Address& address, uint16_t connection_handle, uint16_t service_data, uint8_t adv_handle, int pa_source) { if (!is_periodic_advertising_sync_transfer_sender_supported_) { log::warn("PAST sender not supported on this device"); int status = static_cast(ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); scanning_callbacks_->OnPeriodicSyncTransferred(pa_source, status, address); return; } if (connection_handle == 0xFFFF) { log::error("[PAST]:Invalid connection handle or no LE ACL link"); int status = static_cast(ErrorCode::UNKNOWN_CONNECTION); scanning_callbacks_->OnPeriodicSyncTransferred(pa_source, status, address); return; } periodic_sync_manager_.SyncSetInfo(address, service_data, adv_handle, pa_source, connection_handle); } void sync_tx_parameters(const Address& address, uint8_t mode, uint16_t skip, uint16_t timeout, int reg_id) { if (!is_periodic_advertising_sync_transfer_sender_supported_) { log::warn("PAST sender not supported on this device"); int status = static_cast(ErrorCode::UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE); AddressWithType address_with_type(address, AddressType::RANDOM_DEVICE_ADDRESS); scanning_callbacks_->OnPeriodicSyncStarted(reg_id, status, -1, -1, address_with_type, 0, 0); return; } periodic_sync_manager_.SyncTxParameters(address, mode, skip, timeout, reg_id); } void track_advertiser(uint8_t filter_index, ScannerId scanner_id) { if (total_num_of_advt_tracked_ <= 0) { log::warn("advertisement tracking is not supported"); AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info = {}; on_found_on_lost_info.scanner_id = scanner_id; on_found_on_lost_info.advertiser_info_present = AdvtInfoPresent::NO_ADVT_INFO_PRESENT; scanning_callbacks_->OnTrackAdvFoundLost(on_found_on_lost_info); return; } else if (tracker_id_map_.size() >= total_num_of_advt_tracked_) { AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info = {}; on_found_on_lost_info.scanner_id = scanner_id; on_found_on_lost_info.advertiser_info_present = AdvtInfoPresent::NO_ADVT_INFO_PRESENT; scanning_callbacks_->OnTrackAdvFoundLost(on_found_on_lost_info); return; } log::info( "track_advertiser scanner_id {}, filter_index {}", (uint16_t)scanner_id, (uint16_t)filter_index); tracker_id_map_[filter_index] = scanner_id; } void register_scanning_callback(ScanningCallback* scanning_callbacks) { scanning_callbacks_ = scanning_callbacks; periodic_sync_manager_.SetScanningCallback(scanning_callbacks_); } bool is_ad_type_filter_supported() { return is_ad_type_filter_supported_; } void on_set_scan_parameter_complete(CommandCompleteView view) { switch (view.GetCommandOpCode()) { case (OpCode::LE_SET_SCAN_PARAMETERS): { auto status_view = LeSetScanParametersCompleteView::Create(view); log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()"); if (status_view.GetStatus() != ErrorCode::SUCCESS) { log::info( "Receive set scan parameter complete with error code {}", ErrorCodeText(status_view.GetStatus())); } } break; case (OpCode::LE_EXTENDED_SCAN_PARAMS): { auto status_view = LeExtendedScanParamsCompleteView::Create(view); log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()"); if (status_view.GetStatus() != ErrorCode::SUCCESS) { log::info( "Receive extended scan parameter complete with error code {}", ErrorCodeText(status_view.GetStatus())); } } break; case (OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS): { auto status_view = LeSetExtendedScanParametersCompleteView::Create(view); log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()"); if (status_view.GetStatus() != ErrorCode::SUCCESS) { log::info( "Receive set extended scan parameter complete with error code {}", ErrorCodeText(status_view.GetStatus())); } } break; default: log::fatal("Unhandled event {}", OpCodeText(view.GetCommandOpCode())); } } void on_advertising_filter_complete(CommandCompleteView view) { log::assert_that(view.IsValid(), "assert failed: view.IsValid()"); auto status_view = LeAdvFilterCompleteView::Create(view); log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()"); if (status_view.GetStatus() != ErrorCode::SUCCESS) { log::info( "Got a Command complete {}, status {}", OpCodeText(view.GetCommandOpCode()), ErrorCodeText(status_view.GetStatus())); } ApcfOpcode apcf_opcode = status_view.GetApcfOpcode(); switch (apcf_opcode) { case ApcfOpcode::ENABLE: { auto complete_view = LeAdvFilterEnableCompleteView::Create(status_view); log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); scanning_callbacks_->OnFilterEnable(complete_view.GetApcfEnable(), (uint8_t)complete_view.GetStatus()); } break; case ApcfOpcode::SET_FILTERING_PARAMETERS: { auto complete_view = LeAdvFilterSetFilteringParametersCompleteView::Create(status_view); log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); scanning_callbacks_->OnFilterParamSetup( complete_view.GetApcfAvailableSpaces(), complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus()); } break; case ApcfOpcode::BROADCASTER_ADDRESS: { auto complete_view = LeAdvFilterBroadcasterAddressCompleteView::Create(status_view); log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); scanning_callbacks_->OnFilterConfigCallback( ApcfFilterType::BROADCASTER_ADDRESS, complete_view.GetApcfAvailableSpaces(), complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus()); } break; case ApcfOpcode::SERVICE_UUID: { auto complete_view = LeAdvFilterServiceUuidCompleteView::Create(status_view); log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); scanning_callbacks_->OnFilterConfigCallback( ApcfFilterType::SERVICE_UUID, complete_view.GetApcfAvailableSpaces(), complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus()); } break; case ApcfOpcode::SERVICE_SOLICITATION_UUID: { auto complete_view = LeAdvFilterSolicitationUuidCompleteView::Create(status_view); log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); scanning_callbacks_->OnFilterConfigCallback( ApcfFilterType::SERVICE_SOLICITATION_UUID, complete_view.GetApcfAvailableSpaces(), complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus()); } break; case ApcfOpcode::LOCAL_NAME: { auto complete_view = LeAdvFilterLocalNameCompleteView::Create(status_view); log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); scanning_callbacks_->OnFilterConfigCallback( ApcfFilterType::LOCAL_NAME, complete_view.GetApcfAvailableSpaces(), complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus()); } break; case ApcfOpcode::MANUFACTURER_DATA: { auto complete_view = LeAdvFilterManufacturerDataCompleteView::Create(status_view); log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); scanning_callbacks_->OnFilterConfigCallback( ApcfFilterType::MANUFACTURER_DATA, complete_view.GetApcfAvailableSpaces(), complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus()); } break; case ApcfOpcode::SERVICE_DATA: { auto complete_view = LeAdvFilterServiceDataCompleteView::Create(status_view); log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); scanning_callbacks_->OnFilterConfigCallback( ApcfFilterType::SERVICE_DATA, complete_view.GetApcfAvailableSpaces(), complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus()); } break; case ApcfOpcode::TRANSPORT_DISCOVERY_DATA: { auto complete_view = LeAdvFilterTransportDiscoveryDataCompleteView::Create(status_view); log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); scanning_callbacks_->OnFilterConfigCallback( ApcfFilterType::TRANSPORT_DISCOVERY_DATA, complete_view.GetApcfAvailableSpaces(), complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus()); } break; case ApcfOpcode::AD_TYPE: { auto complete_view = LeAdvFilterADTypeCompleteView::Create(status_view); log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); scanning_callbacks_->OnFilterConfigCallback( ApcfFilterType::AD_TYPE, complete_view.GetApcfAvailableSpaces(), complete_view.GetApcfAction(), (uint8_t)complete_view.GetStatus()); } break; default: log::warn("Unexpected event type {}", OpCodeText(view.GetCommandOpCode())); } } void on_apcf_read_extended_features_complete(CommandCompleteView view) { log::assert_that(view.IsValid(), "assert failed: view.IsValid()"); auto status_view = LeAdvFilterCompleteView::Create(view); if (!status_view.IsValid()) { log::warn("Can not get valid LeAdvFilterCompleteView, return"); return; } if (status_view.GetStatus() != ErrorCode::SUCCESS) { log::warn( "Got a Command complete {}, status {}", OpCodeText(view.GetCommandOpCode()), ErrorCodeText(status_view.GetStatus())); return; } auto complete_view = LeAdvFilterReadExtendedFeaturesCompleteView::Create(status_view); log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); is_transport_discovery_data_filter_supported_ = complete_view.GetTransportDiscoveryDataFilter() == 1; is_ad_type_filter_supported_ = complete_view.GetAdTypeFilter() == 1; log::info( "set is_ad_type_filter_supported_ to {} & is_transport_discovery_data_filter_supported_ to " "{}", is_ad_type_filter_supported_, is_transport_discovery_data_filter_supported_); } void on_batch_scan_complete(CommandCompleteView view) { log::assert_that(view.IsValid(), "assert failed: view.IsValid()"); auto status_view = LeBatchScanCompleteView::Create(view); log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()"); if (status_view.GetStatus() != ErrorCode::SUCCESS) { log::info( "Got a Command complete {}, status {}, batch_scan_opcode {}", OpCodeText(view.GetCommandOpCode()), ErrorCodeText(status_view.GetStatus()), BatchScanOpcodeText(status_view.GetBatchScanOpcode())); } } void on_batch_scan_enable_complete(CommandCompleteView view) { log::assert_that(view.IsValid(), "assert failed: view.IsValid()"); auto status_view = LeBatchScanCompleteView::Create(view); log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()"); auto complete_view = LeBatchScanEnableCompleteView::Create(status_view); log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); if (status_view.GetStatus() != ErrorCode::SUCCESS) { log::info( "Got batch scan enable complete, status {}", ErrorCodeText(status_view.GetStatus())); batch_scan_config_.current_state = BatchScanState::ERROR_STATE; } else { batch_scan_config_.current_state = BatchScanState::ENABLED_STATE; } } void on_batch_scan_disable_complete(CommandCompleteView view) { log::assert_that(view.IsValid(), "assert failed: view.IsValid()"); auto status_view = LeBatchScanCompleteView::Create(view); log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()"); auto complete_view = LeBatchScanSetScanParametersCompleteView::Create(status_view); log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); log::assert_that( status_view.GetStatus() == ErrorCode::SUCCESS, "assert failed: status_view.GetStatus() == ErrorCode::SUCCESS"); batch_scan_config_.current_state = BatchScanState::DISABLED_STATE; } void on_batch_scan_read_result_complete( ScannerId scanner_id, uint16_t total_num_of_records, CommandCompleteView view) { log::assert_that(view.IsValid(), "assert failed: view.IsValid()"); auto status_view = LeBatchScanCompleteView::Create(view); log::assert_that(status_view.IsValid(), "assert failed: status_view.IsValid()"); auto complete_view = LeBatchScanReadResultParametersCompleteRawView::Create(status_view); log::assert_that(complete_view.IsValid(), "assert failed: complete_view.IsValid()"); if (complete_view.GetStatus() != ErrorCode::SUCCESS) { log::info( "Got batch scan read result complete, status {}", ErrorCodeText(status_view.GetStatus())); } uint8_t num_of_records = complete_view.GetNumOfRecords(); auto report_format = complete_view.GetBatchScanDataRead(); if (num_of_records == 0) { scanning_callbacks_->OnBatchScanReports( scanner_id, 0x00, (int)report_format, total_num_of_records, batch_scan_result_cache_[scanner_id]); batch_scan_result_cache_.erase(scanner_id); } else { auto raw_data = complete_view.GetRawData(); batch_scan_result_cache_[scanner_id].insert( batch_scan_result_cache_[scanner_id].end(), raw_data.begin(), raw_data.end()); total_num_of_records += num_of_records; batch_scan_read_results(scanner_id, total_num_of_records, static_cast(report_format)); } } void on_storage_threshold_breach(VendorSpecificEventView /* event */) { if (batch_scan_config_.ref_value == kInvalidScannerId) { log::warn("storage threshold was not set !!"); return; } scanning_callbacks_->OnBatchScanThresholdCrossed(static_cast(batch_scan_config_.ref_value)); } void on_advertisement_tracking(VendorSpecificEventView event) { auto view = LEAdvertisementTrackingEventView::Create(event); log::assert_that(view.IsValid(), "assert failed: view.IsValid()"); uint8_t filter_index = view.GetApcfFilterIndex(); if (tracker_id_map_.find(filter_index) == tracker_id_map_.end()) { log::warn("Advertisement track for filter_index {} is not register", (uint16_t)filter_index); return; } AdvertisingFilterOnFoundOnLostInfo on_found_on_lost_info = {}; on_found_on_lost_info.scanner_id = tracker_id_map_[filter_index]; on_found_on_lost_info.filter_index = filter_index; on_found_on_lost_info.advertiser_state = view.GetAdvertiserState(); on_found_on_lost_info.advertiser_address = view.GetAdvertiserAddress(); on_found_on_lost_info.advertiser_address_type = view.GetAdvertiserAddressType(); on_found_on_lost_info.advertiser_info_present = view.GetAdvtInfoPresent(); /* Extract the adv info details */ if (on_found_on_lost_info.advertiser_info_present == AdvtInfoPresent::ADVT_INFO_PRESENT) { auto info_view = LEAdvertisementTrackingWithInfoEventView::Create(view); log::assert_that(info_view.IsValid(), "assert failed: info_view.IsValid()"); on_found_on_lost_info.tx_power = info_view.GetTxPower(); on_found_on_lost_info.rssi = info_view.GetRssi(); on_found_on_lost_info.time_stamp = info_view.GetTimestamp(); auto adv_data = info_view.GetAdvPacket(); on_found_on_lost_info.adv_packet.reserve(adv_data.size()); on_found_on_lost_info.adv_packet.insert(on_found_on_lost_info.adv_packet.end(), adv_data.begin(), adv_data.end()); auto scan_rsp_data = info_view.GetScanResponse(); on_found_on_lost_info.scan_response.reserve(scan_rsp_data.size()); on_found_on_lost_info.scan_response.insert( on_found_on_lost_info.scan_response.end(), scan_rsp_data.begin(), scan_rsp_data.end()); } scanning_callbacks_->OnTrackAdvFoundLost(on_found_on_lost_info); } void OnPause() override { if (!address_manager_registered_) { log::warn("Unregistered!"); return; } paused_ = true; scan_on_resume_ = is_scanning_; stop_scan(); ack_pause(); } void ack_pause() { le_address_manager_->AckPause(this); } void OnResume() override { if (!address_manager_registered_) { log::warn("Unregistered!"); return; } paused_ = false; if (scan_on_resume_ == true) { scan_on_resume_ = false; start_scan(); } le_address_manager_->AckResume(this); } ScanApiType api_type_; Module* module_; os::Handler* module_handler_; HciLayer* hci_layer_; Controller* controller_; AclManager* acl_manager_; storage::StorageModule* storage_module_; LeScanningInterface* le_scanning_interface_; LeAddressManager* le_address_manager_; bool address_manager_registered_ = false; NullScanningCallback null_scanning_callback_; ScanningCallback* scanning_callbacks_ = &null_scanning_callback_; PeriodicSyncManager periodic_sync_manager_{&null_scanning_callback_}; std::vector scanners_; bool is_scanning_ = false; bool scan_on_resume_ = false; bool paused_ = false; LeScanningReassembler scanning_reassembler_; bool is_filter_supported_ = false; bool is_ad_type_filter_supported_ = false; bool is_batch_scan_supported_ = false; bool is_periodic_advertising_sync_transfer_sender_supported_ = false; bool is_transport_discovery_data_filter_supported_ = false; LeScanType le_scan_type_ = LeScanType::ACTIVE; uint32_t interval_ms_{1000}; uint16_t window_ms_{1000}; uint8_t phy_{(uint8_t)PhyType::LE_1M}; OwnAddressType own_address_type_{OwnAddressType::PUBLIC_DEVICE_ADDRESS}; LeScanningFilterPolicy filter_policy_{LeScanningFilterPolicy::ACCEPT_ALL}; BatchScanConfig batch_scan_config_; std::map> batch_scan_result_cache_; std::unordered_map tracker_id_map_; uint16_t total_num_of_advt_tracked_ = 0x00; int8_t le_rx_path_loss_comp_ = 0; }; LeScanningManager::LeScanningManager() { pimpl_ = std::make_unique(this); } void LeScanningManager::ListDependencies(ModuleList* list) const { list->add(); list->add(); list->add(); list->add(); } void LeScanningManager::Start() { pimpl_->start( GetHandler(), GetDependency(), GetDependency(), GetDependency(), GetDependency()); } void LeScanningManager::Stop() { pimpl_->stop(); pimpl_.reset(); } std::string LeScanningManager::ToString() const { return "Le Scanning Manager"; } void LeScanningManager::RegisterScanner(Uuid app_uuid) { CallOn(pimpl_.get(), &impl::register_scanner, app_uuid); } void LeScanningManager::Unregister(ScannerId scanner_id) { CallOn(pimpl_.get(), &impl::unregister_scanner, scanner_id); } void LeScanningManager::Scan(bool start) { CallOn(pimpl_.get(), &impl::scan, start); } void LeScanningManager::SetScanParameters( ScannerId scanner_id, LeScanType scan_type, uint16_t scan_interval, uint16_t scan_window, uint8_t scan_phy) { CallOn( pimpl_.get(), &impl::set_scan_parameters, scanner_id, scan_type, scan_interval, scan_window, scan_phy); } void LeScanningManager::SetScanFilterPolicy(LeScanningFilterPolicy filter_policy) { CallOn(pimpl_.get(), &impl::set_scan_filter_policy, filter_policy); } void LeScanningManager::ScanFilterEnable(bool enable) { CallOn(pimpl_.get(), &impl::scan_filter_enable, enable); } void LeScanningManager::ScanFilterParameterSetup( ApcfAction action, uint8_t filter_index, AdvertisingFilterParameter advertising_filter_parameter) { CallOn(pimpl_.get(), &impl::scan_filter_parameter_setup, action, filter_index, advertising_filter_parameter); } void LeScanningManager::ScanFilterAdd( uint8_t filter_index, std::vector filters) { CallOn(pimpl_.get(), &impl::scan_filter_add, filter_index, filters); } void LeScanningManager::BatchScanConifgStorage( uint8_t batch_scan_full_max, uint8_t batch_scan_truncated_max, uint8_t batch_scan_notify_threshold, ScannerId scanner_id) { CallOn( pimpl_.get(), &impl::batch_scan_set_storage_parameter, batch_scan_full_max, batch_scan_truncated_max, batch_scan_notify_threshold, scanner_id); } void LeScanningManager::BatchScanEnable( BatchScanMode scan_mode, uint32_t duty_cycle_scan_window_slots, uint32_t duty_cycle_scan_interval_slots, BatchScanDiscardRule batch_scan_discard_rule) { CallOn( pimpl_.get(), &impl::batch_scan_enable, scan_mode, duty_cycle_scan_window_slots, duty_cycle_scan_interval_slots, batch_scan_discard_rule); } void LeScanningManager::BatchScanDisable() { CallOn(pimpl_.get(), &impl::batch_scan_disable); } void LeScanningManager::BatchScanReadReport(ScannerId scanner_id, BatchScanMode scan_mode) { CallOn(pimpl_.get(), &impl::batch_scan_read_results, scanner_id, 0, scan_mode); } void LeScanningManager::StartSync( uint8_t sid, const AddressWithType& address_with_type, uint16_t skip, uint16_t timeout, int reg_id) { CallOn(pimpl_.get(), &impl::start_sync, sid, address_with_type, skip, timeout, reg_id); } void LeScanningManager::StopSync(uint16_t handle) { CallOn(pimpl_.get(), &impl::stop_sync, handle); } void LeScanningManager::CancelCreateSync(uint8_t sid, const Address& address) { CallOn(pimpl_.get(), &impl::cancel_create_sync, sid, address); } void LeScanningManager::TransferSync( const Address& address, uint16_t handle, uint16_t service_data, uint16_t sync_handle, int pa_source) { CallOn(pimpl_.get(), &impl::transfer_sync, address, handle, service_data, sync_handle, pa_source); } void LeScanningManager::TransferSetInfo( const Address& address, uint16_t handle, uint16_t service_data, uint8_t adv_handle, int pa_source) { CallOn( pimpl_.get(), &impl::transfer_set_info, address, handle, service_data, adv_handle, pa_source); } void LeScanningManager::SyncTxParameters( const Address& address, uint8_t mode, uint16_t skip, uint16_t timeout, int reg_id) { CallOn(pimpl_.get(), &impl::sync_tx_parameters, address, mode, skip, timeout, reg_id); } void LeScanningManager::TrackAdvertiser(uint8_t filter_index, ScannerId scanner_id) { CallOn(pimpl_.get(), &impl::track_advertiser, filter_index, scanner_id); } void LeScanningManager::RegisterScanningCallback(ScanningCallback* scanning_callback) { CallOn(pimpl_.get(), &impl::register_scanning_callback, scanning_callback); } bool LeScanningManager::IsAdTypeFilterSupported() const { return pimpl_->is_ad_type_filter_supported(); } } // namespace hci } // namespace bluetooth