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/scan_utils.h"
     26 
     27 using android::binder::Status;
     28 using android::net::wifi::IPnoScanEvent;
     29 using android::net::wifi::IScanEvent;
     30 using android::sp;
     31 using com::android::server::wifi::wificond::NativeScanResult;
     32 using com::android::server::wifi::wificond::PnoSettings;
     33 using com::android::server::wifi::wificond::SingleScanSettings;
     34 
     35 using std::string;
     36 using std::vector;
     37 
     38 using namespace std::placeholders;
     39 
     40 namespace android {
     41 namespace wificond {
     42 
     43 ScannerImpl::ScannerImpl(uint32_t wiphy_index,
     44                          uint32_t interface_index,
     45                          const ScanCapabilities& scan_capabilities,
     46                          const WiphyFeatures& wiphy_features,
     47                          ClientInterfaceImpl* client_interface,
     48                          NetlinkUtils* netlink_utils,
     49                          ScanUtils* scan_utils)
     50     : valid_(true),
     51       scan_started_(false),
     52       pno_scan_started_(false),
     53       wiphy_index_(wiphy_index),
     54       interface_index_(interface_index),
     55       scan_capabilities_(scan_capabilities),
     56       wiphy_features_(wiphy_features),
     57       client_interface_(client_interface),
     58       netlink_utils_(netlink_utils),
     59       scan_utils_(scan_utils),
     60       scan_event_handler_(nullptr) {
     61   // Subscribe one-shot scan result notification from kernel.
     62   LOG(INFO) << "subscribe scan result for interface with index: "
     63             << (int)interface_index_;
     64   scan_utils_->SubscribeScanResultNotification(
     65       interface_index_,
     66       std::bind(&ScannerImpl::OnScanResultsReady,
     67                 this,
     68                 _1, _2, _3, _4));
     69   // Subscribe scheduled scan result notification from kernel.
     70   scan_utils_->SubscribeSchedScanResultNotification(
     71       interface_index_,
     72       std::bind(&ScannerImpl::OnSchedScanResultsReady,
     73                 this,
     74                 _1, _2));
     75 }
     76 
     77 ScannerImpl::~ScannerImpl() {
     78 }
     79 
     80 void ScannerImpl::Invalidate() {
     81   LOG(INFO) << "Unsubscribe scan result for interface with index: "
     82             << (int)interface_index_;
     83   scan_utils_->UnsubscribeScanResultNotification(interface_index_);
     84   scan_utils_->UnsubscribeSchedScanResultNotification(interface_index_);
     85 }
     86 
     87 bool ScannerImpl::CheckIsValid() {
     88   if (!valid_) {
     89     LOG(DEBUG) << "Calling on a invalid scanner object."
     90                << "Underlying client interface object was destroyed.";
     91   }
     92   return valid_;
     93 }
     94 
     95 Status ScannerImpl::getAvailable2gChannels(
     96     std::unique_ptr<vector<int32_t>>* out_frequencies) {
     97   if (!CheckIsValid()) {
     98     return Status::ok();
     99   }
    100   BandInfo band_info;
    101   if (!netlink_utils_->GetWiphyInfo(wiphy_index_,
    102                                &band_info,
    103                                &scan_capabilities_,
    104                                &wiphy_features_)) {
    105     LOG(ERROR) << "Failed to get wiphy info from kernel";
    106     out_frequencies->reset(nullptr);
    107     return Status::ok();
    108   }
    109 
    110   out_frequencies->reset(new vector<int32_t>(band_info.band_2g.begin(),
    111                                              band_info.band_2g.end()));
    112   return Status::ok();
    113 }
    114 
    115 Status ScannerImpl::getAvailable5gNonDFSChannels(
    116     std::unique_ptr<vector<int32_t>>* out_frequencies) {
    117   if (!CheckIsValid()) {
    118     return Status::ok();
    119   }
    120   BandInfo band_info;
    121   if (!netlink_utils_->GetWiphyInfo(wiphy_index_,
    122                                &band_info,
    123                                &scan_capabilities_,
    124                                &wiphy_features_)) {
    125     LOG(ERROR) << "Failed to get wiphy info from kernel";
    126     out_frequencies->reset(nullptr);
    127     return Status::ok();
    128   }
    129 
    130   out_frequencies->reset(new vector<int32_t>(band_info.band_5g.begin(),
    131                                              band_info.band_5g.end()));
    132   return Status::ok();
    133 }
    134 
    135 Status ScannerImpl::getAvailableDFSChannels(
    136     std::unique_ptr<vector<int32_t>>* out_frequencies) {
    137   if (!CheckIsValid()) {
    138     return Status::ok();
    139   }
    140   BandInfo band_info;
    141   if (!netlink_utils_->GetWiphyInfo(wiphy_index_,
    142                                &band_info,
    143                                &scan_capabilities_,
    144                                &wiphy_features_)) {
    145     LOG(ERROR) << "Failed to get wiphy info from kernel";
    146     out_frequencies->reset(nullptr);
    147     return Status::ok();
    148   }
    149 
    150   out_frequencies->reset(new vector<int32_t>(band_info.band_dfs.begin(),
    151                                              band_info.band_dfs.end()));
    152   return Status::ok();
    153 }
    154 
    155 Status ScannerImpl::getScanResults(vector<NativeScanResult>* out_scan_results) {
    156   if (!CheckIsValid()) {
    157     return Status::ok();
    158   }
    159   if (!scan_utils_->GetScanResult(interface_index_, out_scan_results)) {
    160     LOG(ERROR) << "Failed to get scan results via NL80211";
    161   }
    162   return Status::ok();
    163 }
    164 
    165 Status ScannerImpl::scan(const SingleScanSettings& scan_settings,
    166                          bool* out_success) {
    167   if (!CheckIsValid()) {
    168     *out_success = false;
    169     return Status::ok();
    170   }
    171 
    172   if (scan_started_) {
    173     LOG(WARNING) << "Scan already started";
    174   }
    175   // Only request MAC address randomization when station is not associated.
    176   bool request_random_mac =  wiphy_features_.supports_random_mac_oneshot_scan &&
    177       !client_interface_->IsAssociated();
    178 
    179   // Initialize it with an empty ssid for a wild card scan.
    180   vector<vector<uint8_t>> ssids = {{}};
    181 
    182   vector<vector<uint8_t>> skipped_scan_ssids;
    183   for (auto& network : scan_settings.hidden_networks_) {
    184     if (ssids.size() + 1 > scan_capabilities_.max_num_scan_ssids) {
    185       skipped_scan_ssids.emplace_back(network.ssid_);
    186       continue;
    187     }
    188     ssids.push_back(network.ssid_);
    189   }
    190 
    191   LogSsidList(skipped_scan_ssids, "Skip scan ssid for single scan");
    192 
    193   vector<uint32_t> freqs;
    194   for (auto& channel : scan_settings.channel_settings_) {
    195     freqs.push_back(channel.frequency_);
    196   }
    197 
    198   if (!scan_utils_->Scan(interface_index_, request_random_mac, ssids, freqs)) {
    199     *out_success = false;
    200     return Status::ok();
    201   }
    202   scan_started_ = true;
    203   *out_success = true;
    204   return Status::ok();
    205 }
    206 
    207 Status ScannerImpl::startPnoScan(const PnoSettings& pno_settings,
    208                                  bool* out_success) {
    209   if (!CheckIsValid()) {
    210     *out_success = false;
    211     return Status::ok();
    212   }
    213   if (pno_scan_started_) {
    214     LOG(WARNING) << "Pno scan already started";
    215   }
    216   // An empty ssid for a wild card scan.
    217   vector<vector<uint8_t>> scan_ssids = {{}};
    218   vector<vector<uint8_t>> match_ssids;
    219   // Empty frequency list: scan all frequencies.
    220   vector<uint32_t> freqs;
    221 
    222   vector<vector<uint8_t>> skipped_scan_ssids;
    223   vector<vector<uint8_t>> skipped_match_ssids;
    224   for (auto& network : pno_settings.pno_networks_) {
    225     // Add hidden network ssid.
    226     if (network.is_hidden_) {
    227       if (scan_ssids.size() + 1 > scan_capabilities_.max_num_sched_scan_ssids) {
    228         skipped_scan_ssids.emplace_back(network.ssid_);
    229         continue;
    230       }
    231       scan_ssids.push_back(network.ssid_);
    232     }
    233 
    234     if (match_ssids.size() + 1 > scan_capabilities_.max_match_sets) {
    235       skipped_match_ssids.emplace_back(network.ssid_);
    236       continue;
    237     }
    238     match_ssids.push_back(network.ssid_);
    239   }
    240 
    241   LogSsidList(skipped_scan_ssids, "Skip scan ssid for pno scan");
    242   LogSsidList(skipped_match_ssids, "Skip match ssid for pno scan");
    243 
    244   // Only request MAC address randomization when station is not associated.
    245   bool request_random_mac = wiphy_features_.supports_random_mac_sched_scan &&
    246       !client_interface_->IsAssociated();
    247 
    248   if (!scan_utils_->StartScheduledScan(interface_index_,
    249                                        pno_settings.interval_ms_,
    250                                        // TODO: honor both rssi thresholds.
    251                                        pno_settings.min_5g_rssi_,
    252                                        request_random_mac,
    253                                        scan_ssids,
    254                                        match_ssids,
    255                                        freqs)) {
    256     *out_success = false;
    257     LOG(ERROR) << "Failed to start pno scan";
    258     return Status::ok();
    259   }
    260   LOG(INFO) << "Pno scan started";
    261   pno_scan_started_ = true;
    262   *out_success = true;
    263   return Status::ok();
    264 }
    265 
    266 Status ScannerImpl::stopPnoScan(bool* out_success) {
    267   if (!CheckIsValid()) {
    268     *out_success = false;
    269     return Status::ok();
    270   }
    271 
    272   if (!pno_scan_started_) {
    273     LOG(WARNING) << "No pno scan started";
    274   }
    275   if (!scan_utils_->StopScheduledScan(interface_index_)) {
    276     *out_success = false;
    277     return Status::ok();
    278   }
    279   LOG(INFO) << "Pno scan stopped";
    280   pno_scan_started_ = false;
    281   *out_success = true;
    282   return Status::ok();
    283 }
    284 
    285 Status ScannerImpl::abortScan() {
    286   if (!CheckIsValid()) {
    287     return Status::ok();
    288   }
    289 
    290   if (!scan_started_) {
    291     LOG(WARNING) << "Scan is not started. Ignore abort request";
    292     return Status::ok();
    293   }
    294   if (!scan_utils_->AbortScan(interface_index_)) {
    295     LOG(WARNING) << "Abort scan failed";
    296   }
    297   return Status::ok();
    298 }
    299 
    300 Status ScannerImpl::subscribeScanEvents(const sp<IScanEvent>& handler) {
    301   if (!CheckIsValid()) {
    302     return Status::ok();
    303   }
    304 
    305   if (scan_event_handler_ != nullptr) {
    306     LOG(ERROR) << "Found existing scan events subscriber."
    307                << " This subscription request will unsubscribe it";
    308   }
    309   scan_event_handler_ = handler;
    310   return Status::ok();
    311 }
    312 
    313 Status ScannerImpl::unsubscribeScanEvents() {
    314   scan_event_handler_ = nullptr;
    315   return Status::ok();
    316 }
    317 
    318 
    319 Status ScannerImpl::subscribePnoScanEvents(const sp<IPnoScanEvent>& handler) {
    320   if (!CheckIsValid()) {
    321     return Status::ok();
    322   }
    323 
    324   if (pno_scan_event_handler_ != nullptr) {
    325     LOG(ERROR) << "Found existing pno scan events subscriber."
    326                << " This subscription request will unsubscribe it";
    327   }
    328   pno_scan_event_handler_ = handler;
    329 
    330   return Status::ok();
    331 }
    332 
    333 Status ScannerImpl::unsubscribePnoScanEvents() {
    334   pno_scan_event_handler_ = nullptr;
    335   return Status::ok();
    336 }
    337 
    338 void ScannerImpl::OnScanResultsReady(
    339     uint32_t interface_index,
    340     bool aborted,
    341     vector<vector<uint8_t>>& ssids,
    342     vector<uint32_t>& frequencies) {
    343   if (!scan_started_) {
    344     LOG(INFO) << "Received external scan result notification from kernel.";
    345   }
    346   scan_started_ = false;
    347   if (scan_event_handler_ != nullptr) {
    348     // TODO: Pass other parameters back once we find framework needs them.
    349     if (aborted) {
    350       LOG(WARNING) << "Scan aborted";
    351       scan_event_handler_->OnScanFailed();
    352     } else {
    353       scan_event_handler_->OnScanResultReady();
    354     }
    355   } else {
    356     LOG(WARNING) << "No scan event handler found.";
    357   }
    358 }
    359 
    360 void ScannerImpl::OnSchedScanResultsReady(uint32_t interface_index,
    361                                           bool scan_stopped) {
    362   if (pno_scan_event_handler_ != nullptr) {
    363     if (scan_stopped) {
    364       // If |pno_scan_started_| is false.
    365       // This stop notification might result from our own request.
    366       // See the document for NL80211_CMD_SCHED_SCAN_STOPPED in nl80211.h.
    367       if (pno_scan_started_) {
    368         LOG(WARNING) << "Unexpected pno scan stopped event";
    369         pno_scan_event_handler_->OnPnoScanFailed();
    370       }
    371       pno_scan_started_ = false;
    372     } else {
    373       LOG(INFO) << "Pno scan result ready event";
    374       pno_scan_event_handler_->OnPnoNetworkFound();
    375     }
    376   }
    377 }
    378 
    379 void ScannerImpl::LogSsidList(vector<vector<uint8_t>>& ssid_list,
    380                               string prefix) {
    381   if (ssid_list.empty()) {
    382     return;
    383   }
    384   string ssid_list_string;
    385   for (auto& ssid : ssid_list) {
    386     ssid_list_string += string(ssid.begin(), ssid.end());
    387     if (&ssid != &ssid_list.back()) {
    388       ssid_list_string += ", ";
    389     }
    390   }
    391   LOG(WARNING) << prefix << ": " << ssid_list_string;
    392 }
    393 
    394 }  // namespace wificond
    395 }  // namespace android
    396