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
scan(const SingleScanSettings & scan_settings,bool * out_success)137 Status ScannerImpl::scan(const SingleScanSettings& scan_settings,
138 bool* out_success) {
139 if (!CheckIsValid()) {
140 *out_success = false;
141 return Status::ok();
142 }
143
144 if (scan_started_) {
145 LOG(WARNING) << "Scan already started";
146 }
147 // Only request MAC address randomization when station is not associated.
148 bool request_random_mac =
149 wiphy_features_.supports_random_mac_oneshot_scan &&
150 !client_interface_->IsAssociated();
151 int scan_type = scan_settings.scan_type_;
152 if (!IsScanTypeSupported(scan_settings.scan_type_, wiphy_features_)) {
153 LOG(DEBUG) << "Ignoring scan type because device does not support it";
154 scan_type = SCAN_TYPE_DEFAULT;
155 }
156
157 // Initialize it with an empty ssid for a wild card scan.
158 vector<vector<uint8_t>> ssids = {{}};
159
160 vector<vector<uint8_t>> skipped_scan_ssids;
161 vector<vector<uint8_t>> skipped_long_ssids;
162 for (auto& network : scan_settings.hidden_networks_) {
163 if (ssids.size() + 1 > scan_capabilities_.max_num_scan_ssids) {
164 skipped_scan_ssids.emplace_back(network.ssid_);
165 continue;
166 }
167 if (network.ssid_.size() > 32) {
168 skipped_long_ssids.emplace_back(network.ssid_);
169 continue;
170 }
171 ssids.push_back(network.ssid_);
172 }
173
174 LogSsidList(skipped_scan_ssids, "Skip scan ssid for single scan");
175 LogSsidList(skipped_long_ssids, "Skip too long ssid");
176
177 vector<uint32_t> freqs;
178 for (auto& channel : scan_settings.channel_settings_) {
179 freqs.push_back(channel.frequency_);
180 }
181
182 int error_code = 0;
183 if (!scan_utils_->Scan(interface_index_, request_random_mac, scan_type,
184 scan_settings.enable_6ghz_rnr_, ssids, freqs, &error_code)) {
185 if (error_code == ENODEV) {
186 nodev_counter_ ++;
187 LOG(WARNING) << "Scan failed with error=nodev. counter=" << nodev_counter_;
188 }
189 CHECK(error_code != ENODEV || nodev_counter_ <= 3)
190 << "Driver is in a bad state, restarting wificond";
191 *out_success = false;
192 return Status::ok();
193 }
194 nodev_counter_ = 0;
195 scan_started_ = true;
196 *out_success = true;
197 return Status::ok();
198 }
199
startPnoScan(const PnoSettings & pno_settings,bool * out_success)200 Status ScannerImpl::startPnoScan(const PnoSettings& pno_settings,
201 bool* out_success) {
202 pno_settings_ = pno_settings;
203 LOG(VERBOSE) << "startPnoScan";
204 *out_success = StartPnoScanDefault(pno_settings);
205 return Status::ok();
206 }
207
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)208 void ScannerImpl::ParsePnoSettings(const PnoSettings& pno_settings,
209 vector<vector<uint8_t>>* scan_ssids,
210 vector<vector<uint8_t>>* match_ssids,
211 vector<uint32_t>* freqs,
212 vector<uint8_t>* match_security) {
213 // TODO provide actionable security match parameters
214 const uint8_t kNetworkFlagsDefault = 0;
215 vector<vector<uint8_t>> skipped_scan_ssids;
216 vector<vector<uint8_t>> skipped_match_ssids;
217 std::set<int32_t> unique_frequencies;
218 int num_networks_no_freqs = 0;
219 for (auto& network : pno_settings.pno_networks_) {
220 // Add hidden network ssid.
221 if (network.is_hidden_) {
222 if (scan_ssids->size() + 1 >
223 scan_capabilities_.max_num_sched_scan_ssids) {
224 skipped_scan_ssids.emplace_back(network.ssid_);
225 continue;
226 }
227 scan_ssids->push_back(network.ssid_);
228 }
229
230 if (match_ssids->size() + 1 > scan_capabilities_.max_match_sets) {
231 skipped_match_ssids.emplace_back(network.ssid_);
232 continue;
233 }
234 match_ssids->push_back(network.ssid_);
235 match_security->push_back(kNetworkFlagsDefault);
236
237 // build the set of unique frequencies to scan for.
238 for (const auto& frequency : network.frequencies_) {
239 unique_frequencies.insert(frequency);
240 }
241 if (network.frequencies_.empty()) {
242 num_networks_no_freqs++;
243 }
244 }
245
246 // Also scan the default frequencies if there is frequency data passed down but more than 30% of
247 // networks don't have frequency data.
248 if (unique_frequencies.size() > 0 && num_networks_no_freqs * 100 / match_ssids->size()
249 > kPercentNetworksWithFreq) {
250 // Filter out frequencies not supported by chip.
251 const auto band_2g = client_interface_->GetBandInfo().band_2g;
252 for (const auto frequency : kPnoScanDefaultFreqs2G) {
253 if (std::find(band_2g.begin(), band_2g.end(), frequency) != band_2g.end()) {
254 unique_frequencies.insert(frequency);
255 }
256 }
257 // Note: kPnoScanDefaultFreqs5G doesn't contain DFS frequencies.
258 const auto band_5g = client_interface_->GetBandInfo().band_5g;
259 for (const auto frequency : kPnoScanDefaultFreqs5G) {
260 if (std::find(band_5g.begin(), band_5g.end(), frequency) != band_5g.end()) {
261 unique_frequencies.insert(frequency);
262 }
263 }
264 }
265 for (const auto& frequency : unique_frequencies) {
266 freqs->push_back(frequency);
267 }
268 LogSsidList(skipped_scan_ssids, "Skip scan ssid for pno scan");
269 LogSsidList(skipped_match_ssids, "Skip match ssid for pno scan");
270 }
271
StartPnoScanDefault(const PnoSettings & pno_settings)272 bool ScannerImpl::StartPnoScanDefault(const PnoSettings& pno_settings) {
273 if (!CheckIsValid()) {
274 return false;
275 }
276 if (pno_scan_started_) {
277 LOG(WARNING) << "Pno scan already started";
278 }
279 // An empty ssid for a wild card scan.
280 vector<vector<uint8_t>> scan_ssids = {{}};
281 vector<vector<uint8_t>> match_ssids;
282 vector<uint8_t> unused;
283 // Empty frequency list: scan all frequencies.
284 vector<uint32_t> freqs;
285
286 ParsePnoSettings(pno_settings, &scan_ssids, &match_ssids, &freqs, &unused);
287 // Only request MAC address randomization when station is not associated.
288 bool request_random_mac = wiphy_features_.supports_random_mac_sched_scan &&
289 !client_interface_->IsAssociated();
290 // Always request a low power scan for PNO, if device supports it.
291 bool request_low_power = wiphy_features_.supports_low_power_oneshot_scan;
292
293 bool request_sched_scan_relative_rssi = wiphy_features_.supports_ext_sched_scan_relative_rssi;
294
295 int error_code = 0;
296 struct SchedScanReqFlags req_flags = {};
297 req_flags.request_random_mac = request_random_mac;
298 req_flags.request_low_power = request_low_power;
299 req_flags.request_sched_scan_relative_rssi = request_sched_scan_relative_rssi;
300 if (!scan_utils_->StartScheduledScan(interface_index_,
301 GenerateIntervalSetting(pno_settings),
302 pno_settings.min_2g_rssi_,
303 pno_settings.min_5g_rssi_,
304 pno_settings.min_6g_rssi_,
305 req_flags,
306 scan_ssids,
307 match_ssids,
308 freqs,
309 &error_code)) {
310 if (error_code == ENODEV) {
311 nodev_counter_ ++;
312 LOG(WARNING) << "Pno Scan failed with error=nodev. counter=" << nodev_counter_;
313 }
314 LOG(ERROR) << "Failed to start pno scan";
315 CHECK(error_code != ENODEV || nodev_counter_ <= 3)
316 << "Driver is in a bad state, restarting wificond";
317 return false;
318 }
319 string freq_string;
320 if (freqs.empty()) {
321 freq_string = "for all supported frequencies";
322 } else {
323 freq_string = "for frequencies: ";
324 for (uint32_t f : freqs) {
325 freq_string += std::to_string(f) + ", ";
326 }
327 }
328 LOG(INFO) << "Pno scan started " << freq_string;
329 nodev_counter_ = 0;
330 pno_scan_started_ = true;
331 return true;
332 }
333
stopPnoScan(bool * out_success)334 Status ScannerImpl::stopPnoScan(bool* out_success) {
335 *out_success = StopPnoScanDefault();
336 return Status::ok();
337 }
338
StopPnoScanDefault()339 bool ScannerImpl::StopPnoScanDefault() {
340 if (!CheckIsValid()) {
341 return false;
342 }
343
344 if (!pno_scan_started_) {
345 LOG(WARNING) << "No pno scan started";
346 }
347 if (!scan_utils_->StopScheduledScan(interface_index_)) {
348 return false;
349 }
350 LOG(INFO) << "Pno scan stopped";
351 pno_scan_started_ = false;
352 return true;
353 }
354
abortScan()355 Status ScannerImpl::abortScan() {
356 if (!CheckIsValid()) {
357 return Status::ok();
358 }
359
360 if (!scan_started_) {
361 LOG(WARNING) << "Scan is not started. Ignore abort request";
362 return Status::ok();
363 }
364 if (!scan_utils_->AbortScan(interface_index_)) {
365 LOG(WARNING) << "Abort scan failed";
366 }
367 return Status::ok();
368 }
369
subscribeScanEvents(const sp<IScanEvent> & handler)370 Status ScannerImpl::subscribeScanEvents(const sp<IScanEvent>& handler) {
371 if (!CheckIsValid()) {
372 return Status::ok();
373 }
374
375 if (scan_event_handler_ != nullptr) {
376 LOG(ERROR) << "Found existing scan events subscriber."
377 << " This subscription request will unsubscribe it";
378 }
379 scan_event_handler_ = handler;
380 return Status::ok();
381 }
382
unsubscribeScanEvents()383 Status ScannerImpl::unsubscribeScanEvents() {
384 scan_event_handler_ = nullptr;
385 return Status::ok();
386 }
387
subscribePnoScanEvents(const sp<IPnoScanEvent> & handler)388 Status ScannerImpl::subscribePnoScanEvents(const sp<IPnoScanEvent>& handler) {
389 if (!CheckIsValid()) {
390 return Status::ok();
391 }
392
393 if (pno_scan_event_handler_ != nullptr) {
394 LOG(ERROR) << "Found existing pno scan events subscriber."
395 << " This subscription request will unsubscribe it";
396 }
397 pno_scan_event_handler_ = handler;
398
399 return Status::ok();
400 }
401
unsubscribePnoScanEvents()402 Status ScannerImpl::unsubscribePnoScanEvents() {
403 pno_scan_event_handler_ = nullptr;
404 return Status::ok();
405 }
406
OnScanResultsReady(uint32_t interface_index,bool aborted,vector<vector<uint8_t>> & ssids,vector<uint32_t> & frequencies)407 void ScannerImpl::OnScanResultsReady(uint32_t interface_index, bool aborted,
408 vector<vector<uint8_t>>& ssids,
409 vector<uint32_t>& frequencies) {
410 if (!scan_started_) {
411 LOG(INFO) << "Received external scan result notification from kernel.";
412 }
413 scan_started_ = false;
414 if (scan_event_handler_ != nullptr) {
415 // TODO: Pass other parameters back once we find framework needs them.
416 if (aborted) {
417 LOG(WARNING) << "Scan aborted";
418 scan_event_handler_->OnScanFailed();
419 } else {
420 scan_event_handler_->OnScanResultReady();
421 }
422 } else {
423 LOG(WARNING) << "No scan event handler found.";
424 }
425 }
426
OnSchedScanResultsReady(uint32_t interface_index,bool scan_stopped)427 void ScannerImpl::OnSchedScanResultsReady(uint32_t interface_index,
428 bool scan_stopped) {
429 if (pno_scan_event_handler_ != nullptr) {
430 if (scan_stopped) {
431 // If |pno_scan_started_| is false.
432 // This stop notification might result from our own request.
433 // See the document for NL80211_CMD_SCHED_SCAN_STOPPED in nl80211.h.
434 if (pno_scan_started_) {
435 LOG(WARNING) << "Unexpected pno scan stopped event";
436 pno_scan_event_handler_->OnPnoScanFailed();
437 }
438 pno_scan_started_ = false;
439 } else {
440 LOG(INFO) << "Pno scan result ready event";
441 pno_scan_event_handler_->OnPnoNetworkFound();
442 }
443 }
444 }
445
GenerateIntervalSetting(const android::net::wifi::nl80211::PnoSettings & pno_settings) const446 SchedScanIntervalSetting ScannerImpl::GenerateIntervalSetting(
447 const android::net::wifi::nl80211::PnoSettings&
448 pno_settings) const {
449 bool support_num_scan_plans = scan_capabilities_.max_num_scan_plans >= 2;
450 bool support_scan_plan_interval =
451 scan_capabilities_.max_scan_plan_interval * 1000 >=
452 pno_settings.interval_ms_ * PnoSettings::kSlowScanIntervalMultiplier;
453 bool support_scan_plan_iterations =
454 scan_capabilities_.max_scan_plan_iterations >=
455 PnoSettings::kFastScanIterations;
456
457 uint32_t fast_scan_interval =
458 static_cast<uint32_t>(pno_settings.interval_ms_);
459 if (support_num_scan_plans && support_scan_plan_interval &&
460 support_scan_plan_iterations) {
461 return SchedScanIntervalSetting{
462 {{fast_scan_interval, PnoSettings::kFastScanIterations}},
463 fast_scan_interval * PnoSettings::kSlowScanIntervalMultiplier};
464 } else {
465 // Device doesn't support the provided scan plans.
466 // Specify single interval instead.
467 // In this case, the driver/firmware is expected to implement back off
468 // logic internally using |pno_settings.interval_ms_| as "fast scan"
469 // interval.
470 return SchedScanIntervalSetting{{}, fast_scan_interval};
471 }
472 }
473
LogSsidList(vector<vector<uint8_t>> & ssid_list,string prefix)474 void ScannerImpl::LogSsidList(vector<vector<uint8_t>>& ssid_list,
475 string prefix) {
476 if (ssid_list.empty()) {
477 return;
478 }
479 string ssid_list_string;
480 for (auto& ssid : ssid_list) {
481 ssid_list_string += string(ssid.begin(), ssid.end());
482 if (&ssid != &ssid_list.back()) {
483 ssid_list_string += ", ";
484 }
485 }
486 LOG(WARNING) << prefix << ": " << ssid_list_string;
487 }
488
489 } // namespace wificond
490 } // namespace android
491