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