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 <string>
20 #include <vector>
21
22 #include <android-base/logging.h>
23
24 #include "wificond/client_interface_impl.h"
25 #include "wificond/scanning/scan_utils.h"
26
27 using android::binder::Status;
28 using android::net::wifi::IPnoScanEvent;
29 using android::net::wifi::IScanEvent;
30 using android::sp;
31 using com::android::server::wifi::wificond::NativeScanResult;
32 using com::android::server::wifi::wificond::PnoSettings;
33 using com::android::server::wifi::wificond::SingleScanSettings;
34
35 using std::string;
36 using std::vector;
37
38 using namespace std::placeholders;
39
40 namespace android {
41 namespace wificond {
42
ScannerImpl(uint32_t wiphy_index,uint32_t interface_index,const ScanCapabilities & scan_capabilities,const WiphyFeatures & wiphy_features,ClientInterfaceImpl * client_interface,NetlinkUtils * netlink_utils,ScanUtils * scan_utils)43 ScannerImpl::ScannerImpl(uint32_t wiphy_index,
44 uint32_t interface_index,
45 const ScanCapabilities& scan_capabilities,
46 const WiphyFeatures& wiphy_features,
47 ClientInterfaceImpl* client_interface,
48 NetlinkUtils* netlink_utils,
49 ScanUtils* scan_utils)
50 : valid_(true),
51 scan_started_(false),
52 pno_scan_started_(false),
53 wiphy_index_(wiphy_index),
54 interface_index_(interface_index),
55 scan_capabilities_(scan_capabilities),
56 wiphy_features_(wiphy_features),
57 client_interface_(client_interface),
58 netlink_utils_(netlink_utils),
59 scan_utils_(scan_utils),
60 scan_event_handler_(nullptr) {
61 // Subscribe one-shot scan result notification from kernel.
62 LOG(INFO) << "subscribe scan result for interface with index: "
63 << (int)interface_index_;
64 scan_utils_->SubscribeScanResultNotification(
65 interface_index_,
66 std::bind(&ScannerImpl::OnScanResultsReady,
67 this,
68 _1, _2, _3, _4));
69 // Subscribe scheduled scan result notification from kernel.
70 scan_utils_->SubscribeSchedScanResultNotification(
71 interface_index_,
72 std::bind(&ScannerImpl::OnSchedScanResultsReady,
73 this,
74 _1, _2));
75 }
76
~ScannerImpl()77 ScannerImpl::~ScannerImpl() {
78 }
79
Invalidate()80 void ScannerImpl::Invalidate() {
81 LOG(INFO) << "Unsubscribe scan result for interface with index: "
82 << (int)interface_index_;
83 scan_utils_->UnsubscribeScanResultNotification(interface_index_);
84 scan_utils_->UnsubscribeSchedScanResultNotification(interface_index_);
85 }
86
CheckIsValid()87 bool ScannerImpl::CheckIsValid() {
88 if (!valid_) {
89 LOG(DEBUG) << "Calling on a invalid scanner object."
90 << "Underlying client interface object was destroyed.";
91 }
92 return valid_;
93 }
94
getAvailable2gChannels(std::unique_ptr<vector<int32_t>> * out_frequencies)95 Status ScannerImpl::getAvailable2gChannels(
96 std::unique_ptr<vector<int32_t>>* out_frequencies) {
97 if (!CheckIsValid()) {
98 return Status::ok();
99 }
100 BandInfo band_info;
101 if (!netlink_utils_->GetWiphyInfo(wiphy_index_,
102 &band_info,
103 &scan_capabilities_,
104 &wiphy_features_)) {
105 LOG(ERROR) << "Failed to get wiphy info from kernel";
106 out_frequencies->reset(nullptr);
107 return Status::ok();
108 }
109
110 out_frequencies->reset(new vector<int32_t>(band_info.band_2g.begin(),
111 band_info.band_2g.end()));
112 return Status::ok();
113 }
114
getAvailable5gNonDFSChannels(std::unique_ptr<vector<int32_t>> * out_frequencies)115 Status ScannerImpl::getAvailable5gNonDFSChannels(
116 std::unique_ptr<vector<int32_t>>* out_frequencies) {
117 if (!CheckIsValid()) {
118 return Status::ok();
119 }
120 BandInfo band_info;
121 if (!netlink_utils_->GetWiphyInfo(wiphy_index_,
122 &band_info,
123 &scan_capabilities_,
124 &wiphy_features_)) {
125 LOG(ERROR) << "Failed to get wiphy info from kernel";
126 out_frequencies->reset(nullptr);
127 return Status::ok();
128 }
129
130 out_frequencies->reset(new vector<int32_t>(band_info.band_5g.begin(),
131 band_info.band_5g.end()));
132 return Status::ok();
133 }
134
getAvailableDFSChannels(std::unique_ptr<vector<int32_t>> * out_frequencies)135 Status ScannerImpl::getAvailableDFSChannels(
136 std::unique_ptr<vector<int32_t>>* out_frequencies) {
137 if (!CheckIsValid()) {
138 return Status::ok();
139 }
140 BandInfo band_info;
141 if (!netlink_utils_->GetWiphyInfo(wiphy_index_,
142 &band_info,
143 &scan_capabilities_,
144 &wiphy_features_)) {
145 LOG(ERROR) << "Failed to get wiphy info from kernel";
146 out_frequencies->reset(nullptr);
147 return Status::ok();
148 }
149
150 out_frequencies->reset(new vector<int32_t>(band_info.band_dfs.begin(),
151 band_info.band_dfs.end()));
152 return Status::ok();
153 }
154
getScanResults(vector<NativeScanResult> * out_scan_results)155 Status ScannerImpl::getScanResults(vector<NativeScanResult>* out_scan_results) {
156 if (!CheckIsValid()) {
157 return Status::ok();
158 }
159 if (!scan_utils_->GetScanResult(interface_index_, out_scan_results)) {
160 LOG(ERROR) << "Failed to get scan results via NL80211";
161 }
162 return Status::ok();
163 }
164
scan(const SingleScanSettings & scan_settings,bool * out_success)165 Status ScannerImpl::scan(const SingleScanSettings& scan_settings,
166 bool* out_success) {
167 if (!CheckIsValid()) {
168 *out_success = false;
169 return Status::ok();
170 }
171
172 if (scan_started_) {
173 LOG(WARNING) << "Scan already started";
174 }
175 // Only request MAC address randomization when station is not associated.
176 bool request_random_mac = wiphy_features_.supports_random_mac_oneshot_scan &&
177 !client_interface_->IsAssociated();
178
179 // Initialize it with an empty ssid for a wild card scan.
180 vector<vector<uint8_t>> ssids = {{}};
181
182 vector<vector<uint8_t>> skipped_scan_ssids;
183 for (auto& network : scan_settings.hidden_networks_) {
184 if (ssids.size() + 1 > scan_capabilities_.max_num_scan_ssids) {
185 skipped_scan_ssids.emplace_back(network.ssid_);
186 continue;
187 }
188 ssids.push_back(network.ssid_);
189 }
190
191 LogSsidList(skipped_scan_ssids, "Skip scan ssid for single scan");
192
193 vector<uint32_t> freqs;
194 for (auto& channel : scan_settings.channel_settings_) {
195 freqs.push_back(channel.frequency_);
196 }
197
198 if (!scan_utils_->Scan(interface_index_, request_random_mac, ssids, freqs)) {
199 *out_success = false;
200 return Status::ok();
201 }
202 scan_started_ = true;
203 *out_success = true;
204 return Status::ok();
205 }
206
startPnoScan(const PnoSettings & pno_settings,bool * out_success)207 Status ScannerImpl::startPnoScan(const PnoSettings& pno_settings,
208 bool* out_success) {
209 if (!CheckIsValid()) {
210 *out_success = false;
211 return Status::ok();
212 }
213 if (pno_scan_started_) {
214 LOG(WARNING) << "Pno scan already started";
215 }
216 // An empty ssid for a wild card scan.
217 vector<vector<uint8_t>> scan_ssids = {{}};
218 vector<vector<uint8_t>> match_ssids;
219 // Empty frequency list: scan all frequencies.
220 vector<uint32_t> freqs;
221
222 vector<vector<uint8_t>> skipped_scan_ssids;
223 vector<vector<uint8_t>> skipped_match_ssids;
224 for (auto& network : pno_settings.pno_networks_) {
225 // Add hidden network ssid.
226 if (network.is_hidden_) {
227 if (scan_ssids.size() + 1 > scan_capabilities_.max_num_sched_scan_ssids) {
228 skipped_scan_ssids.emplace_back(network.ssid_);
229 continue;
230 }
231 scan_ssids.push_back(network.ssid_);
232 }
233
234 if (match_ssids.size() + 1 > scan_capabilities_.max_match_sets) {
235 skipped_match_ssids.emplace_back(network.ssid_);
236 continue;
237 }
238 match_ssids.push_back(network.ssid_);
239 }
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 // Only request MAC address randomization when station is not associated.
245 bool request_random_mac = wiphy_features_.supports_random_mac_sched_scan &&
246 !client_interface_->IsAssociated();
247
248 if (!scan_utils_->StartScheduledScan(interface_index_,
249 pno_settings.interval_ms_,
250 // TODO: honor both rssi thresholds.
251 pno_settings.min_5g_rssi_,
252 request_random_mac,
253 scan_ssids,
254 match_ssids,
255 freqs)) {
256 *out_success = false;
257 LOG(ERROR) << "Failed to start pno scan";
258 return Status::ok();
259 }
260 LOG(INFO) << "Pno scan started";
261 pno_scan_started_ = true;
262 *out_success = true;
263 return Status::ok();
264 }
265
stopPnoScan(bool * out_success)266 Status ScannerImpl::stopPnoScan(bool* out_success) {
267 if (!CheckIsValid()) {
268 *out_success = false;
269 return Status::ok();
270 }
271
272 if (!pno_scan_started_) {
273 LOG(WARNING) << "No pno scan started";
274 }
275 if (!scan_utils_->StopScheduledScan(interface_index_)) {
276 *out_success = false;
277 return Status::ok();
278 }
279 LOG(INFO) << "Pno scan stopped";
280 pno_scan_started_ = false;
281 *out_success = true;
282 return Status::ok();
283 }
284
abortScan()285 Status ScannerImpl::abortScan() {
286 if (!CheckIsValid()) {
287 return Status::ok();
288 }
289
290 if (!scan_started_) {
291 LOG(WARNING) << "Scan is not started. Ignore abort request";
292 return Status::ok();
293 }
294 if (!scan_utils_->AbortScan(interface_index_)) {
295 LOG(WARNING) << "Abort scan failed";
296 }
297 return Status::ok();
298 }
299
subscribeScanEvents(const sp<IScanEvent> & handler)300 Status ScannerImpl::subscribeScanEvents(const sp<IScanEvent>& handler) {
301 if (!CheckIsValid()) {
302 return Status::ok();
303 }
304
305 if (scan_event_handler_ != nullptr) {
306 LOG(ERROR) << "Found existing scan events subscriber."
307 << " This subscription request will unsubscribe it";
308 }
309 scan_event_handler_ = handler;
310 return Status::ok();
311 }
312
unsubscribeScanEvents()313 Status ScannerImpl::unsubscribeScanEvents() {
314 scan_event_handler_ = nullptr;
315 return Status::ok();
316 }
317
318
subscribePnoScanEvents(const sp<IPnoScanEvent> & handler)319 Status ScannerImpl::subscribePnoScanEvents(const sp<IPnoScanEvent>& handler) {
320 if (!CheckIsValid()) {
321 return Status::ok();
322 }
323
324 if (pno_scan_event_handler_ != nullptr) {
325 LOG(ERROR) << "Found existing pno scan events subscriber."
326 << " This subscription request will unsubscribe it";
327 }
328 pno_scan_event_handler_ = handler;
329
330 return Status::ok();
331 }
332
unsubscribePnoScanEvents()333 Status ScannerImpl::unsubscribePnoScanEvents() {
334 pno_scan_event_handler_ = nullptr;
335 return Status::ok();
336 }
337
OnScanResultsReady(uint32_t interface_index,bool aborted,vector<vector<uint8_t>> & ssids,vector<uint32_t> & frequencies)338 void ScannerImpl::OnScanResultsReady(
339 uint32_t interface_index,
340 bool aborted,
341 vector<vector<uint8_t>>& ssids,
342 vector<uint32_t>& frequencies) {
343 if (!scan_started_) {
344 LOG(INFO) << "Received external scan result notification from kernel.";
345 }
346 scan_started_ = false;
347 if (scan_event_handler_ != nullptr) {
348 // TODO: Pass other parameters back once we find framework needs them.
349 if (aborted) {
350 LOG(WARNING) << "Scan aborted";
351 scan_event_handler_->OnScanFailed();
352 } else {
353 scan_event_handler_->OnScanResultReady();
354 }
355 } else {
356 LOG(WARNING) << "No scan event handler found.";
357 }
358 }
359
OnSchedScanResultsReady(uint32_t interface_index,bool scan_stopped)360 void ScannerImpl::OnSchedScanResultsReady(uint32_t interface_index,
361 bool scan_stopped) {
362 if (pno_scan_event_handler_ != nullptr) {
363 if (scan_stopped) {
364 // If |pno_scan_started_| is false.
365 // This stop notification might result from our own request.
366 // See the document for NL80211_CMD_SCHED_SCAN_STOPPED in nl80211.h.
367 if (pno_scan_started_) {
368 LOG(WARNING) << "Unexpected pno scan stopped event";
369 pno_scan_event_handler_->OnPnoScanFailed();
370 }
371 pno_scan_started_ = false;
372 } else {
373 LOG(INFO) << "Pno scan result ready event";
374 pno_scan_event_handler_->OnPnoNetworkFound();
375 }
376 }
377 }
378
LogSsidList(vector<vector<uint8_t>> & ssid_list,string prefix)379 void ScannerImpl::LogSsidList(vector<vector<uint8_t>>& ssid_list,
380 string prefix) {
381 if (ssid_list.empty()) {
382 return;
383 }
384 string ssid_list_string;
385 for (auto& ssid : ssid_list) {
386 ssid_list_string += string(ssid.begin(), ssid.end());
387 if (&ssid != &ssid_list.back()) {
388 ssid_list_string += ", ";
389 }
390 }
391 LOG(WARNING) << prefix << ": " << ssid_list_string;
392 }
393
394 } // namespace wificond
395 } // namespace android
396