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