Home | History | Annotate | Download | only in scanning
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "wificond/scanning/scanner_impl.h"
     18 
     19 #include <string>
     20 #include <vector>
     21 
     22 #include <android-base/logging.h>
     23 
     24 #include "wificond/client_interface_impl.h"
     25 #include "wificond/scanning/offload/offload_scan_manager.h"
     26 #include "wificond/scanning/offload/offload_service_utils.h"
     27 #include "wificond/scanning/scan_utils.h"
     28 
     29 using android::binder::Status;
     30 using android::net::wifi::IPnoScanEvent;
     31 using android::net::wifi::IScanEvent;
     32 using android::net::wifi::IWifiScannerImpl;
     33 using android::hardware::wifi::offload::V1_0::IOffload;
     34 using android::sp;
     35 using com::android::server::wifi::wificond::NativeScanResult;
     36 using com::android::server::wifi::wificond::PnoSettings;
     37 using com::android::server::wifi::wificond::SingleScanSettings;
     38 
     39 using std::pair;
     40 using std::string;
     41 using std::vector;
     42 using std::weak_ptr;
     43 using std::shared_ptr;
     44 
     45 using namespace std::placeholders;
     46 
     47 namespace {
     48 using android::wificond::WiphyFeatures;
     49 bool IsScanTypeSupported(int scan_type, const WiphyFeatures& wiphy_features) {
     50   switch(scan_type) {
     51     case IWifiScannerImpl::SCAN_TYPE_LOW_SPAN:
     52       return wiphy_features.supports_low_span_oneshot_scan;
     53     case IWifiScannerImpl::SCAN_TYPE_LOW_POWER:
     54       return wiphy_features.supports_low_power_oneshot_scan;
     55     case IWifiScannerImpl::SCAN_TYPE_HIGH_ACCURACY:
     56       return wiphy_features.supports_high_accuracy_oneshot_scan;
     57     default:
     58       CHECK(0) << "Invalid scan type received: " << scan_type;
     59   }
     60   return {};
     61 }
     62 } // namespace
     63 
     64 namespace android {
     65 namespace wificond {
     66 
     67 ScannerImpl::ScannerImpl(uint32_t interface_index,
     68                          const ScanCapabilities& scan_capabilities,
     69                          const WiphyFeatures& wiphy_features,
     70                          ClientInterfaceImpl* client_interface,
     71                          ScanUtils* scan_utils,
     72                          weak_ptr<OffloadServiceUtils> offload_service_utils)
     73     : valid_(true),
     74       scan_started_(false),
     75       pno_scan_started_(false),
     76       offload_scan_supported_(false),
     77       pno_scan_running_over_offload_(false),
     78       pno_scan_results_from_offload_(false),
     79       interface_index_(interface_index),
     80       scan_capabilities_(scan_capabilities),
     81       wiphy_features_(wiphy_features),
     82       client_interface_(client_interface),
     83       scan_utils_(scan_utils),
     84       scan_event_handler_(nullptr) {
     85   // Subscribe one-shot scan result notification from kernel.
     86   LOG(INFO) << "subscribe scan result for interface with index: "
     87             << (int)interface_index_;
     88   scan_utils_->SubscribeScanResultNotification(
     89       interface_index_,
     90       std::bind(&ScannerImpl::OnScanResultsReady, this, _1, _2, _3, _4));
     91   // Subscribe scheduled scan result notification from kernel.
     92   scan_utils_->SubscribeSchedScanResultNotification(
     93       interface_index_,
     94       std::bind(&ScannerImpl::OnSchedScanResultsReady,
     95                 this,
     96                 _1, _2));
     97   std::shared_ptr<OffloadScanCallbackInterfaceImpl>
     98       offload_scan_callback_interface =
     99           offload_service_utils.lock()->GetOffloadScanCallbackInterface(this);
    100   offload_scan_manager_ = offload_service_utils.lock()->GetOffloadScanManager(
    101       offload_service_utils, offload_scan_callback_interface);
    102   offload_scan_supported_ = offload_service_utils.lock()->IsOffloadScanSupported();
    103 }
    104 
    105 ScannerImpl::~ScannerImpl() {}
    106 
    107 void ScannerImpl::Invalidate() {
    108   LOG(INFO) << "Unsubscribe scan result for interface with index: "
    109             << (int)interface_index_;
    110   scan_utils_->UnsubscribeScanResultNotification(interface_index_);
    111   scan_utils_->UnsubscribeSchedScanResultNotification(interface_index_);
    112 }
    113 
    114 bool ScannerImpl::CheckIsValid() {
    115   if (!valid_) {
    116     LOG(DEBUG) << "Calling on a invalid scanner object."
    117                << "Underlying client interface object was destroyed.";
    118   }
    119   return valid_;
    120 }
    121 
    122 Status ScannerImpl::getScanResults(vector<NativeScanResult>* out_scan_results) {
    123   if (!CheckIsValid()) {
    124     return Status::ok();
    125   }
    126   if (!scan_utils_->GetScanResult(interface_index_, out_scan_results)) {
    127     LOG(ERROR) << "Failed to get scan results via NL80211";
    128   }
    129   return Status::ok();
    130 }
    131 
    132 Status ScannerImpl::getPnoScanResults(
    133     vector<NativeScanResult>* out_scan_results) {
    134   if (!CheckIsValid()) {
    135     return Status::ok();
    136   }
    137   if (pno_scan_results_from_offload_) {
    138     if (!offload_scan_manager_->getScanResults(out_scan_results)) {
    139       LOG(ERROR) << "Failed to get scan results via Offload HAL";
    140     }
    141   } else {
    142     if (!scan_utils_->GetScanResult(interface_index_, out_scan_results)) {
    143       LOG(ERROR) << "Failed to get scan results via NL80211";
    144     }
    145   }
    146   return Status::ok();
    147 }
    148 
    149 Status ScannerImpl::scan(const SingleScanSettings& scan_settings,
    150                          bool* out_success) {
    151   if (!CheckIsValid()) {
    152     *out_success = false;
    153     return Status::ok();
    154   }
    155 
    156   if (scan_started_) {
    157     LOG(WARNING) << "Scan already started";
    158   }
    159   // Only request MAC address randomization when station is not associated.
    160   bool request_random_mac =
    161       wiphy_features_.supports_random_mac_oneshot_scan &&
    162       !client_interface_->IsAssociated();
    163   int scan_type = scan_settings.scan_type_;
    164   if (!IsScanTypeSupported(scan_settings.scan_type_, wiphy_features_)) {
    165     LOG(DEBUG) << "Ignoring scan type because device does not support it";
    166     scan_type = SCAN_TYPE_DEFAULT;
    167   }
    168 
    169   // Initialize it with an empty ssid for a wild card scan.
    170   vector<vector<uint8_t>> ssids = {{}};
    171 
    172   vector<vector<uint8_t>> skipped_scan_ssids;
    173   for (auto& network : scan_settings.hidden_networks_) {
    174     if (ssids.size() + 1 > scan_capabilities_.max_num_scan_ssids) {
    175       skipped_scan_ssids.emplace_back(network.ssid_);
    176       continue;
    177     }
    178     ssids.push_back(network.ssid_);
    179   }
    180 
    181   LogSsidList(skipped_scan_ssids, "Skip scan ssid for single scan");
    182 
    183   vector<uint32_t> freqs;
    184   for (auto& channel : scan_settings.channel_settings_) {
    185     freqs.push_back(channel.frequency_);
    186   }
    187 
    188   int error_code = 0;
    189   if (!scan_utils_->Scan(interface_index_, request_random_mac, scan_type,
    190                          ssids, freqs, &error_code)) {
    191     CHECK(error_code != ENODEV) << "Driver is in a bad state, restarting wificond";
    192     *out_success = false;
    193     return Status::ok();
    194   }
    195   scan_started_ = true;
    196   *out_success = true;
    197   return Status::ok();
    198 }
    199 
    200 Status ScannerImpl::startPnoScan(const PnoSettings& pno_settings,
    201                                  bool* out_success) {
    202   pno_settings_ = pno_settings;
    203   pno_scan_results_from_offload_ = false;
    204   LOG(VERBOSE) << "startPnoScan";
    205   if (offload_scan_supported_ && StartPnoScanOffload(pno_settings)) {
    206     // scanning over offload succeeded
    207     *out_success = true;
    208   } else {
    209     *out_success = StartPnoScanDefault(pno_settings);
    210   }
    211   return Status::ok();
    212 }
    213 
    214 bool ScannerImpl::StartPnoScanOffload(const PnoSettings& pno_settings) {
    215   OffloadScanManager::ReasonCode reason_code;
    216   vector<vector<uint8_t>> scan_ssids;
    217   vector<vector<uint8_t>> match_ssids;
    218   vector<uint8_t> match_security;
    219   // Empty frequency list: scan all frequencies.
    220   vector<uint32_t> freqs;
    221 
    222   ParsePnoSettings(pno_settings, &scan_ssids, &match_ssids, &freqs,
    223                    &match_security);
    224   pno_scan_running_over_offload_ = offload_scan_manager_->startScan(
    225       pno_settings.interval_ms_,
    226       // TODO: honor both rssi thresholds.
    227       pno_settings.min_5g_rssi_, scan_ssids, match_ssids, match_security, freqs,
    228       &reason_code);
    229   if (pno_scan_running_over_offload_) {
    230     LOG(VERBOSE) << "Pno scans requested over Offload HAL";
    231     if (pno_scan_event_handler_ != nullptr) {
    232       pno_scan_event_handler_->OnPnoScanOverOffloadStarted();
    233     }
    234   }
    235   return pno_scan_running_over_offload_;
    236 }
    237 
    238 void ScannerImpl::ParsePnoSettings(const PnoSettings& pno_settings,
    239                                    vector<vector<uint8_t>>* scan_ssids,
    240                                    vector<vector<uint8_t>>* match_ssids,
    241                                    vector<uint32_t>* freqs,
    242                                    vector<uint8_t>* match_security) {
    243   // TODO provide actionable security match parameters
    244   const uint8_t kNetworkFlagsDefault = 0;
    245   vector<vector<uint8_t>> skipped_scan_ssids;
    246   vector<vector<uint8_t>> skipped_match_ssids;
    247   for (auto& network : pno_settings.pno_networks_) {
    248     // Add hidden network ssid.
    249     if (network.is_hidden_) {
    250       // TODO remove pruning for Offload Scans
    251       if (scan_ssids->size() + 1 >
    252           scan_capabilities_.max_num_sched_scan_ssids) {
    253         skipped_scan_ssids.emplace_back(network.ssid_);
    254         continue;
    255       }
    256       scan_ssids->push_back(network.ssid_);
    257     }
    258 
    259     if (match_ssids->size() + 1 > scan_capabilities_.max_match_sets) {
    260       skipped_match_ssids.emplace_back(network.ssid_);
    261       continue;
    262     }
    263     match_ssids->push_back(network.ssid_);
    264     match_security->push_back(kNetworkFlagsDefault);
    265   }
    266 
    267   LogSsidList(skipped_scan_ssids, "Skip scan ssid for pno scan");
    268   LogSsidList(skipped_match_ssids, "Skip match ssid for pno scan");
    269 }
    270 
    271 bool ScannerImpl::StartPnoScanDefault(const PnoSettings& pno_settings) {
    272   if (!CheckIsValid()) {
    273     return false;
    274   }
    275   if (pno_scan_started_) {
    276     LOG(WARNING) << "Pno scan already started";
    277   }
    278   // An empty ssid for a wild card scan.
    279   vector<vector<uint8_t>> scan_ssids = {{}};
    280   vector<vector<uint8_t>> match_ssids;
    281   vector<uint8_t> unused;
    282   // Empty frequency list: scan all frequencies.
    283   vector<uint32_t> freqs;
    284 
    285   ParsePnoSettings(pno_settings, &scan_ssids, &match_ssids, &freqs, &unused);
    286   // Only request MAC address randomization when station is not associated.
    287   bool request_random_mac = wiphy_features_.supports_random_mac_sched_scan &&
    288       !client_interface_->IsAssociated();
    289   // Always request a low power scan for PNO, if device supports it.
    290   bool request_low_power = wiphy_features_.supports_low_power_oneshot_scan;
    291 
    292   int error_code = 0;
    293   if (!scan_utils_->StartScheduledScan(interface_index_,
    294                                        GenerateIntervalSetting(pno_settings),
    295                                        pno_settings.min_2g_rssi_,
    296                                        pno_settings.min_5g_rssi_,
    297                                        request_random_mac,
    298                                        request_low_power,
    299                                        scan_ssids,
    300                                        match_ssids,
    301                                        freqs,
    302                                        &error_code)) {
    303     LOG(ERROR) << "Failed to start pno scan";
    304     CHECK(error_code != ENODEV) << "Driver is in a bad state, restarting wificond";
    305     return false;
    306   }
    307   LOG(INFO) << "Pno scan started";
    308   pno_scan_started_ = true;
    309   return true;
    310 }
    311 
    312 Status ScannerImpl::stopPnoScan(bool* out_success) {
    313   if (offload_scan_supported_ && StopPnoScanOffload()) {
    314     // Pno scans over offload stopped successfully
    315     *out_success = true;
    316   } else {
    317     // Pno scans were not requested over offload
    318     *out_success = StopPnoScanDefault();
    319   }
    320   return Status::ok();
    321 }
    322 
    323 bool ScannerImpl::StopPnoScanOffload() {
    324   OffloadScanManager::ReasonCode reason_code;
    325   if (!pno_scan_running_over_offload_) {
    326     return false;
    327   }
    328   if (!offload_scan_manager_->stopScan(&reason_code)) {
    329     LOG(WARNING) << "Unable to unsubscribe to Offload scan results";
    330   }
    331   pno_scan_running_over_offload_ = false;
    332   LOG(VERBOSE) << "Pno scans over Offload stopped";
    333   return true;
    334 }
    335 
    336 bool ScannerImpl::StopPnoScanDefault() {
    337   if (!CheckIsValid()) {
    338     return false;
    339   }
    340 
    341   if (!pno_scan_started_) {
    342     LOG(WARNING) << "No pno scan started";
    343   }
    344   if (!scan_utils_->StopScheduledScan(interface_index_)) {
    345     return false;
    346   }
    347   LOG(INFO) << "Pno scan stopped";
    348   pno_scan_started_ = false;
    349   return true;
    350 }
    351 
    352 Status ScannerImpl::abortScan() {
    353   if (!CheckIsValid()) {
    354     return Status::ok();
    355   }
    356 
    357   if (!scan_started_) {
    358     LOG(WARNING) << "Scan is not started. Ignore abort request";
    359     return Status::ok();
    360   }
    361   if (!scan_utils_->AbortScan(interface_index_)) {
    362     LOG(WARNING) << "Abort scan failed";
    363   }
    364   return Status::ok();
    365 }
    366 
    367 Status ScannerImpl::subscribeScanEvents(const sp<IScanEvent>& handler) {
    368   if (!CheckIsValid()) {
    369     return Status::ok();
    370   }
    371 
    372   if (scan_event_handler_ != nullptr) {
    373     LOG(ERROR) << "Found existing scan events subscriber."
    374                << " This subscription request will unsubscribe it";
    375   }
    376   scan_event_handler_ = handler;
    377   return Status::ok();
    378 }
    379 
    380 Status ScannerImpl::unsubscribeScanEvents() {
    381   scan_event_handler_ = nullptr;
    382   return Status::ok();
    383 }
    384 
    385 Status ScannerImpl::subscribePnoScanEvents(const sp<IPnoScanEvent>& handler) {
    386   if (!CheckIsValid()) {
    387     return Status::ok();
    388   }
    389 
    390   if (pno_scan_event_handler_ != nullptr) {
    391     LOG(ERROR) << "Found existing pno scan events subscriber."
    392                << " This subscription request will unsubscribe it";
    393   }
    394   pno_scan_event_handler_ = handler;
    395 
    396   return Status::ok();
    397 }
    398 
    399 Status ScannerImpl::unsubscribePnoScanEvents() {
    400   pno_scan_event_handler_ = nullptr;
    401   return Status::ok();
    402 }
    403 
    404 void ScannerImpl::OnScanResultsReady(uint32_t interface_index, bool aborted,
    405                                      vector<vector<uint8_t>>& ssids,
    406                                      vector<uint32_t>& frequencies) {
    407   if (!scan_started_) {
    408     LOG(INFO) << "Received external scan result notification from kernel.";
    409   }
    410   scan_started_ = false;
    411   if (scan_event_handler_ != nullptr) {
    412     // TODO: Pass other parameters back once we find framework needs them.
    413     if (aborted) {
    414       LOG(WARNING) << "Scan aborted";
    415       scan_event_handler_->OnScanFailed();
    416     } else {
    417       scan_event_handler_->OnScanResultReady();
    418     }
    419   } else {
    420     LOG(WARNING) << "No scan event handler found.";
    421   }
    422 }
    423 
    424 void ScannerImpl::OnSchedScanResultsReady(uint32_t interface_index,
    425                                           bool scan_stopped) {
    426   if (pno_scan_event_handler_ != nullptr) {
    427     if (scan_stopped) {
    428       // If |pno_scan_started_| is false.
    429       // This stop notification might result from our own request.
    430       // See the document for NL80211_CMD_SCHED_SCAN_STOPPED in nl80211.h.
    431       if (pno_scan_started_) {
    432         LOG(WARNING) << "Unexpected pno scan stopped event";
    433         pno_scan_event_handler_->OnPnoScanFailed();
    434       }
    435       pno_scan_started_ = false;
    436     } else {
    437       LOG(INFO) << "Pno scan result ready event";
    438       pno_scan_results_from_offload_ = false;
    439       pno_scan_event_handler_->OnPnoNetworkFound();
    440     }
    441   }
    442 }
    443 
    444 SchedScanIntervalSetting ScannerImpl::GenerateIntervalSetting(
    445     const ::com::android::server::wifi::wificond::PnoSettings&
    446         pno_settings) const {
    447   bool support_num_scan_plans = scan_capabilities_.max_num_scan_plans >= 2;
    448   bool support_scan_plan_interval =
    449       scan_capabilities_.max_scan_plan_interval * 1000 >=
    450           pno_settings.interval_ms_ * PnoSettings::kSlowScanIntervalMultiplier;
    451   bool support_scan_plan_iterations =
    452       scan_capabilities_.max_scan_plan_iterations >=
    453                   PnoSettings::kFastScanIterations;
    454 
    455   uint32_t fast_scan_interval =
    456       static_cast<uint32_t>(pno_settings.interval_ms_);
    457   if (support_num_scan_plans && support_scan_plan_interval &&
    458       support_scan_plan_iterations) {
    459     return SchedScanIntervalSetting{
    460         {{fast_scan_interval, PnoSettings::kFastScanIterations}},
    461         fast_scan_interval * PnoSettings::kSlowScanIntervalMultiplier};
    462   } else {
    463     // Device doesn't support the provided scan plans.
    464     // Specify single interval instead.
    465     // In this case, the driver/firmware is expected to implement back off
    466     // logic internally using |pno_settings.interval_ms_| as "fast scan"
    467     // interval.
    468     return SchedScanIntervalSetting{{}, fast_scan_interval};
    469   }
    470 }
    471 
    472 void ScannerImpl::OnOffloadScanResult() {
    473   if (!pno_scan_running_over_offload_) {
    474     LOG(WARNING) << "Scan results from Offload HAL but scan not requested over "
    475                     "this interface";
    476     return;
    477   }
    478   LOG(INFO) << "Offload Scan results received";
    479   pno_scan_results_from_offload_ = true;
    480   if (pno_scan_event_handler_ != nullptr) {
    481     pno_scan_event_handler_->OnPnoNetworkFound();
    482   } else {
    483     LOG(WARNING) << "No scan event handler Offload Scan result";
    484   }
    485 }
    486 
    487 void ScannerImpl::OnOffloadError(
    488     OffloadScanCallbackInterface::AsyncErrorReason error_code) {
    489   if (!pno_scan_running_over_offload_) {
    490     // Ignore irrelevant error notifications
    491     LOG(WARNING) << "Offload HAL Async Error occured but Offload HAL is not "
    492                     "subscribed to";
    493     return;
    494   }
    495   LOG(ERROR) << "Offload Service Async Failure error_code=" << error_code;
    496   switch (error_code) {
    497     case OffloadScanCallbackInterface::AsyncErrorReason::BINDER_DEATH:
    498       LOG(ERROR) << "Binder death";
    499       if (pno_scan_event_handler_ != nullptr) {
    500         pno_scan_event_handler_->OnPnoScanOverOffloadFailed(
    501             net::wifi::IPnoScanEvent::PNO_SCAN_OVER_OFFLOAD_BINDER_FAILURE);
    502       }
    503       break;
    504     case OffloadScanCallbackInterface::AsyncErrorReason::REMOTE_FAILURE:
    505       LOG(ERROR) << "Remote failure";
    506       if (pno_scan_event_handler_ != nullptr) {
    507         pno_scan_event_handler_->OnPnoScanOverOffloadFailed(
    508             net::wifi::IPnoScanEvent::PNO_SCAN_OVER_OFFLOAD_REMOTE_FAILURE);
    509       }
    510       break;
    511     default:
    512       LOG(WARNING) << "Invalid Error code";
    513       break;
    514   }
    515   bool success = false;
    516   // Stop scans over Offload HAL and request them over netlink
    517   stopPnoScan(&success);
    518   if (success) {
    519     LOG(INFO) << "Pno scans stopped";
    520   }
    521   // Restart PNO scans over netlink interface
    522   success = StartPnoScanDefault(pno_settings_);
    523   if (success) {
    524     LOG(INFO) << "Pno scans restarted";
    525   } else {
    526     LOG(ERROR) << "Unable to fall back to netlink pno scan";
    527     pno_scan_event_handler_->OnPnoScanFailed();
    528   }
    529 }
    530 
    531 void ScannerImpl::LogSsidList(vector<vector<uint8_t>>& ssid_list,
    532                               string prefix) {
    533   if (ssid_list.empty()) {
    534     return;
    535   }
    536   string ssid_list_string;
    537   for (auto& ssid : ssid_list) {
    538     ssid_list_string += string(ssid.begin(), ssid.end());
    539     if (&ssid != &ssid_list.back()) {
    540       ssid_list_string += ", ";
    541     }
    542   }
    543   LOG(WARNING) << prefix << ": " << ssid_list_string;
    544 }
    545 
    546 }  // namespace wificond
    547 }  // namespace android
    548