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