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"
26 #include "wificond/scanning/offload/offload_service_utils.h"
27 #include "wificond/scanning/offload/offload_scan_manager.h"
29 using android::binder::Status;
30 using android::net::wifi::IPnoScanEvent;
31 using android::net::wifi::IScanEvent;
32 using android::hardware::wifi::offload::V1_0::IOffload;
34 using com::android::server::wifi::wificond::NativeScanResult;
35 using com::android::server::wifi::wificond::PnoSettings;
36 using com::android::server::wifi::wificond::SingleScanSettings;
41 using namespace std::placeholders;
46 ScannerImpl::ScannerImpl(uint32_t wiphy_index,
47 uint32_t interface_index,
48 const ScanCapabilities& scan_capabilities,
49 const WiphyFeatures& wiphy_features,
50 ClientInterfaceImpl* client_interface,
51 NetlinkUtils* netlink_utils,
52 ScanUtils* scan_utils)
55 pno_scan_started_(false),
56 wiphy_index_(wiphy_index),
57 interface_index_(interface_index),
58 scan_capabilities_(scan_capabilities),
59 wiphy_features_(wiphy_features),
60 client_interface_(client_interface),
61 netlink_utils_(netlink_utils),
62 scan_utils_(scan_utils),
63 scan_event_handler_(nullptr) {
64 // Subscribe one-shot scan result notification from kernel.
65 LOG(INFO) << "subscribe scan result for interface with index: "
66 << (int)interface_index_;
67 scan_utils_->SubscribeScanResultNotification(
69 std::bind(&ScannerImpl::OnScanResultsReady,
72 // Subscribe scheduled scan result notification from kernel.
73 scan_utils_->SubscribeSchedScanResultNotification(
75 std::bind(&ScannerImpl::OnSchedScanResultsReady,
78 offload_scan_manager_.reset(
79 new OffloadScanManager(new OffloadServiceUtils(),
80 std::bind(&ScannerImpl::OnOffloadScanResult,
84 ScannerImpl::~ScannerImpl() {
87 void ScannerImpl::Invalidate() {
88 LOG(INFO) << "Unsubscribe scan result for interface with index: "
89 << (int)interface_index_;
90 scan_utils_->UnsubscribeScanResultNotification(interface_index_);
91 scan_utils_->UnsubscribeSchedScanResultNotification(interface_index_);
94 bool ScannerImpl::CheckIsValid() {
96 LOG(DEBUG) << "Calling on a invalid scanner object."
97 << "Underlying client interface object was destroyed.";
102 Status ScannerImpl::getAvailable2gChannels(
103 std::unique_ptr<vector<int32_t>>* out_frequencies) {
104 if (!CheckIsValid()) {
108 if (!netlink_utils_->GetWiphyInfo(wiphy_index_,
112 LOG(ERROR) << "Failed to get wiphy info from kernel";
113 out_frequencies->reset(nullptr);
117 out_frequencies->reset(new vector<int32_t>(band_info.band_2g.begin(),
118 band_info.band_2g.end()));
122 Status ScannerImpl::getAvailable5gNonDFSChannels(
123 std::unique_ptr<vector<int32_t>>* out_frequencies) {
124 if (!CheckIsValid()) {
128 if (!netlink_utils_->GetWiphyInfo(wiphy_index_,
132 LOG(ERROR) << "Failed to get wiphy info from kernel";
133 out_frequencies->reset(nullptr);
137 out_frequencies->reset(new vector<int32_t>(band_info.band_5g.begin(),
138 band_info.band_5g.end()));
142 Status ScannerImpl::getAvailableDFSChannels(
143 std::unique_ptr<vector<int32_t>>* out_frequencies) {
144 if (!CheckIsValid()) {
148 if (!netlink_utils_->GetWiphyInfo(wiphy_index_,
152 LOG(ERROR) << "Failed to get wiphy info from kernel";
153 out_frequencies->reset(nullptr);
157 out_frequencies->reset(new vector<int32_t>(band_info.band_dfs.begin(),
158 band_info.band_dfs.end()));
162 Status ScannerImpl::getScanResults(vector<NativeScanResult>* out_scan_results) {
163 if (!CheckIsValid()) {
166 if (!scan_utils_->GetScanResult(interface_index_, out_scan_results)) {
167 LOG(ERROR) << "Failed to get scan results via NL80211";
172 Status ScannerImpl::scan(const SingleScanSettings& scan_settings,
174 if (!CheckIsValid()) {
175 *out_success = false;
180 LOG(WARNING) << "Scan already started";
182 // Only request MAC address randomization when station is not associated.
183 bool request_random_mac = wiphy_features_.supports_random_mac_oneshot_scan &&
184 !client_interface_->IsAssociated();
186 // Initialize it with an empty ssid for a wild card scan.
187 vector<vector<uint8_t>> ssids = {{}};
189 vector<vector<uint8_t>> skipped_scan_ssids;
190 for (auto& network : scan_settings.hidden_networks_) {
191 if (ssids.size() + 1 > scan_capabilities_.max_num_scan_ssids) {
192 skipped_scan_ssids.emplace_back(network.ssid_);
195 ssids.push_back(network.ssid_);
198 LogSsidList(skipped_scan_ssids, "Skip scan ssid for single scan");
200 vector<uint32_t> freqs;
201 for (auto& channel : scan_settings.channel_settings_) {
202 freqs.push_back(channel.frequency_);
205 if (!scan_utils_->Scan(interface_index_, request_random_mac, ssids, freqs)) {
206 *out_success = false;
209 scan_started_ = true;
214 Status ScannerImpl::startPnoScan(const PnoSettings& pno_settings,
216 if (!CheckIsValid()) {
217 *out_success = false;
220 if (pno_scan_started_) {
221 LOG(WARNING) << "Pno scan already started";
223 // An empty ssid for a wild card scan.
224 vector<vector<uint8_t>> scan_ssids = {{}};
225 vector<vector<uint8_t>> match_ssids;
226 // Empty frequency list: scan all frequencies.
227 vector<uint32_t> freqs;
229 vector<vector<uint8_t>> skipped_scan_ssids;
230 vector<vector<uint8_t>> skipped_match_ssids;
231 for (auto& network : pno_settings.pno_networks_) {
232 // Add hidden network ssid.
233 if (network.is_hidden_) {
234 if (scan_ssids.size() + 1 > scan_capabilities_.max_num_sched_scan_ssids) {
235 skipped_scan_ssids.emplace_back(network.ssid_);
238 scan_ssids.push_back(network.ssid_);
241 if (match_ssids.size() + 1 > scan_capabilities_.max_match_sets) {
242 skipped_match_ssids.emplace_back(network.ssid_);
245 match_ssids.push_back(network.ssid_);
248 LogSsidList(skipped_scan_ssids, "Skip scan ssid for pno scan");
249 LogSsidList(skipped_match_ssids, "Skip match ssid for pno scan");
251 // Only request MAC address randomization when station is not associated.
252 bool request_random_mac = wiphy_features_.supports_random_mac_sched_scan &&
253 !client_interface_->IsAssociated();
255 if (!scan_utils_->StartScheduledScan(interface_index_,
256 pno_settings.interval_ms_,
257 // TODO: honor both rssi thresholds.
258 pno_settings.min_5g_rssi_,
263 *out_success = false;
264 LOG(ERROR) << "Failed to start pno scan";
267 LOG(INFO) << "Pno scan started";
268 pno_scan_started_ = true;
273 Status ScannerImpl::stopPnoScan(bool* out_success) {
274 if (!CheckIsValid()) {
275 *out_success = false;
279 if (!pno_scan_started_) {
280 LOG(WARNING) << "No pno scan started";
282 if (!scan_utils_->StopScheduledScan(interface_index_)) {
283 *out_success = false;
286 LOG(INFO) << "Pno scan stopped";
287 pno_scan_started_ = false;
292 Status ScannerImpl::subscribeScanEvents(const sp<IScanEvent>& handler) {
293 if (!CheckIsValid()) {
297 if (scan_event_handler_ != nullptr) {
298 LOG(ERROR) << "Found existing scan events subscriber."
299 << " This subscription request will unsubscribe it";
301 scan_event_handler_ = handler;
305 Status ScannerImpl::unsubscribeScanEvents() {
306 scan_event_handler_ = nullptr;
311 Status ScannerImpl::subscribePnoScanEvents(const sp<IPnoScanEvent>& handler) {
312 if (!CheckIsValid()) {
316 if (pno_scan_event_handler_ != nullptr) {
317 LOG(ERROR) << "Found existing pno scan events subscriber."
318 << " This subscription request will unsubscribe it";
320 pno_scan_event_handler_ = handler;
325 Status ScannerImpl::unsubscribePnoScanEvents() {
326 pno_scan_event_handler_ = nullptr;
330 void ScannerImpl::OnScanResultsReady(
331 uint32_t interface_index,
333 vector<vector<uint8_t>>& ssids,
334 vector<uint32_t>& frequencies) {
335 if (!scan_started_) {
336 LOG(INFO) << "Received external scan result notification from kernel.";
338 scan_started_ = false;
339 if (scan_event_handler_ != nullptr) {
340 // TODO: Pass other parameters back once we find framework needs them.
342 LOG(WARNING) << "Scan aborted";
343 scan_event_handler_->OnScanFailed();
345 scan_event_handler_->OnScanResultReady();
348 LOG(WARNING) << "No scan event handler found.";
352 void ScannerImpl::OnSchedScanResultsReady(uint32_t interface_index,
354 if (pno_scan_event_handler_ != nullptr) {
356 // If |pno_scan_started_| is false.
357 // This stop notification might result from our own request.
358 // See the document for NL80211_CMD_SCHED_SCAN_STOPPED in nl80211.h.
359 if (pno_scan_started_) {
360 LOG(WARNING) << "Unexpected pno scan stopped event";
361 pno_scan_event_handler_->OnPnoScanFailed();
363 pno_scan_started_ = false;
365 LOG(INFO) << "Pno scan result ready event";
366 pno_scan_event_handler_->OnPnoNetworkFound();
371 void ScannerImpl::LogSsidList(vector<vector<uint8_t>>& ssid_list,
373 if (ssid_list.empty()) {
376 string ssid_list_string;
377 for (auto& ssid : ssid_list) {
378 ssid_list_string += string(ssid.begin(), ssid.end());
379 if (&ssid != &ssid_list.back()) {
380 ssid_list_string += ", ";
383 LOG(WARNING) << prefix << ": " << ssid_list_string;
386 void ScannerImpl::OnOffloadScanResult(
387 std::vector<NativeScanResult> scanResult) {
388 // TODO: Process scan result
389 if (scan_event_handler_ != nullptr) {
390 scan_event_handler_->OnScanResultReady();
392 LOG(WARNING) << "No scan event handler Offload Scan result";
396 } // namespace wificond
397 } // namespace android