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