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 <set>
20 #include <string>
21 #include <vector>
22 
23 #include <android-base/logging.h>
24 
25 #include "wificond/client_interface_impl.h"
26 #include "wificond/scanning/scan_utils.h"
27 
28 using android::binder::Status;
29 using android::sp;
30 using android::net::wifi::nl80211::IPnoScanEvent;
31 using android::net::wifi::nl80211::IScanEvent;
32 using android::net::wifi::nl80211::IWifiScannerImpl;
33 using android::net::wifi::nl80211::NativeScanResult;
34 using android::net::wifi::nl80211::PnoSettings;
35 using android::net::wifi::nl80211::SingleScanSettings;
36 
37 using std::string;
38 using std::vector;
39 using std::weak_ptr;
40 using std::shared_ptr;
41 
42 using namespace std::placeholders;
43 
44 namespace {
45 using android::wificond::WiphyFeatures;
IsScanTypeSupported(int scan_type,const WiphyFeatures & wiphy_features)46 bool IsScanTypeSupported(int scan_type, const WiphyFeatures& wiphy_features) {
47   switch(scan_type) {
48     case IWifiScannerImpl::SCAN_TYPE_LOW_SPAN:
49       return wiphy_features.supports_low_span_oneshot_scan;
50     case IWifiScannerImpl::SCAN_TYPE_LOW_POWER:
51       return wiphy_features.supports_low_power_oneshot_scan;
52     case IWifiScannerImpl::SCAN_TYPE_HIGH_ACCURACY:
53       return wiphy_features.supports_high_accuracy_oneshot_scan;
54     default:
55       CHECK(0) << "Invalid scan type received: " << scan_type;
56   }
57   return {};
58 }
59 
convertStdErrNumToScanStatus(int errNum)60 int convertStdErrNumToScanStatus(int errNum) {
61     switch(errNum) {
62     case EINVAL:
63       return IWifiScannerImpl::SCAN_STATUS_FAILED_INVALID_ARGS;
64     case EBUSY:
65       return IWifiScannerImpl::SCAN_STATUS_FAILED_BUSY;
66     case ENODEV:
67       return IWifiScannerImpl::SCAN_STATUS_FAILED_NODEV;
68     default:
69       return IWifiScannerImpl::SCAN_STATUS_FAILED_GENERIC;
70   }
71   return {};
72 }
73 
74 constexpr const int kPercentNetworksWithFreq = 30;
75 constexpr const int32_t kPnoScanDefaultFreqs2G[] = {2412, 2417, 2422, 2427, 2432, 2437, 2447, 2452,
76     2457, 2462};
77 constexpr const int32_t kPnoScanDefaultFreqs5G[] = {5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805};
78 } // namespace
79 
80 namespace android {
81 namespace wificond {
82 
ScannerImpl(uint32_t interface_index,const ScanCapabilities & scan_capabilities,const WiphyFeatures & wiphy_features,ClientInterfaceImpl * client_interface,ScanUtils * scan_utils)83 ScannerImpl::ScannerImpl(uint32_t interface_index,
84                          const ScanCapabilities& scan_capabilities,
85                          const WiphyFeatures& wiphy_features,
86                          ClientInterfaceImpl* client_interface,
87                          ScanUtils* scan_utils)
88     : valid_(true),
89       scan_started_(false),
90       pno_scan_started_(false),
91       nodev_counter_(0),
92       interface_index_(interface_index),
93       scan_capabilities_(scan_capabilities),
94       wiphy_features_(wiphy_features),
95       client_interface_(client_interface),
96       scan_utils_(scan_utils),
97       scan_event_handler_(nullptr) {
98   // Subscribe one-shot scan result notification from kernel.
99   LOG(INFO) << "subscribe scan result for interface with index: "
100             << (int)interface_index_;
101   scan_utils_->SubscribeScanResultNotification(
102       interface_index_,
103       std::bind(&ScannerImpl::OnScanResultsReady, this, _1, _2, _3, _4));
104   // Subscribe scheduled scan result notification from kernel.
105   scan_utils_->SubscribeSchedScanResultNotification(
106       interface_index_,
107       std::bind(&ScannerImpl::OnSchedScanResultsReady,
108                 this,
109                 _1, _2));
110 }
111 
~ScannerImpl()112 ScannerImpl::~ScannerImpl() {}
113 
Invalidate()114 void ScannerImpl::Invalidate() {
115   LOG(INFO) << "Unsubscribe scan result for interface with index: "
116             << (int)interface_index_;
117   scan_utils_->UnsubscribeScanResultNotification(interface_index_);
118   scan_utils_->UnsubscribeSchedScanResultNotification(interface_index_);
119   valid_ = false;
120 }
121 
CheckIsValid()122 bool ScannerImpl::CheckIsValid() {
123   if (!valid_) {
124     LOG(DEBUG) << "Calling on a invalid scanner object."
125                << "Underlying client interface object was destroyed.";
126   }
127   return valid_;
128 }
129 
getScanResults(vector<NativeScanResult> * out_scan_results)130 Status ScannerImpl::getScanResults(vector<NativeScanResult>* out_scan_results) {
131   if (!CheckIsValid()) {
132     return Status::ok();
133   }
134   if (!scan_utils_->GetScanResult(interface_index_, out_scan_results)) {
135     LOG(ERROR) << "Failed to get scan results via NL80211";
136   }
137   return Status::ok();
138 }
139 
getPnoScanResults(vector<NativeScanResult> * out_scan_results)140 Status ScannerImpl::getPnoScanResults(
141     vector<NativeScanResult>* out_scan_results) {
142   if (!CheckIsValid()) {
143     return Status::ok();
144   }
145   if (!scan_utils_->GetScanResult(interface_index_, out_scan_results)) {
146     LOG(ERROR) << "Failed to get scan results via NL80211";
147   }
148   return Status::ok();
149 }
150 
getMaxSsidsPerScan(int32_t * out_max_ssids_per_scan)151 Status ScannerImpl::getMaxSsidsPerScan(int32_t* out_max_ssids_per_scan) {
152   if (!CheckIsValid()) {
153     *out_max_ssids_per_scan = 0;
154     return Status::ok();
155   }
156   *out_max_ssids_per_scan = static_cast<int32_t>(scan_capabilities_.max_num_scan_ssids);
157   return Status::ok();
158 }
159 
scanRequest(const SingleScanSettings & scan_settings,int * status)160 Status ScannerImpl::scanRequest(const SingleScanSettings& scan_settings,
161                          int* status) {
162   if (!CheckIsValid()) {
163     *status = IWifiScannerImpl::SCAN_STATUS_FAILED_GENERIC;
164     return Status::ok();
165   }
166 
167   if (scan_started_) {
168     LOG(WARNING) << "Scan already started";
169   }
170   // Only request MAC address randomization when station is not associated.
171   bool request_random_mac =
172       wiphy_features_.supports_random_mac_oneshot_scan &&
173       !client_interface_->IsAssociated();
174   int scan_type = scan_settings.scan_type_;
175   if (!IsScanTypeSupported(scan_settings.scan_type_, wiphy_features_)) {
176     LOG(DEBUG) << "Ignoring scan type because device does not support it";
177     scan_type = SCAN_TYPE_DEFAULT;
178   }
179 
180   // Initialize it with an empty ssid for a wild card scan.
181   vector<vector<uint8_t>> ssids = {{}};
182 
183   vector<vector<uint8_t>> skipped_scan_ssids;
184   vector<vector<uint8_t>> skipped_long_ssids;
185   for (auto& network : scan_settings.hidden_networks_) {
186     if (ssids.size() + 1 > scan_capabilities_.max_num_scan_ssids) {
187       skipped_scan_ssids.emplace_back(network.ssid_);
188       continue;
189     }
190     if (network.ssid_.size() > 32) {
191         skipped_long_ssids.emplace_back(network.ssid_);
192         continue;
193     }
194     ssids.push_back(network.ssid_);
195   }
196 
197   LogSsidList(skipped_scan_ssids, "Skip scan ssid for single scan");
198   LogSsidList(skipped_long_ssids, "Skip too long ssid");
199 
200   vector<uint32_t> freqs;
201   for (auto& channel : scan_settings.channel_settings_) {
202     freqs.push_back(channel.frequency_);
203   }
204 
205   int error_code = 0;
206   if (!scan_utils_->Scan(interface_index_, request_random_mac, scan_type,
207                          scan_settings.enable_6ghz_rnr_, ssids, freqs,
208                          scan_settings.vendor_ies_, &error_code)) {
209     if (error_code == ENODEV) {
210         nodev_counter_ ++;
211         LOG(WARNING) << "Scan failed with error=nodev. counter=" << nodev_counter_;
212     }
213     CHECK(error_code != ENODEV || nodev_counter_ <= 3)
214         << "Driver is in a bad state, restarting wificond";
215     *status = convertStdErrNumToScanStatus(error_code);
216     return Status::ok();
217   }
218   nodev_counter_ = 0;
219   scan_started_ = true;
220   *status = IWifiScannerImpl::SCAN_STATUS_SUCCESS;
221   return Status::ok();
222 
223 }
scan(const SingleScanSettings & scan_settings,bool * out_success)224 Status ScannerImpl::scan(const SingleScanSettings& scan_settings,
225                          bool* out_success) {
226 
227   int status = 0;
228   scanRequest(scan_settings, &status);
229   if (status == IWifiScannerImpl::SCAN_STATUS_SUCCESS) {
230     *out_success = true;
231   } else {
232     *out_success = false;
233   }
234   return Status::ok();
235 }
236 
startPnoScan(const PnoSettings & pno_settings,bool * out_success)237 Status ScannerImpl::startPnoScan(const PnoSettings& pno_settings,
238                                  bool* out_success) {
239   pno_settings_ = pno_settings;
240   LOG(VERBOSE) << "startPnoScan";
241   *out_success = StartPnoScanDefault(pno_settings);
242   return Status::ok();
243 }
244 
ParsePnoSettings(const PnoSettings & pno_settings,vector<vector<uint8_t>> * scan_ssids,vector<vector<uint8_t>> * match_ssids,vector<uint32_t> * freqs,vector<uint8_t> * match_security)245 void ScannerImpl::ParsePnoSettings(const PnoSettings& pno_settings,
246                                    vector<vector<uint8_t>>* scan_ssids,
247                                    vector<vector<uint8_t>>* match_ssids,
248                                    vector<uint32_t>* freqs,
249                                    vector<uint8_t>* match_security) {
250   // TODO provide actionable security match parameters
251   const uint8_t kNetworkFlagsDefault = 0;
252   vector<vector<uint8_t>> skipped_scan_ssids;
253   vector<vector<uint8_t>> skipped_match_ssids;
254   std::set<int32_t> unique_frequencies;
255   int num_networks_no_freqs = 0;
256   // Get the list of supported frequencies
257   const auto band_2g = client_interface_->GetBandInfo().band_2g;
258   const auto band_5g = client_interface_->GetBandInfo().band_5g;
259   const auto band_dfs = client_interface_->GetBandInfo().band_dfs;
260   const auto band_6g = client_interface_->GetBandInfo().band_6g;
261   const auto band_60g = client_interface_->GetBandInfo().band_60g;
262   std::set<uint32_t> all_freqs;
263   all_freqs.insert(band_2g.begin(), band_2g.end());
264   all_freqs.insert(band_5g.begin(), band_5g.end());
265   all_freqs.insert(band_dfs.begin(), band_dfs.end());
266   all_freqs.insert(band_6g.begin(), band_6g.end());
267   all_freqs.insert(band_60g.begin(), band_60g.end());
268   for (auto& network : pno_settings.pno_networks_) {
269     // Add hidden network ssid.
270     if (network.is_hidden_) {
271       if (scan_ssids->size() + 1 >
272           scan_capabilities_.max_num_sched_scan_ssids) {
273         skipped_scan_ssids.emplace_back(network.ssid_);
274         continue;
275       }
276       scan_ssids->push_back(network.ssid_);
277     }
278 
279     if (match_ssids->size() + 1 > scan_capabilities_.max_match_sets) {
280       skipped_match_ssids.emplace_back(network.ssid_);
281       continue;
282     }
283     match_ssids->push_back(network.ssid_);
284     match_security->push_back(kNetworkFlagsDefault);
285 
286     // build the set of unique frequencies to scan for.
287     for (const auto& frequency : network.frequencies_) {
288       if (all_freqs.find(frequency) != all_freqs.end()) {
289         unique_frequencies.insert(frequency);
290       } else {
291         LOG(INFO) << "filtered out invalid frequency " << frequency;
292       }
293     }
294     if (network.frequencies_.empty()) {
295       num_networks_no_freqs++;
296     }
297   }
298 
299   // Also scan the default frequencies if more than kPercentNetworksWithFreq of
300   // networks don't have frequency data.
301   if (num_networks_no_freqs * 100 > kPercentNetworksWithFreq * match_ssids->size()) {
302     // Filter out frequencies not supported by chip.
303     for (const auto frequency : kPnoScanDefaultFreqs2G) {
304       if (std::find(band_2g.begin(), band_2g.end(), frequency) != band_2g.end()) {
305         unique_frequencies.insert(frequency);
306       }
307     }
308     // Note: kPnoScanDefaultFreqs5G doesn't contain DFS frequencies.
309     for (const auto frequency : kPnoScanDefaultFreqs5G) {
310       if (std::find(band_5g.begin(), band_5g.end(), frequency) != band_5g.end()) {
311         unique_frequencies.insert(frequency);
312       }
313     }
314   }
315   for (const auto& frequency : unique_frequencies) {
316     freqs->push_back(frequency);
317   }
318   LogSsidList(skipped_scan_ssids, "Skip scan ssid for pno scan");
319   LogSsidList(skipped_match_ssids, "Skip match ssid for pno scan");
320 }
321 
StartPnoScanDefault(const PnoSettings & pno_settings)322 bool ScannerImpl::StartPnoScanDefault(const PnoSettings& pno_settings) {
323   if (!CheckIsValid()) {
324     return false;
325   }
326   if (pno_scan_started_) {
327     LOG(WARNING) << "Pno scan already started";
328   }
329   // An empty ssid for a wild card scan.
330   vector<vector<uint8_t>> scan_ssids = {{}};
331   vector<vector<uint8_t>> match_ssids;
332   vector<uint8_t> unused;
333   // Empty frequency list: scan all frequencies.
334   vector<uint32_t> freqs;
335 
336   ParsePnoSettings(pno_settings, &scan_ssids, &match_ssids, &freqs, &unused);
337   // Only request MAC address randomization when station is not associated.
338   bool request_random_mac = wiphy_features_.supports_random_mac_sched_scan &&
339       !client_interface_->IsAssociated();
340   // Always request a low power scan for PNO, if device supports it.
341   bool request_low_power = wiphy_features_.supports_low_power_oneshot_scan;
342 
343   bool request_sched_scan_relative_rssi = wiphy_features_.supports_ext_sched_scan_relative_rssi;
344 
345   int error_code = 0;
346   struct SchedScanReqFlags req_flags = {};
347   req_flags.request_random_mac = request_random_mac;
348   req_flags.request_low_power = request_low_power;
349   req_flags.request_sched_scan_relative_rssi = request_sched_scan_relative_rssi;
350   if (!scan_utils_->StartScheduledScan(interface_index_,
351                                        GenerateIntervalSetting(pno_settings),
352                                        pno_settings.min_2g_rssi_,
353                                        pno_settings.min_5g_rssi_,
354                                        pno_settings.min_6g_rssi_,
355                                        req_flags,
356                                        scan_ssids,
357                                        match_ssids,
358                                        freqs,
359                                        &error_code)) {
360     if (error_code == ENODEV) {
361         nodev_counter_ ++;
362         LOG(WARNING) << "Pno Scan failed with error=nodev. counter=" << nodev_counter_;
363     }
364     LOG(ERROR) << "Failed to start pno scan";
365     CHECK(error_code != ENODEV || nodev_counter_ <= 3)
366         << "Driver is in a bad state, restarting wificond";
367     return false;
368   }
369   string freq_string;
370   if (freqs.empty()) {
371     freq_string = "for all supported frequencies";
372   } else {
373     freq_string = "for frequencies: ";
374     for (uint32_t f : freqs) {
375       freq_string += std::to_string(f) + ", ";
376     }
377   }
378   LOG(INFO) << "Pno scan started " << freq_string;
379   nodev_counter_ = 0;
380   pno_scan_started_ = true;
381   return true;
382 }
383 
stopPnoScan(bool * out_success)384 Status ScannerImpl::stopPnoScan(bool* out_success) {
385   *out_success = StopPnoScanDefault();
386   return Status::ok();
387 }
388 
StopPnoScanDefault()389 bool ScannerImpl::StopPnoScanDefault() {
390   if (!CheckIsValid()) {
391     return false;
392   }
393 
394   if (!pno_scan_started_) {
395     LOG(WARNING) << "No pno scan started";
396   }
397   if (!scan_utils_->StopScheduledScan(interface_index_)) {
398     return false;
399   }
400   LOG(INFO) << "Pno scan stopped";
401   pno_scan_started_ = false;
402   return true;
403 }
404 
abortScan()405 Status ScannerImpl::abortScan() {
406   if (!CheckIsValid()) {
407     return Status::ok();
408   }
409 
410   if (!scan_started_) {
411     LOG(WARNING) << "Scan is not started. Ignore abort request";
412     return Status::ok();
413   }
414   if (!scan_utils_->AbortScan(interface_index_)) {
415     LOG(WARNING) << "Abort scan failed";
416   }
417   return Status::ok();
418 }
419 
subscribeScanEvents(const sp<IScanEvent> & handler)420 Status ScannerImpl::subscribeScanEvents(const sp<IScanEvent>& handler) {
421   if (!CheckIsValid()) {
422     return Status::ok();
423   }
424 
425   if (scan_event_handler_ != nullptr) {
426     LOG(ERROR) << "Found existing scan events subscriber."
427                << " This subscription request will unsubscribe it";
428   }
429   scan_event_handler_ = handler;
430   return Status::ok();
431 }
432 
unsubscribeScanEvents()433 Status ScannerImpl::unsubscribeScanEvents() {
434   scan_event_handler_ = nullptr;
435   return Status::ok();
436 }
437 
subscribePnoScanEvents(const sp<IPnoScanEvent> & handler)438 Status ScannerImpl::subscribePnoScanEvents(const sp<IPnoScanEvent>& handler) {
439   if (!CheckIsValid()) {
440     return Status::ok();
441   }
442 
443   if (pno_scan_event_handler_ != nullptr) {
444     LOG(ERROR) << "Found existing pno scan events subscriber."
445                << " This subscription request will unsubscribe it";
446   }
447   pno_scan_event_handler_ = handler;
448 
449   return Status::ok();
450 }
451 
unsubscribePnoScanEvents()452 Status ScannerImpl::unsubscribePnoScanEvents() {
453   pno_scan_event_handler_ = nullptr;
454   return Status::ok();
455 }
456 
OnScanResultsReady(uint32_t interface_index,bool aborted,vector<vector<uint8_t>> & ssids,vector<uint32_t> & frequencies)457 void ScannerImpl::OnScanResultsReady(uint32_t interface_index, bool aborted,
458                                      vector<vector<uint8_t>>& ssids,
459                                      vector<uint32_t>& frequencies) {
460   if (!scan_started_) {
461     LOG(INFO) << "Received external scan result notification from kernel.";
462   }
463   scan_started_ = false;
464   if (scan_event_handler_ != nullptr) {
465     // TODO: Pass other parameters back once we find framework needs them.
466     if (aborted) {
467       LOG(WARNING) << "Scan aborted";
468       scan_event_handler_->OnScanRequestFailed(IWifiScannerImpl::SCAN_STATUS_FAILED_ABORT);
469     } else {
470       scan_event_handler_->OnScanResultReady();
471     }
472   } else {
473     LOG(WARNING) << "No scan event handler found.";
474   }
475 }
476 
OnSchedScanResultsReady(uint32_t interface_index,bool scan_stopped)477 void ScannerImpl::OnSchedScanResultsReady(uint32_t interface_index,
478                                           bool scan_stopped) {
479   if (pno_scan_event_handler_ != nullptr) {
480     if (scan_stopped) {
481       // If |pno_scan_started_| is false.
482       // This stop notification might result from our own request.
483       // See the document for NL80211_CMD_SCHED_SCAN_STOPPED in nl80211.h.
484       if (pno_scan_started_) {
485         LOG(WARNING) << "Unexpected pno scan stopped event";
486         pno_scan_event_handler_->OnPnoScanFailed();
487       }
488       pno_scan_started_ = false;
489     } else {
490       LOG(INFO) << "Pno scan result ready event";
491       pno_scan_event_handler_->OnPnoNetworkFound();
492     }
493   }
494 }
495 
GenerateIntervalSetting(const android::net::wifi::nl80211::PnoSettings & pno_settings) const496 SchedScanIntervalSetting ScannerImpl::GenerateIntervalSetting(
497     const android::net::wifi::nl80211::PnoSettings&
498         pno_settings) const {
499   bool support_num_scan_plans = scan_capabilities_.max_num_scan_plans >= 2;
500   bool support_scan_plan_interval =
501       scan_capabilities_.max_scan_plan_interval * 1000 >=
502           pno_settings.interval_ms_ * pno_settings.scan_interval_multiplier_;
503   bool support_scan_plan_iterations =
504       scan_capabilities_.max_scan_plan_iterations >=
505                   pno_settings.scan_iterations_;
506 
507   uint32_t fast_scan_interval =
508       static_cast<uint32_t>(pno_settings.interval_ms_);
509   if (support_num_scan_plans && support_scan_plan_interval &&
510       support_scan_plan_iterations) {
511     return SchedScanIntervalSetting{
512         {{fast_scan_interval, pno_settings.scan_iterations_}},
513         fast_scan_interval * pno_settings.scan_interval_multiplier_};
514   } else {
515     // Device doesn't support the provided scan plans.
516     // Specify single interval instead.
517     // In this case, the driver/firmware is expected to implement back off
518     // logic internally using |pno_settings.interval_ms_| as "fast scan"
519     // interval.
520     return SchedScanIntervalSetting{{}, fast_scan_interval};
521   }
522 }
523 
LogSsidList(vector<vector<uint8_t>> & ssid_list,string prefix)524 void ScannerImpl::LogSsidList(vector<vector<uint8_t>>& ssid_list,
525                               string prefix) {
526   if (ssid_list.empty()) {
527     return;
528   }
529   string ssid_list_string;
530   for (auto& ssid : ssid_list) {
531     ssid_list_string += string(ssid.begin(), ssid.end());
532     if (&ssid != &ssid_list.back()) {
533       ssid_list_string += ", ";
534     }
535   }
536   LOG(WARNING) << prefix << ": " << ssid_list_string;
537 }
538 
539 }  // namespace wificond
540 }  // namespace android
541