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