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 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 77 ScannerImpl::~ScannerImpl() { 78 } 79 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 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 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 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 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 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 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 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 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 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 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 313 Status ScannerImpl::unsubscribeScanEvents() { 314 scan_event_handler_ = nullptr; 315 return Status::ok(); 316 } 317 318 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 333 Status ScannerImpl::unsubscribePnoScanEvents() { 334 pno_scan_event_handler_ = nullptr; 335 return Status::ok(); 336 } 337 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 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 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