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/offload/offload_scan_manager.h" 26 #include "wificond/scanning/offload/offload_service_utils.h" 27 #include "wificond/scanning/scan_utils.h" 28 29 using android::binder::Status; 30 using android::net::wifi::IPnoScanEvent; 31 using android::net::wifi::IScanEvent; 32 using android::net::wifi::IWifiScannerImpl; 33 using android::hardware::wifi::offload::V1_0::IOffload; 34 using android::sp; 35 using com::android::server::wifi::wificond::NativeScanResult; 36 using com::android::server::wifi::wificond::PnoSettings; 37 using com::android::server::wifi::wificond::SingleScanSettings; 38 39 using std::pair; 40 using std::string; 41 using std::vector; 42 using std::weak_ptr; 43 using std::shared_ptr; 44 45 using namespace std::placeholders; 46 47 namespace { 48 using android::wificond::WiphyFeatures; 49 bool IsScanTypeSupported(int scan_type, const WiphyFeatures& wiphy_features) { 50 switch(scan_type) { 51 case IWifiScannerImpl::SCAN_TYPE_LOW_SPAN: 52 return wiphy_features.supports_low_span_oneshot_scan; 53 case IWifiScannerImpl::SCAN_TYPE_LOW_POWER: 54 return wiphy_features.supports_low_power_oneshot_scan; 55 case IWifiScannerImpl::SCAN_TYPE_HIGH_ACCURACY: 56 return wiphy_features.supports_high_accuracy_oneshot_scan; 57 default: 58 CHECK(0) << "Invalid scan type received: " << scan_type; 59 } 60 return {}; 61 } 62 } // namespace 63 64 namespace android { 65 namespace wificond { 66 67 ScannerImpl::ScannerImpl(uint32_t interface_index, 68 const ScanCapabilities& scan_capabilities, 69 const WiphyFeatures& wiphy_features, 70 ClientInterfaceImpl* client_interface, 71 ScanUtils* scan_utils, 72 weak_ptr<OffloadServiceUtils> offload_service_utils) 73 : valid_(true), 74 scan_started_(false), 75 pno_scan_started_(false), 76 offload_scan_supported_(false), 77 pno_scan_running_over_offload_(false), 78 pno_scan_results_from_offload_(false), 79 interface_index_(interface_index), 80 scan_capabilities_(scan_capabilities), 81 wiphy_features_(wiphy_features), 82 client_interface_(client_interface), 83 scan_utils_(scan_utils), 84 scan_event_handler_(nullptr) { 85 // Subscribe one-shot scan result notification from kernel. 86 LOG(INFO) << "subscribe scan result for interface with index: " 87 << (int)interface_index_; 88 scan_utils_->SubscribeScanResultNotification( 89 interface_index_, 90 std::bind(&ScannerImpl::OnScanResultsReady, this, _1, _2, _3, _4)); 91 // Subscribe scheduled scan result notification from kernel. 92 scan_utils_->SubscribeSchedScanResultNotification( 93 interface_index_, 94 std::bind(&ScannerImpl::OnSchedScanResultsReady, 95 this, 96 _1, _2)); 97 std::shared_ptr<OffloadScanCallbackInterfaceImpl> 98 offload_scan_callback_interface = 99 offload_service_utils.lock()->GetOffloadScanCallbackInterface(this); 100 offload_scan_manager_ = offload_service_utils.lock()->GetOffloadScanManager( 101 offload_service_utils, offload_scan_callback_interface); 102 offload_scan_supported_ = offload_service_utils.lock()->IsOffloadScanSupported(); 103 } 104 105 ScannerImpl::~ScannerImpl() {} 106 107 void ScannerImpl::Invalidate() { 108 LOG(INFO) << "Unsubscribe scan result for interface with index: " 109 << (int)interface_index_; 110 scan_utils_->UnsubscribeScanResultNotification(interface_index_); 111 scan_utils_->UnsubscribeSchedScanResultNotification(interface_index_); 112 } 113 114 bool ScannerImpl::CheckIsValid() { 115 if (!valid_) { 116 LOG(DEBUG) << "Calling on a invalid scanner object." 117 << "Underlying client interface object was destroyed."; 118 } 119 return valid_; 120 } 121 122 Status ScannerImpl::getScanResults(vector<NativeScanResult>* out_scan_results) { 123 if (!CheckIsValid()) { 124 return Status::ok(); 125 } 126 if (!scan_utils_->GetScanResult(interface_index_, out_scan_results)) { 127 LOG(ERROR) << "Failed to get scan results via NL80211"; 128 } 129 return Status::ok(); 130 } 131 132 Status ScannerImpl::getPnoScanResults( 133 vector<NativeScanResult>* out_scan_results) { 134 if (!CheckIsValid()) { 135 return Status::ok(); 136 } 137 if (pno_scan_results_from_offload_) { 138 if (!offload_scan_manager_->getScanResults(out_scan_results)) { 139 LOG(ERROR) << "Failed to get scan results via Offload HAL"; 140 } 141 } else { 142 if (!scan_utils_->GetScanResult(interface_index_, out_scan_results)) { 143 LOG(ERROR) << "Failed to get scan results via NL80211"; 144 } 145 } 146 return Status::ok(); 147 } 148 149 Status ScannerImpl::scan(const SingleScanSettings& scan_settings, 150 bool* out_success) { 151 if (!CheckIsValid()) { 152 *out_success = false; 153 return Status::ok(); 154 } 155 156 if (scan_started_) { 157 LOG(WARNING) << "Scan already started"; 158 } 159 // Only request MAC address randomization when station is not associated. 160 bool request_random_mac = 161 wiphy_features_.supports_random_mac_oneshot_scan && 162 !client_interface_->IsAssociated(); 163 int scan_type = scan_settings.scan_type_; 164 if (!IsScanTypeSupported(scan_settings.scan_type_, wiphy_features_)) { 165 LOG(DEBUG) << "Ignoring scan type because device does not support it"; 166 scan_type = SCAN_TYPE_DEFAULT; 167 } 168 169 // Initialize it with an empty ssid for a wild card scan. 170 vector<vector<uint8_t>> ssids = {{}}; 171 172 vector<vector<uint8_t>> skipped_scan_ssids; 173 for (auto& network : scan_settings.hidden_networks_) { 174 if (ssids.size() + 1 > scan_capabilities_.max_num_scan_ssids) { 175 skipped_scan_ssids.emplace_back(network.ssid_); 176 continue; 177 } 178 ssids.push_back(network.ssid_); 179 } 180 181 LogSsidList(skipped_scan_ssids, "Skip scan ssid for single scan"); 182 183 vector<uint32_t> freqs; 184 for (auto& channel : scan_settings.channel_settings_) { 185 freqs.push_back(channel.frequency_); 186 } 187 188 int error_code = 0; 189 if (!scan_utils_->Scan(interface_index_, request_random_mac, scan_type, 190 ssids, freqs, &error_code)) { 191 CHECK(error_code != ENODEV) << "Driver is in a bad state, restarting wificond"; 192 *out_success = false; 193 return Status::ok(); 194 } 195 scan_started_ = true; 196 *out_success = true; 197 return Status::ok(); 198 } 199 200 Status ScannerImpl::startPnoScan(const PnoSettings& pno_settings, 201 bool* out_success) { 202 pno_settings_ = pno_settings; 203 pno_scan_results_from_offload_ = false; 204 LOG(VERBOSE) << "startPnoScan"; 205 if (offload_scan_supported_ && StartPnoScanOffload(pno_settings)) { 206 // scanning over offload succeeded 207 *out_success = true; 208 } else { 209 *out_success = StartPnoScanDefault(pno_settings); 210 } 211 return Status::ok(); 212 } 213 214 bool ScannerImpl::StartPnoScanOffload(const PnoSettings& pno_settings) { 215 OffloadScanManager::ReasonCode reason_code; 216 vector<vector<uint8_t>> scan_ssids; 217 vector<vector<uint8_t>> match_ssids; 218 vector<uint8_t> match_security; 219 // Empty frequency list: scan all frequencies. 220 vector<uint32_t> freqs; 221 222 ParsePnoSettings(pno_settings, &scan_ssids, &match_ssids, &freqs, 223 &match_security); 224 pno_scan_running_over_offload_ = offload_scan_manager_->startScan( 225 pno_settings.interval_ms_, 226 // TODO: honor both rssi thresholds. 227 pno_settings.min_5g_rssi_, scan_ssids, match_ssids, match_security, freqs, 228 &reason_code); 229 if (pno_scan_running_over_offload_) { 230 LOG(VERBOSE) << "Pno scans requested over Offload HAL"; 231 if (pno_scan_event_handler_ != nullptr) { 232 pno_scan_event_handler_->OnPnoScanOverOffloadStarted(); 233 } 234 } 235 return pno_scan_running_over_offload_; 236 } 237 238 void ScannerImpl::ParsePnoSettings(const PnoSettings& pno_settings, 239 vector<vector<uint8_t>>* scan_ssids, 240 vector<vector<uint8_t>>* match_ssids, 241 vector<uint32_t>* freqs, 242 vector<uint8_t>* match_security) { 243 // TODO provide actionable security match parameters 244 const uint8_t kNetworkFlagsDefault = 0; 245 vector<vector<uint8_t>> skipped_scan_ssids; 246 vector<vector<uint8_t>> skipped_match_ssids; 247 for (auto& network : pno_settings.pno_networks_) { 248 // Add hidden network ssid. 249 if (network.is_hidden_) { 250 // TODO remove pruning for Offload Scans 251 if (scan_ssids->size() + 1 > 252 scan_capabilities_.max_num_sched_scan_ssids) { 253 skipped_scan_ssids.emplace_back(network.ssid_); 254 continue; 255 } 256 scan_ssids->push_back(network.ssid_); 257 } 258 259 if (match_ssids->size() + 1 > scan_capabilities_.max_match_sets) { 260 skipped_match_ssids.emplace_back(network.ssid_); 261 continue; 262 } 263 match_ssids->push_back(network.ssid_); 264 match_security->push_back(kNetworkFlagsDefault); 265 } 266 267 LogSsidList(skipped_scan_ssids, "Skip scan ssid for pno scan"); 268 LogSsidList(skipped_match_ssids, "Skip match ssid for pno scan"); 269 } 270 271 bool ScannerImpl::StartPnoScanDefault(const PnoSettings& pno_settings) { 272 if (!CheckIsValid()) { 273 return false; 274 } 275 if (pno_scan_started_) { 276 LOG(WARNING) << "Pno scan already started"; 277 } 278 // An empty ssid for a wild card scan. 279 vector<vector<uint8_t>> scan_ssids = {{}}; 280 vector<vector<uint8_t>> match_ssids; 281 vector<uint8_t> unused; 282 // Empty frequency list: scan all frequencies. 283 vector<uint32_t> freqs; 284 285 ParsePnoSettings(pno_settings, &scan_ssids, &match_ssids, &freqs, &unused); 286 // Only request MAC address randomization when station is not associated. 287 bool request_random_mac = wiphy_features_.supports_random_mac_sched_scan && 288 !client_interface_->IsAssociated(); 289 // Always request a low power scan for PNO, if device supports it. 290 bool request_low_power = wiphy_features_.supports_low_power_oneshot_scan; 291 292 int error_code = 0; 293 if (!scan_utils_->StartScheduledScan(interface_index_, 294 GenerateIntervalSetting(pno_settings), 295 pno_settings.min_2g_rssi_, 296 pno_settings.min_5g_rssi_, 297 request_random_mac, 298 request_low_power, 299 scan_ssids, 300 match_ssids, 301 freqs, 302 &error_code)) { 303 LOG(ERROR) << "Failed to start pno scan"; 304 CHECK(error_code != ENODEV) << "Driver is in a bad state, restarting wificond"; 305 return false; 306 } 307 LOG(INFO) << "Pno scan started"; 308 pno_scan_started_ = true; 309 return true; 310 } 311 312 Status ScannerImpl::stopPnoScan(bool* out_success) { 313 if (offload_scan_supported_ && StopPnoScanOffload()) { 314 // Pno scans over offload stopped successfully 315 *out_success = true; 316 } else { 317 // Pno scans were not requested over offload 318 *out_success = StopPnoScanDefault(); 319 } 320 return Status::ok(); 321 } 322 323 bool ScannerImpl::StopPnoScanOffload() { 324 OffloadScanManager::ReasonCode reason_code; 325 if (!pno_scan_running_over_offload_) { 326 return false; 327 } 328 if (!offload_scan_manager_->stopScan(&reason_code)) { 329 LOG(WARNING) << "Unable to unsubscribe to Offload scan results"; 330 } 331 pno_scan_running_over_offload_ = false; 332 LOG(VERBOSE) << "Pno scans over Offload stopped"; 333 return true; 334 } 335 336 bool ScannerImpl::StopPnoScanDefault() { 337 if (!CheckIsValid()) { 338 return false; 339 } 340 341 if (!pno_scan_started_) { 342 LOG(WARNING) << "No pno scan started"; 343 } 344 if (!scan_utils_->StopScheduledScan(interface_index_)) { 345 return false; 346 } 347 LOG(INFO) << "Pno scan stopped"; 348 pno_scan_started_ = false; 349 return true; 350 } 351 352 Status ScannerImpl::abortScan() { 353 if (!CheckIsValid()) { 354 return Status::ok(); 355 } 356 357 if (!scan_started_) { 358 LOG(WARNING) << "Scan is not started. Ignore abort request"; 359 return Status::ok(); 360 } 361 if (!scan_utils_->AbortScan(interface_index_)) { 362 LOG(WARNING) << "Abort scan failed"; 363 } 364 return Status::ok(); 365 } 366 367 Status ScannerImpl::subscribeScanEvents(const sp<IScanEvent>& handler) { 368 if (!CheckIsValid()) { 369 return Status::ok(); 370 } 371 372 if (scan_event_handler_ != nullptr) { 373 LOG(ERROR) << "Found existing scan events subscriber." 374 << " This subscription request will unsubscribe it"; 375 } 376 scan_event_handler_ = handler; 377 return Status::ok(); 378 } 379 380 Status ScannerImpl::unsubscribeScanEvents() { 381 scan_event_handler_ = nullptr; 382 return Status::ok(); 383 } 384 385 Status ScannerImpl::subscribePnoScanEvents(const sp<IPnoScanEvent>& handler) { 386 if (!CheckIsValid()) { 387 return Status::ok(); 388 } 389 390 if (pno_scan_event_handler_ != nullptr) { 391 LOG(ERROR) << "Found existing pno scan events subscriber." 392 << " This subscription request will unsubscribe it"; 393 } 394 pno_scan_event_handler_ = handler; 395 396 return Status::ok(); 397 } 398 399 Status ScannerImpl::unsubscribePnoScanEvents() { 400 pno_scan_event_handler_ = nullptr; 401 return Status::ok(); 402 } 403 404 void ScannerImpl::OnScanResultsReady(uint32_t interface_index, bool aborted, 405 vector<vector<uint8_t>>& ssids, 406 vector<uint32_t>& frequencies) { 407 if (!scan_started_) { 408 LOG(INFO) << "Received external scan result notification from kernel."; 409 } 410 scan_started_ = false; 411 if (scan_event_handler_ != nullptr) { 412 // TODO: Pass other parameters back once we find framework needs them. 413 if (aborted) { 414 LOG(WARNING) << "Scan aborted"; 415 scan_event_handler_->OnScanFailed(); 416 } else { 417 scan_event_handler_->OnScanResultReady(); 418 } 419 } else { 420 LOG(WARNING) << "No scan event handler found."; 421 } 422 } 423 424 void ScannerImpl::OnSchedScanResultsReady(uint32_t interface_index, 425 bool scan_stopped) { 426 if (pno_scan_event_handler_ != nullptr) { 427 if (scan_stopped) { 428 // If |pno_scan_started_| is false. 429 // This stop notification might result from our own request. 430 // See the document for NL80211_CMD_SCHED_SCAN_STOPPED in nl80211.h. 431 if (pno_scan_started_) { 432 LOG(WARNING) << "Unexpected pno scan stopped event"; 433 pno_scan_event_handler_->OnPnoScanFailed(); 434 } 435 pno_scan_started_ = false; 436 } else { 437 LOG(INFO) << "Pno scan result ready event"; 438 pno_scan_results_from_offload_ = false; 439 pno_scan_event_handler_->OnPnoNetworkFound(); 440 } 441 } 442 } 443 444 SchedScanIntervalSetting ScannerImpl::GenerateIntervalSetting( 445 const ::com::android::server::wifi::wificond::PnoSettings& 446 pno_settings) const { 447 bool support_num_scan_plans = scan_capabilities_.max_num_scan_plans >= 2; 448 bool support_scan_plan_interval = 449 scan_capabilities_.max_scan_plan_interval * 1000 >= 450 pno_settings.interval_ms_ * PnoSettings::kSlowScanIntervalMultiplier; 451 bool support_scan_plan_iterations = 452 scan_capabilities_.max_scan_plan_iterations >= 453 PnoSettings::kFastScanIterations; 454 455 uint32_t fast_scan_interval = 456 static_cast<uint32_t>(pno_settings.interval_ms_); 457 if (support_num_scan_plans && support_scan_plan_interval && 458 support_scan_plan_iterations) { 459 return SchedScanIntervalSetting{ 460 {{fast_scan_interval, PnoSettings::kFastScanIterations}}, 461 fast_scan_interval * PnoSettings::kSlowScanIntervalMultiplier}; 462 } else { 463 // Device doesn't support the provided scan plans. 464 // Specify single interval instead. 465 // In this case, the driver/firmware is expected to implement back off 466 // logic internally using |pno_settings.interval_ms_| as "fast scan" 467 // interval. 468 return SchedScanIntervalSetting{{}, fast_scan_interval}; 469 } 470 } 471 472 void ScannerImpl::OnOffloadScanResult() { 473 if (!pno_scan_running_over_offload_) { 474 LOG(WARNING) << "Scan results from Offload HAL but scan not requested over " 475 "this interface"; 476 return; 477 } 478 LOG(INFO) << "Offload Scan results received"; 479 pno_scan_results_from_offload_ = true; 480 if (pno_scan_event_handler_ != nullptr) { 481 pno_scan_event_handler_->OnPnoNetworkFound(); 482 } else { 483 LOG(WARNING) << "No scan event handler Offload Scan result"; 484 } 485 } 486 487 void ScannerImpl::OnOffloadError( 488 OffloadScanCallbackInterface::AsyncErrorReason error_code) { 489 if (!pno_scan_running_over_offload_) { 490 // Ignore irrelevant error notifications 491 LOG(WARNING) << "Offload HAL Async Error occured but Offload HAL is not " 492 "subscribed to"; 493 return; 494 } 495 LOG(ERROR) << "Offload Service Async Failure error_code=" << error_code; 496 switch (error_code) { 497 case OffloadScanCallbackInterface::AsyncErrorReason::BINDER_DEATH: 498 LOG(ERROR) << "Binder death"; 499 if (pno_scan_event_handler_ != nullptr) { 500 pno_scan_event_handler_->OnPnoScanOverOffloadFailed( 501 net::wifi::IPnoScanEvent::PNO_SCAN_OVER_OFFLOAD_BINDER_FAILURE); 502 } 503 break; 504 case OffloadScanCallbackInterface::AsyncErrorReason::REMOTE_FAILURE: 505 LOG(ERROR) << "Remote failure"; 506 if (pno_scan_event_handler_ != nullptr) { 507 pno_scan_event_handler_->OnPnoScanOverOffloadFailed( 508 net::wifi::IPnoScanEvent::PNO_SCAN_OVER_OFFLOAD_REMOTE_FAILURE); 509 } 510 break; 511 default: 512 LOG(WARNING) << "Invalid Error code"; 513 break; 514 } 515 bool success = false; 516 // Stop scans over Offload HAL and request them over netlink 517 stopPnoScan(&success); 518 if (success) { 519 LOG(INFO) << "Pno scans stopped"; 520 } 521 // Restart PNO scans over netlink interface 522 success = StartPnoScanDefault(pno_settings_); 523 if (success) { 524 LOG(INFO) << "Pno scans restarted"; 525 } else { 526 LOG(ERROR) << "Unable to fall back to netlink pno scan"; 527 pno_scan_event_handler_->OnPnoScanFailed(); 528 } 529 } 530 531 void ScannerImpl::LogSsidList(vector<vector<uint8_t>>& ssid_list, 532 string prefix) { 533 if (ssid_list.empty()) { 534 return; 535 } 536 string ssid_list_string; 537 for (auto& ssid : ssid_list) { 538 ssid_list_string += string(ssid.begin(), ssid.end()); 539 if (&ssid != &ssid_list.back()) { 540 ssid_list_string += ", "; 541 } 542 } 543 LOG(WARNING) << prefix << ": " << ssid_list_string; 544 } 545 546 } // namespace wificond 547 } // namespace android 548