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