2 * Copyright (C) 2016 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "wificond/scanning/scanner_impl.h"
22 #include <android-base/logging.h>
24 #include "wificond/client_interface_impl.h"
25 #include "wificond/scanning/scan_utils.h"
27 using android::binder::Status;
28 using android::net::wifi::IPnoScanEvent;
29 using android::net::wifi::IScanEvent;
31 using com::android::server::wifi::wificond::NativeScanResult;
32 using com::android::server::wifi::wificond::PnoSettings;
33 using com::android::server::wifi::wificond::SingleScanSettings;
38 using namespace std::placeholders;
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)
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(
66 std::bind(&ScannerImpl::OnScanResultsReady,
69 // Subscribe scheduled scan result notification from kernel.
70 scan_utils_->SubscribeSchedScanResultNotification(
72 std::bind(&ScannerImpl::OnSchedScanResultsReady,
77 ScannerImpl::~ScannerImpl() {
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_);
87 bool ScannerImpl::CheckIsValid() {
89 LOG(DEBUG) << "Calling on a invalid scanner object."
90 << "Underlying client interface object was destroyed.";
95 Status ScannerImpl::getAvailable2gChannels(
96 std::unique_ptr<vector<int32_t>>* out_frequencies) {
97 if (!CheckIsValid()) {
101 if (!netlink_utils_->GetWiphyInfo(wiphy_index_,
105 LOG(ERROR) << "Failed to get wiphy info from kernel";
106 out_frequencies->reset(nullptr);
110 out_frequencies->reset(new vector<int32_t>(band_info.band_2g.begin(),
111 band_info.band_2g.end()));
115 Status ScannerImpl::getAvailable5gNonDFSChannels(
116 std::unique_ptr<vector<int32_t>>* out_frequencies) {
117 if (!CheckIsValid()) {
121 if (!netlink_utils_->GetWiphyInfo(wiphy_index_,
125 LOG(ERROR) << "Failed to get wiphy info from kernel";
126 out_frequencies->reset(nullptr);
130 out_frequencies->reset(new vector<int32_t>(band_info.band_5g.begin(),
131 band_info.band_5g.end()));
135 Status ScannerImpl::getAvailableDFSChannels(
136 std::unique_ptr<vector<int32_t>>* out_frequencies) {
137 if (!CheckIsValid()) {
141 if (!netlink_utils_->GetWiphyInfo(wiphy_index_,
145 LOG(ERROR) << "Failed to get wiphy info from kernel";
146 out_frequencies->reset(nullptr);
150 out_frequencies->reset(new vector<int32_t>(band_info.band_dfs.begin(),
151 band_info.band_dfs.end()));
155 Status ScannerImpl::getScanResults(vector<NativeScanResult>* out_scan_results) {
156 if (!CheckIsValid()) {
159 if (!scan_utils_->GetScanResult(interface_index_, out_scan_results)) {
160 LOG(ERROR) << "Failed to get scan results via NL80211";
165 Status ScannerImpl::scan(const SingleScanSettings& scan_settings,
167 if (!CheckIsValid()) {
168 *out_success = false;
173 LOG(WARNING) << "Scan already started";
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();
179 // Initialize it with an empty ssid for a wild card scan.
180 vector<vector<uint8_t>> ssids = {{}};
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_);
188 ssids.push_back(network.ssid_);
191 LogSsidList(skipped_scan_ssids, "Skip scan ssid for single scan");
193 vector<uint32_t> freqs;
194 for (auto& channel : scan_settings.channel_settings_) {
195 freqs.push_back(channel.frequency_);
198 if (!scan_utils_->Scan(interface_index_, request_random_mac, ssids, freqs)) {
199 *out_success = false;
202 scan_started_ = true;
207 Status ScannerImpl::startPnoScan(const PnoSettings& pno_settings,
209 if (!CheckIsValid()) {
210 *out_success = false;
213 if (pno_scan_started_) {
214 LOG(WARNING) << "Pno scan already started";
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;
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_);
231 scan_ssids.push_back(network.ssid_);
234 if (match_ssids.size() + 1 > scan_capabilities_.max_match_sets) {
235 skipped_match_ssids.emplace_back(network.ssid_);
238 match_ssids.push_back(network.ssid_);
241 LogSsidList(skipped_scan_ssids, "Skip scan ssid for pno scan");
242 LogSsidList(skipped_match_ssids, "Skip match ssid for pno scan");
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();
248 if (!scan_utils_->StartScheduledScan(interface_index_,
249 pno_settings.interval_ms_,
250 // TODO: honor both rssi thresholds.
251 pno_settings.min_5g_rssi_,
256 *out_success = false;
257 LOG(ERROR) << "Failed to start pno scan";
260 LOG(INFO) << "Pno scan started";
261 pno_scan_started_ = true;
266 Status ScannerImpl::stopPnoScan(bool* out_success) {
267 if (!CheckIsValid()) {
268 *out_success = false;
272 if (!pno_scan_started_) {
273 LOG(WARNING) << "No pno scan started";
275 if (!scan_utils_->StopScheduledScan(interface_index_)) {
276 *out_success = false;
279 LOG(INFO) << "Pno scan stopped";
280 pno_scan_started_ = false;
285 Status ScannerImpl::subscribeScanEvents(const sp<IScanEvent>& handler) {
286 if (!CheckIsValid()) {
290 if (scan_event_handler_ != nullptr) {
291 LOG(ERROR) << "Found existing scan events subscriber."
292 << " This subscription request will unsubscribe it";
294 scan_event_handler_ = handler;
298 Status ScannerImpl::unsubscribeScanEvents() {
299 scan_event_handler_ = nullptr;
304 Status ScannerImpl::subscribePnoScanEvents(const sp<IPnoScanEvent>& handler) {
305 if (!CheckIsValid()) {
309 if (pno_scan_event_handler_ != nullptr) {
310 LOG(ERROR) << "Found existing pno scan events subscriber."
311 << " This subscription request will unsubscribe it";
313 pno_scan_event_handler_ = handler;
318 Status ScannerImpl::unsubscribePnoScanEvents() {
319 pno_scan_event_handler_ = nullptr;
323 void ScannerImpl::OnScanResultsReady(
324 uint32_t interface_index,
326 vector<vector<uint8_t>>& ssids,
327 vector<uint32_t>& frequencies) {
328 if (!scan_started_) {
329 LOG(INFO) << "Received external scan result notification from kernel.";
331 scan_started_ = false;
332 if (scan_event_handler_ != nullptr) {
333 // TODO: Pass other parameters back once we find framework needs them.
335 LOG(WARNING) << "Scan aborted";
336 scan_event_handler_->OnScanFailed();
338 scan_event_handler_->OnScanResultReady();
341 LOG(WARNING) << "No scan event handler found.";
345 void ScannerImpl::OnSchedScanResultsReady(uint32_t interface_index,
347 if (pno_scan_event_handler_ != nullptr) {
349 // If |pno_scan_started_| is false.
350 // This stop notification might result from our own request.
351 // See the document for NL80211_CMD_SCHED_SCAN_STOPPED in nl80211.h.
352 if (pno_scan_started_) {
353 LOG(WARNING) << "Unexpected pno scan stopped event";
354 pno_scan_event_handler_->OnPnoScanFailed();
356 pno_scan_started_ = false;
358 LOG(INFO) << "Pno scan result ready event";
359 pno_scan_event_handler_->OnPnoNetworkFound();
364 void ScannerImpl::LogSsidList(vector<vector<uint8_t>>& ssid_list,
366 if (ssid_list.empty()) {
369 string ssid_list_string;
370 for (auto& ssid : ssid_list) {
371 ssid_list_string += string(ssid.begin(), ssid.end());
372 if (&ssid != &ssid_list.back()) {
373 ssid_list_string += ", ";
376 LOG(WARNING) << prefix << ": " << ssid_list_string;
379 } // namespace wificond
380 } // namespace android