1 // 2 // Copyright (C) 2012 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 "shill/wifi/wifi.h" 18 19 #include <linux/if.h> // Needs definitions from netinet/ether.h 20 #include <netinet/ether.h> 21 #include <stdio.h> 22 #include <string.h> 23 24 #include <limits> 25 #include <map> 26 #include <set> 27 #include <string> 28 #include <vector> 29 30 #include <base/bind.h> 31 #include <base/files/file_util.h> 32 #include <base/files/file_path.h> 33 #include <base/strings/string_util.h> 34 #include <base/strings/stringprintf.h> 35 #if defined(__ANDROID__) 36 #include <dbus/service_constants.h> 37 #else 38 #include <chromeos/dbus/service_constants.h> 39 #endif // __ANDROID__ 40 41 #include "shill/control_interface.h" 42 #include "shill/device.h" 43 #include "shill/eap_credentials.h" 44 #include "shill/error.h" 45 #include "shill/file_reader.h" 46 #include "shill/geolocation_info.h" 47 #include "shill/link_monitor.h" 48 #include "shill/logging.h" 49 #include "shill/manager.h" 50 #include "shill/metrics.h" 51 #include "shill/net/ieee80211.h" 52 #include "shill/net/ip_address.h" 53 #include "shill/net/netlink_manager.h" 54 #include "shill/net/netlink_message.h" 55 #include "shill/net/nl80211_message.h" 56 #include "shill/net/rtnl_handler.h" 57 #include "shill/net/shill_time.h" 58 #include "shill/property_accessor.h" 59 #include "shill/scope_logger.h" 60 #include "shill/supplicant/supplicant_eap_state_handler.h" 61 #include "shill/supplicant/supplicant_interface_proxy_interface.h" 62 #include "shill/supplicant/supplicant_network_proxy_interface.h" 63 #include "shill/supplicant/supplicant_process_proxy_interface.h" 64 #include "shill/supplicant/wpa_supplicant.h" 65 #include "shill/technology.h" 66 #include "shill/wifi/mac80211_monitor.h" 67 #include "shill/wifi/scan_session.h" 68 #include "shill/wifi/tdls_manager.h" 69 #include "shill/wifi/wake_on_wifi.h" 70 #include "shill/wifi/wifi_endpoint.h" 71 #include "shill/wifi/wifi_provider.h" 72 #include "shill/wifi/wifi_service.h" 73 74 using base::Bind; 75 using base::FilePath; 76 using base::StringPrintf; 77 using std::map; 78 using std::set; 79 using std::string; 80 using std::vector; 81 82 namespace shill { 83 84 namespace Logging { 85 static auto kModuleLogScope = ScopeLogger::kWiFi; 86 static string ObjectID(WiFi* w) { return w->GetRpcIdentifier(); } 87 } 88 89 // statics 90 const char* WiFi::kDefaultBgscanMethod = 91 WPASupplicant::kNetworkBgscanMethodSimple; 92 const uint16_t WiFi::kDefaultBgscanShortIntervalSeconds = 30; 93 const int32_t WiFi::kDefaultBgscanSignalThresholdDbm = -50; 94 const uint16_t WiFi::kDefaultScanIntervalSeconds = 60; 95 const uint16_t WiFi::kDefaultRoamThresholdDb = 18; // Supplicant's default. 96 97 // Scan interval while connected. 98 const uint16_t WiFi::kBackgroundScanIntervalSeconds = 3601; 99 // Age (in seconds) beyond which a BSS cache entry will not be preserved, 100 // across a suspend/resume. 101 const time_t WiFi::kMaxBSSResumeAgeSeconds = 10; 102 const char WiFi::kInterfaceStateUnknown[] = "shill-unknown"; 103 const time_t WiFi::kRescanIntervalSeconds = 1; 104 const int WiFi::kNumFastScanAttempts = 3; 105 const int WiFi::kFastScanIntervalSeconds = 10; 106 const int WiFi::kPendingTimeoutSeconds = 15; 107 const int WiFi::kReconnectTimeoutSeconds = 10; 108 const int WiFi::kRequestStationInfoPeriodSeconds = 20; 109 const size_t WiFi::kMinumumFrequenciesToScan = 4; // Arbitrary but > 0. 110 const float WiFi::kDefaultFractionPerScan = 0.34; 111 const size_t WiFi::kStuckQueueLengthThreshold = 40; // ~1 full-channel scan 112 // 1 second is less than the time it takes to scan and establish a new 113 // connection after waking, but should be enough time for supplicant to update 114 // its state. 115 const int WiFi::kPostWakeConnectivityReportDelayMilliseconds = 1000; 116 const uint32_t WiFi::kDefaultWiphyIndex = UINT32_MAX; 117 const int WiFi::kPostScanFailedDelayMilliseconds = 10000; 118 // Invalid 802.11 disconnect reason code. 119 const int WiFi::kDefaultDisconnectReason = INT32_MAX; 120 121 namespace { 122 bool IsPrintableAsciiChar(char c) { 123 return (c >= ' ' && c <= '~'); 124 } 125 } // namespace 126 127 WiFi::WiFi(ControlInterface* control_interface, 128 EventDispatcher* dispatcher, 129 Metrics* metrics, 130 Manager* manager, 131 const string& link, 132 const string& address, 133 int interface_index) 134 : Device(control_interface, 135 dispatcher, 136 metrics, 137 manager, 138 link, 139 address, 140 interface_index, 141 Technology::kWifi), 142 provider_(manager->wifi_provider()), 143 weak_ptr_factory_(this), 144 time_(Time::GetInstance()), 145 supplicant_present_(false), 146 supplicant_process_proxy_( 147 control_interface->CreateSupplicantProcessProxy( 148 Bind(&WiFi::OnSupplicantAppear, Unretained(this)), 149 Bind(&WiFi::OnSupplicantVanish, Unretained(this)))), 150 supplicant_state_(kInterfaceStateUnknown), 151 supplicant_bss_("(unknown)"), 152 supplicant_disconnect_reason_(kDefaultDisconnectReason), 153 need_bss_flush_(false), 154 resumed_at_((struct timeval){0}), 155 fast_scans_remaining_(kNumFastScanAttempts), 156 has_already_completed_(false), 157 is_roaming_in_progress_(false), 158 is_debugging_connection_(false), 159 eap_state_handler_(new SupplicantEAPStateHandler()), 160 mac80211_monitor_(new Mac80211Monitor( 161 dispatcher, 162 link, 163 kStuckQueueLengthThreshold, 164 base::Bind(&WiFi::RestartFastScanAttempts, 165 weak_ptr_factory_.GetWeakPtr()), 166 metrics)), 167 bgscan_short_interval_seconds_(kDefaultBgscanShortIntervalSeconds), 168 bgscan_signal_threshold_dbm_(kDefaultBgscanSignalThresholdDbm), 169 roam_threshold_db_(kDefaultRoamThresholdDb), 170 scan_interval_seconds_(kDefaultScanIntervalSeconds), 171 progressive_scan_enabled_(false), 172 scan_configuration_("Full scan"), 173 netlink_manager_(NetlinkManager::GetInstance()), 174 min_frequencies_to_scan_(kMinumumFrequenciesToScan), 175 max_frequencies_to_scan_(std::numeric_limits<int>::max()), 176 scan_all_frequencies_(true), 177 fraction_per_scan_(kDefaultFractionPerScan), 178 scan_state_(kScanIdle), 179 scan_method_(kScanMethodNone), 180 receive_byte_count_at_connect_(0), 181 wiphy_index_(kDefaultWiphyIndex), 182 wake_on_wifi_(new WakeOnWiFi(netlink_manager_, 183 dispatcher, 184 metrics, 185 Bind(&Manager::RecordDarkResumeWakeReason, 186 manager->AsWeakPtr()))) { 187 PropertyStore* store = this->mutable_store(); 188 store->RegisterDerivedString( 189 kBgscanMethodProperty, 190 StringAccessor( 191 // TODO(petkov): CustomMappedAccessor is used for convenience because 192 // it provides a way to define a custom clearer (unlike 193 // CustomAccessor). We need to implement a fully custom accessor with 194 // no extra argument. 195 new CustomMappedAccessor<WiFi, string, int>(this, 196 &WiFi::ClearBgscanMethod, 197 &WiFi::GetBgscanMethod, 198 &WiFi::SetBgscanMethod, 199 0))); // Unused. 200 HelpRegisterDerivedUint16(store, 201 kBgscanShortIntervalProperty, 202 &WiFi::GetBgscanShortInterval, 203 &WiFi::SetBgscanShortInterval); 204 HelpRegisterDerivedInt32(store, 205 kBgscanSignalThresholdProperty, 206 &WiFi::GetBgscanSignalThreshold, 207 &WiFi::SetBgscanSignalThreshold); 208 209 store->RegisterDerivedKeyValueStore( 210 kLinkStatisticsProperty, 211 KeyValueStoreAccessor( 212 new CustomAccessor<WiFi, KeyValueStore>( 213 this, &WiFi::GetLinkStatistics, nullptr))); 214 215 // TODO(quiche): Decide if scan_pending_ is close enough to 216 // "currently scanning" that we don't care, or if we want to track 217 // scan pending/currently scanning/no scan scheduled as a tri-state 218 // kind of thing. 219 HelpRegisterConstDerivedBool(store, 220 kScanningProperty, 221 &WiFi::GetScanPending); 222 HelpRegisterDerivedUint16(store, 223 kRoamThresholdProperty, 224 &WiFi::GetRoamThreshold, 225 &WiFi::SetRoamThreshold); 226 HelpRegisterDerivedUint16(store, 227 kScanIntervalProperty, 228 &WiFi::GetScanInterval, 229 &WiFi::SetScanInterval); 230 wake_on_wifi_->InitPropertyStore(store); 231 ScopeLogger::GetInstance()->RegisterScopeEnableChangedCallback( 232 ScopeLogger::kWiFi, 233 Bind(&WiFi::OnWiFiDebugScopeChanged, weak_ptr_factory_.GetWeakPtr())); 234 CHECK(netlink_manager_); 235 netlink_manager_->AddBroadcastHandler(Bind( 236 &WiFi::OnScanStarted, weak_ptr_factory_.GetWeakPtr())); 237 SLOG(this, 2) << "WiFi device " << link_name() << " initialized."; 238 } 239 240 WiFi::~WiFi() {} 241 242 void WiFi::Start(Error* error, 243 const EnabledStateChangedCallback& /*callback*/) { 244 SLOG(this, 2) << "WiFi " << link_name() << " starting."; 245 if (enabled()) { 246 return; 247 } 248 OnEnabledStateChanged(EnabledStateChangedCallback(), Error()); 249 if (error) { 250 error->Reset(); // indicate immediate completion 251 } 252 253 // Subscribe to multicast events. 254 netlink_manager_->SubscribeToEvents(Nl80211Message::kMessageTypeString, 255 NetlinkManager::kEventTypeConfig); 256 netlink_manager_->SubscribeToEvents(Nl80211Message::kMessageTypeString, 257 NetlinkManager::kEventTypeScan); 258 netlink_manager_->SubscribeToEvents(Nl80211Message::kMessageTypeString, 259 NetlinkManager::kEventTypeRegulatory); 260 netlink_manager_->SubscribeToEvents(Nl80211Message::kMessageTypeString, 261 NetlinkManager::kEventTypeMlme); 262 GetPhyInfo(); 263 // Connect to WPA supplicant if it's already present. If not, we'll connect to 264 // it when it appears. 265 ConnectToSupplicant(); 266 wake_on_wifi_->StartMetricsTimer(); 267 } 268 269 void WiFi::Stop(Error* error, const EnabledStateChangedCallback& /*callback*/) { 270 SLOG(this, 2) << "WiFi " << link_name() << " stopping."; 271 // Unlike other devices, we leave the DBus name watcher in place here, because 272 // WiFi callbacks expect notifications even if the device is disabled. 273 DropConnection(); 274 StopScanTimer(); 275 for (const auto& endpoint : endpoint_by_rpcid_) { 276 provider_->OnEndpointRemoved(endpoint.second); 277 } 278 endpoint_by_rpcid_.clear(); 279 for (const auto& map_entry : rpcid_by_service_) { 280 RemoveNetwork(map_entry.second); 281 } 282 rpcid_by_service_.clear(); 283 // Remove interface from supplicant. 284 if (supplicant_present_ && 285 supplicant_interface_proxy_) { 286 supplicant_process_proxy_->RemoveInterface(supplicant_interface_path_); 287 } 288 supplicant_interface_path_ = ""; 289 SetSupplicantInterfaceProxy(nullptr); 290 pending_scan_results_.reset(); 291 tdls_manager_.reset(); 292 current_service_ = nullptr; // breaks a reference cycle 293 pending_service_ = nullptr; // breaks a reference cycle 294 is_debugging_connection_ = false; 295 SetScanState(kScanIdle, kScanMethodNone, __func__); 296 StopPendingTimer(); 297 StopReconnectTimer(); 298 StopRequestingStationInfo(); 299 mac80211_monitor_->Stop(); 300 301 OnEnabledStateChanged(EnabledStateChangedCallback(), Error()); 302 if (error) 303 error->Reset(); // indicate immediate completion 304 weak_ptr_factory_.InvalidateWeakPtrs(); 305 306 SLOG(this, 3) << "WiFi " << link_name() << " supplicant_process_proxy_ " 307 << (supplicant_process_proxy_.get() ? 308 "is set." : "is not set."); 309 SLOG(this, 3) << "WiFi " << link_name() << " supplicant_interface_proxy_ " 310 << (supplicant_interface_proxy_.get() ? 311 "is set." : "is not set."); 312 SLOG(this, 3) << "WiFi " << link_name() << " pending_service_ " 313 << (pending_service_.get() ? "is set." : "is not set."); 314 SLOG(this, 3) << "WiFi " << link_name() << " has " 315 << endpoint_by_rpcid_.size() << " EndpointMap entries."; 316 } 317 318 void WiFi::Scan(ScanType scan_type, Error* /*error*/, const string& reason) { 319 if ((scan_state_ != kScanIdle) || 320 (current_service_.get() && current_service_->IsConnecting())) { 321 SLOG(this, 2) << "Ignoring scan request while scanning or connecting."; 322 return; 323 } 324 if (progressive_scan_enabled_ && scan_type == kProgressiveScan) { 325 LOG(INFO) << __func__ << " [progressive] on " << link_name() << " from " 326 << reason; 327 LOG(INFO) << scan_configuration_; 328 if (!scan_session_) { 329 // TODO(wdg): Perform in-depth testing to determine the best values for 330 // the different scans. chromium:235293 331 ScanSession::FractionList scan_fractions; 332 float total_fraction = 0.0; 333 do { 334 total_fraction += fraction_per_scan_; 335 scan_fractions.push_back(fraction_per_scan_); 336 } while (total_fraction < 1.0); 337 scan_session_.reset( 338 new ScanSession(netlink_manager_, 339 dispatcher(), 340 provider_->GetScanFrequencies(), 341 (scan_all_frequencies_ ? all_scan_frequencies_ : 342 set<uint16_t>()), 343 interface_index(), 344 scan_fractions, 345 min_frequencies_to_scan_, 346 max_frequencies_to_scan_, 347 Bind(&WiFi::OnFailedProgressiveScan, 348 weak_ptr_factory_.GetWeakPtr()), 349 metrics())); 350 for (const auto& ssid : provider_->GetHiddenSSIDList()) { 351 scan_session_->AddSsid(ByteString(&ssid.front(), ssid.size())); 352 } 353 } 354 dispatcher()->PostTask( 355 Bind(&WiFi::ProgressiveScanTask, weak_ptr_factory_.GetWeakPtr())); 356 } else { 357 LOG(INFO) << __func__ << " [full] on " << link_name() 358 << " (progressive scan " 359 << (progressive_scan_enabled_ ? "ENABLED" : "DISABLED") 360 << ") from " << reason; 361 // Needs to send a D-Bus message, but may be called from D-Bus 362 // signal handler context (via Manager::RequestScan). So defer work 363 // to event loop. 364 dispatcher()->PostTask( 365 Bind(&WiFi::ScanTask, weak_ptr_factory_.GetWeakPtr())); 366 } 367 } 368 369 void WiFi::SetSchedScan(bool enable, Error* /*error*/) { 370 // Needs to send a D-Bus message, but may be called from D-Bus 371 // signal handler context (via Manager::SetSchedScan). So defer work 372 // to event loop. 373 dispatcher()->PostTask( 374 Bind(&WiFi::SetSchedScanTask, weak_ptr_factory_.GetWeakPtr(), enable)); 375 } 376 377 void WiFi::AddPendingScanResult(const string& path, 378 const KeyValueStore& properties, 379 bool is_removal) { 380 if (!pending_scan_results_) { 381 pending_scan_results_.reset(new PendingScanResults( 382 Bind(&WiFi::PendingScanResultsHandler, 383 weak_ptr_factory_.GetWeakPtr()))); 384 dispatcher()->PostTask(pending_scan_results_->callback.callback()); 385 } 386 pending_scan_results_->results.emplace_back(path, properties, is_removal); 387 } 388 389 void WiFi::BSSAdded(const string& path, const KeyValueStore& properties) { 390 // Called from a D-Bus signal handler, and may need to send a D-Bus 391 // message. So defer work to event loop. 392 AddPendingScanResult(path, properties, false); 393 } 394 395 void WiFi::BSSRemoved(const string& path) { 396 // Called from a D-Bus signal handler, and may need to send a D-Bus 397 // message. So defer work to event loop. 398 AddPendingScanResult(path, {}, true); 399 } 400 401 void WiFi::Certification(const KeyValueStore& properties) { 402 dispatcher()->PostTask(Bind(&WiFi::CertificationTask, 403 weak_ptr_factory_.GetWeakPtr(), properties)); 404 } 405 406 void WiFi::EAPEvent(const string& status, const string& parameter) { 407 dispatcher()->PostTask(Bind(&WiFi::EAPEventTask, 408 weak_ptr_factory_.GetWeakPtr(), 409 status, 410 parameter)); 411 } 412 413 void WiFi::PropertiesChanged(const KeyValueStore& properties) { 414 SLOG(this, 2) << __func__; 415 // Called from D-Bus signal handler, but may need to send a D-Bus 416 // message. So defer work to event loop. 417 dispatcher()->PostTask(Bind(&WiFi::PropertiesChangedTask, 418 weak_ptr_factory_.GetWeakPtr(), properties)); 419 } 420 421 void WiFi::ScanDone(const bool& success) { 422 LOG(INFO) << __func__; 423 424 // Defer handling of scan result processing, because that processing 425 // may require the the registration of new D-Bus objects. And such 426 // registration can't be done in the context of a D-Bus signal 427 // handler. 428 if (pending_scan_results_) { 429 pending_scan_results_->is_complete = true; 430 return; 431 } 432 if (success) { 433 scan_failed_callback_.Cancel(); 434 dispatcher()->PostTask( 435 Bind(&WiFi::ScanDoneTask, weak_ptr_factory_.GetWeakPtr())); 436 } else { 437 scan_failed_callback_.Reset( 438 Bind(&WiFi::ScanFailedTask, weak_ptr_factory_.GetWeakPtr())); 439 dispatcher()->PostDelayedTask(scan_failed_callback_.callback(), 440 kPostScanFailedDelayMilliseconds); 441 } 442 } 443 444 void WiFi::ConnectTo(WiFiService* service) { 445 CHECK(service) << "Can't connect to NULL service."; 446 string network_path; 447 448 // Ignore this connection attempt if suppplicant is not present. 449 // This is possible when we try to connect right after WiFi 450 // boostrapping is completed (through weaved). Refer to b/24605760 451 // for more information. 452 // Once supplicant is detected, shill will auto-connect to this 453 // service (if this service is configured for auto-connect) when 454 // it is discovered in the scan. 455 if (!supplicant_present_) { 456 LOG(ERROR) << "Trying to connect before supplicant is present"; 457 return; 458 } 459 460 // TODO(quiche): Handle cases where already connected. 461 if (pending_service_ && pending_service_ == service) { 462 // TODO(quiche): Return an error to the caller. crbug.com/206812 463 LOG(INFO) << "WiFi " << link_name() << " ignoring ConnectTo service " 464 << service->unique_name() 465 << ", which is already pending."; 466 return; 467 } 468 469 if (pending_service_ && pending_service_ != service) { 470 LOG(INFO) << "Connecting to service. " 471 << LogSSID(service->unique_name()) << ", " 472 << "bssid: " << service->bssid() << ", " 473 << "mode: " << service->mode() << ", " 474 << "key management: " << service->key_management() << ", " 475 << "physical mode: " << service->physical_mode() << ", " 476 << "frequency: " << service->frequency(); 477 // This is a signal to SetPendingService(nullptr) to not modify the scan 478 // state since the overall story arc isn't reflected by the disconnect. 479 // It is, instead, described by the transition to either kScanFoundNothing 480 // or kScanConnecting (made by |SetPendingService|, below). 481 if (scan_method_ != kScanMethodNone) { 482 SetScanState(kScanTransitionToConnecting, scan_method_, __func__); 483 } 484 // Explicitly disconnect pending service. 485 pending_service_->set_expecting_disconnect(true); 486 DisconnectFrom(pending_service_.get()); 487 } 488 489 Error unused_error; 490 network_path = FindNetworkRpcidForService(service, &unused_error); 491 if (network_path.empty()) { 492 KeyValueStore service_params = 493 service->GetSupplicantConfigurationParameters(); 494 const uint32_t scan_ssid = 1; // "True": Use directed probe. 495 service_params.SetUint(WPASupplicant::kNetworkPropertyScanSSID, scan_ssid); 496 AppendBgscan(service, &service_params); 497 service_params.SetUint(WPASupplicant::kNetworkPropertyDisableVHT, 498 provider_->disable_vht()); 499 if (!supplicant_interface_proxy_->AddNetwork(service_params, 500 &network_path)) { 501 LOG(ERROR) << "Failed to add network"; 502 SetScanState(kScanIdle, scan_method_, __func__); 503 return; 504 } 505 CHECK(!network_path.empty()); // No DBus path should be empty. 506 rpcid_by_service_[service] = network_path; 507 } 508 509 if (service->HasRecentConnectionIssues()) { 510 SetConnectionDebugging(true); 511 } 512 513 // Enable HT40 for this network in case if it was disabled previously due to 514 // unreliable link. 515 supplicant_interface_proxy_->SetHT40Enable(network_path, true); 516 517 supplicant_interface_proxy_->SelectNetwork(network_path); 518 SetPendingService(service); 519 CHECK(current_service_.get() != pending_service_.get()); 520 521 // SelectService here (instead of in LinkEvent, like Ethernet), so 522 // that, if we fail to bring up L2, we can attribute failure correctly. 523 // 524 // TODO(quiche): When we add code for dealing with connection failures, 525 // reconsider if this is the right place to change the selected service. 526 // see discussion in crbug.com/203282. 527 SelectService(service); 528 } 529 530 void WiFi::DisconnectFromIfActive(WiFiService* service) { 531 SLOG(this, 2) << __func__ << " service " << service->unique_name(); 532 533 if (service != current_service_ && service != pending_service_) { 534 if (!service->IsActive(nullptr)) { 535 SLOG(this, 2) << "In " << __func__ << "(): service " 536 << service->unique_name() 537 << " is not active, no need to initiate disconnect"; 538 return; 539 } 540 } 541 542 DisconnectFrom(service); 543 } 544 545 void WiFi::DisconnectFrom(WiFiService* service) { 546 SLOG(this, 2) << __func__ << " service " << service->unique_name(); 547 548 if (service != current_service_ && service != pending_service_) { 549 // TODO(quiche): Once we have asynchronous reply support, we should 550 // generate a D-Bus error here. (crbug.com/206812) 551 LOG(WARNING) << "In " << __func__ << "(): " 552 << " ignoring request to disconnect from service " 553 << service->unique_name() 554 << " which is neither current nor pending"; 555 return; 556 } 557 558 if (pending_service_ && service != pending_service_) { 559 // TODO(quiche): Once we have asynchronous reply support, we should 560 // generate a D-Bus error here. (crbug.com/206812) 561 LOG(WARNING) << "In " << __func__ << "(): " 562 << " ignoring request to disconnect from service " 563 << service->unique_name() 564 << " which is not the pending service."; 565 return; 566 } 567 568 if (!pending_service_ && service != current_service_) { 569 // TODO(quiche): Once we have asynchronous reply support, we should 570 // generate a D-Bus error here. (crbug.com/206812) 571 LOG(WARNING) << "In " << __func__ << "(): " 572 << " ignoring request to disconnect from service " 573 << service->unique_name() 574 << " which is not the current service."; 575 return; 576 } 577 578 if (pending_service_) { 579 // Since wpa_supplicant has not yet set CurrentBSS, we can't depend 580 // on this to drive the service state back to idle. Do that here. 581 // Update service state for pending service. 582 ServiceDisconnected(pending_service_); 583 } 584 585 SetPendingService(nullptr); 586 StopReconnectTimer(); 587 StopRequestingStationInfo(); 588 589 if (!supplicant_present_) { 590 LOG(ERROR) << "In " << __func__ << "(): " 591 << "wpa_supplicant is not present; silently resetting " 592 << "current_service_."; 593 if (current_service_ == selected_service()) { 594 DropConnection(); 595 } 596 current_service_ = nullptr; 597 return; 598 } 599 600 bool disconnect_in_progress = true; 601 // We'll call RemoveNetwork and reset |current_service_| after 602 // supplicant notifies us that the CurrentBSS has changed. 603 if (!supplicant_interface_proxy_->Disconnect()) { 604 disconnect_in_progress = false; 605 } 606 607 if (supplicant_state_ != WPASupplicant::kInterfaceStateCompleted || 608 !disconnect_in_progress) { 609 // Can't depend on getting a notification of CurrentBSS change. 610 // So effect changes immediately. For instance, this can happen when 611 // a disconnect is triggered by a BSS going away. 612 Error unused_error; 613 RemoveNetworkForService(service, &unused_error); 614 if (service == selected_service()) { 615 DropConnection(); 616 } else { 617 SLOG(this, 5) << __func__ << " skipping DropConnection, " 618 << "selected_service is " 619 << (selected_service() ? 620 selected_service()->unique_name() : "(null)"); 621 } 622 current_service_ = nullptr; 623 } 624 625 CHECK(current_service_ == nullptr || 626 current_service_.get() != pending_service_.get()); 627 } 628 629 bool WiFi::DisableNetwork(const string& network) { 630 std::unique_ptr<SupplicantNetworkProxyInterface> supplicant_network_proxy( 631 control_interface()->CreateSupplicantNetworkProxy(network)); 632 if (!supplicant_network_proxy->SetEnabled(false)) { 633 LOG(ERROR) << "DisableNetwork for " << network << " failed."; 634 return false; 635 } 636 return true; 637 } 638 639 bool WiFi::RemoveNetwork(const string& network) { 640 return supplicant_interface_proxy_->RemoveNetwork(network); 641 } 642 643 void WiFi::SetHT40EnableForService(const WiFiService* service, bool enable) { 644 if (!supplicant_present_) { 645 LOG(ERROR) << "In " << __func__ << "(): " 646 << "wpa_supplicant is not present. Cannot SetHT40Enable."; 647 return; 648 } 649 650 Error error; 651 string rpcid = FindNetworkRpcidForService(service, &error); 652 if (rpcid.empty()) { 653 LOG(ERROR) << "Unable to find supplicant network."; 654 return; 655 } 656 657 if (!supplicant_interface_proxy_->SetHT40Enable(rpcid, enable)) { 658 LOG(ERROR) << "SetHT40Enable for " << rpcid << " failed."; 659 } 660 } 661 662 bool WiFi::IsIdle() const { 663 return !current_service_ && !pending_service_; 664 } 665 666 void WiFi::ClearCachedCredentials(const WiFiService* service) { 667 Error unused_error; 668 RemoveNetworkForService(service, &unused_error); 669 670 // Give up on the connection attempt for the pending service immediately since 671 // the credential for it had already changed. This will allow the Manager to 672 // start a new connection attempt for the pending service immediately without 673 // waiting for the pending connection timeout. 674 // current_service_ will get disconnect notification from the CurrentBSS 675 // change event, so no need to explicitly disconnect here. 676 if (service == pending_service_) { 677 LOG(INFO) << "Disconnect pending service: credential changed"; 678 DisconnectFrom(pending_service_.get()); 679 } 680 } 681 682 void WiFi::NotifyEndpointChanged(const WiFiEndpointConstRefPtr& endpoint) { 683 provider_->OnEndpointUpdated(endpoint); 684 } 685 686 void WiFi::AppendBgscan(WiFiService* service, 687 KeyValueStore* service_params) const { 688 int scan_interval = kBackgroundScanIntervalSeconds; 689 string method = bgscan_method_; 690 if (method.empty()) { 691 // If multiple APs are detected for this SSID, configure the default method. 692 // Otherwise, disable background scanning completely. 693 if (service->GetEndpointCount() > 1) { 694 method = kDefaultBgscanMethod; 695 } else { 696 LOG(INFO) << "Background scan disabled -- single Endpoint for Service."; 697 return; 698 } 699 } else if (method.compare(WPASupplicant::kNetworkBgscanMethodNone) == 0) { 700 LOG(INFO) << "Background scan disabled -- chose None method."; 701 return; 702 } else { 703 // If the background scan method was explicitly specified, honor the 704 // configured background scan interval. 705 scan_interval = scan_interval_seconds_; 706 } 707 DCHECK(!method.empty()); 708 string config_string = StringPrintf("%s:%d:%d:%d", 709 method.c_str(), 710 bgscan_short_interval_seconds_, 711 bgscan_signal_threshold_dbm_, 712 scan_interval); 713 LOG(INFO) << "Background scan: " << config_string; 714 service_params->SetString(WPASupplicant::kNetworkPropertyBgscan, 715 config_string); 716 } 717 718 string WiFi::GetBgscanMethod(const int& /*argument*/, Error* /* error */) { 719 return bgscan_method_.empty() ? kDefaultBgscanMethod : bgscan_method_; 720 } 721 722 bool WiFi::SetBgscanMethod( 723 const int& /*argument*/, const string& method, Error* error) { 724 if (method != WPASupplicant::kNetworkBgscanMethodSimple && 725 method != WPASupplicant::kNetworkBgscanMethodLearn && 726 method != WPASupplicant::kNetworkBgscanMethodNone) { 727 const string error_message = 728 StringPrintf("Unrecognized bgscan method %s", method.c_str()); 729 LOG(WARNING) << error_message; 730 error->Populate(Error::kInvalidArguments, error_message); 731 return false; 732 } 733 if (bgscan_method_ == method) { 734 return false; 735 } 736 bgscan_method_ = method; 737 // We do not update kNetworkPropertyBgscan for |pending_service_| or 738 // |current_service_|, because supplicant does not allow for 739 // reconfiguration without disconnect and reconnect. 740 return true; 741 } 742 743 bool WiFi::SetBgscanShortInterval(const uint16_t& seconds, Error* /*error*/) { 744 if (bgscan_short_interval_seconds_ == seconds) { 745 return false; 746 } 747 bgscan_short_interval_seconds_ = seconds; 748 // We do not update kNetworkPropertyBgscan for |pending_service_| or 749 // |current_service_|, because supplicant does not allow for 750 // reconfiguration without disconnect and reconnect. 751 return true; 752 } 753 754 bool WiFi::SetBgscanSignalThreshold(const int32_t& dbm, Error* /*error*/) { 755 if (bgscan_signal_threshold_dbm_ == dbm) { 756 return false; 757 } 758 bgscan_signal_threshold_dbm_ = dbm; 759 // We do not update kNetworkPropertyBgscan for |pending_service_| or 760 // |current_service_|, because supplicant does not allow for 761 // reconfiguration without disconnect and reconnect. 762 return true; 763 } 764 765 bool WiFi::SetRoamThreshold(const uint16_t& threshold, Error* /*error*/) { 766 roam_threshold_db_ = threshold; 767 if (!current_service_ || !current_service_->roam_threshold_db_set()) { 768 supplicant_interface_proxy_->SetRoamThreshold(threshold); 769 } 770 return true; 771 } 772 773 bool WiFi::SetScanInterval(const uint16_t& seconds, Error* /*error*/) { 774 if (scan_interval_seconds_ == seconds) { 775 return false; 776 } 777 scan_interval_seconds_ = seconds; 778 if (running()) { 779 StartScanTimer(); 780 } 781 // The scan interval affects both foreground scans (handled by 782 // |scan_timer_callback_|), and background scans (handled by 783 // supplicant). However, we do not update |pending_service_| or 784 // |current_service_|, because supplicant does not allow for 785 // reconfiguration without disconnect and reconnect. 786 return true; 787 } 788 789 void WiFi::ClearBgscanMethod(const int& /*argument*/, Error* /*error*/) { 790 bgscan_method_.clear(); 791 } 792 793 void WiFi::CurrentBSSChanged(const string& new_bss) { 794 SLOG(this, 3) << "WiFi " << link_name() << " CurrentBSS " 795 << supplicant_bss_ << " -> " << new_bss; 796 supplicant_bss_ = new_bss; 797 has_already_completed_ = false; 798 is_roaming_in_progress_ = false; 799 800 // Any change in CurrentBSS means supplicant is actively changing our 801 // connectivity. We no longer need to track any previously pending 802 // reconnect. 803 StopReconnectTimer(); 804 StopRequestingStationInfo(); 805 806 if (new_bss == WPASupplicant::kCurrentBSSNull) { 807 HandleDisconnect(); 808 if (!provider_->GetHiddenSSIDList().empty()) { 809 // Before disconnecting, wpa_supplicant probably scanned for 810 // APs. So, in the normal case, we defer to the timer for the next scan. 811 // 812 // However, in the case of hidden SSIDs, supplicant knows about 813 // at most one of them. (That would be the hidden SSID we were 814 // connected to, if applicable.) 815 // 816 // So, in this case, we initiate an immediate scan. This scan 817 // will include the hidden SSIDs we know about (up to the limit of 818 // kScanMAxSSIDsPerScan). 819 // 820 // We may want to reconsider this immediate scan, if/when shill 821 // takes greater responsibility for scanning (vs. letting 822 // supplicant handle most of it). 823 Scan(kProgressiveScan, nullptr, __func__); 824 } 825 } else { 826 HandleRoam(new_bss); 827 } 828 829 // Reset the EAP handler only after calling HandleDisconnect() above 830 // so our EAP state could be used to detect a failed authentication. 831 eap_state_handler_->Reset(); 832 833 // If we are selecting a new service, or if we're clearing selection 834 // of a something other than the pending service, call SelectService. 835 // Otherwise skip SelectService, since this will cause the pending 836 // service to be marked as Idle. 837 if (current_service_ || selected_service() != pending_service_) { 838 SelectService(current_service_); 839 } 840 841 // Invariant check: a Service can either be current, or pending, but 842 // not both. 843 CHECK(current_service_.get() != pending_service_.get() || 844 current_service_.get() == nullptr); 845 846 // If we are no longer debugging a problematic WiFi connection, return 847 // to the debugging level indicated by the WiFi debugging scope. 848 if ((!current_service_ || !current_service_->HasRecentConnectionIssues()) && 849 (!pending_service_ || !pending_service_->HasRecentConnectionIssues())) { 850 SetConnectionDebugging(false); 851 } 852 } 853 854 void WiFi::DisconnectReasonChanged(const int32_t new_disconnect_reason) { 855 if (new_disconnect_reason == kDefaultDisconnectReason) { 856 SLOG(this, 3) << "WiFi clearing DisconnectReason for " << link_name(); 857 } else { 858 string update = ""; 859 if (supplicant_disconnect_reason_ != kDefaultDisconnectReason) { 860 update = StringPrintf(" (was %d)", supplicant_disconnect_reason_); 861 } 862 LOG(INFO) << "WiFi " << link_name() 863 << " supplicant updated DisconnectReason to " 864 << new_disconnect_reason << update; 865 } 866 supplicant_disconnect_reason_ = new_disconnect_reason; 867 } 868 869 void WiFi::HandleDisconnect() { 870 // Identify the affected service. We expect to get a disconnect 871 // event when we fall off a Service that we were connected 872 // to. However, we also allow for the case where we get a disconnect 873 // event while attempting to connect from a disconnected state. 874 WiFiService* affected_service = 875 current_service_.get() ? current_service_.get() : pending_service_.get(); 876 877 if (!affected_service) { 878 SLOG(this, 2) << "WiFi " << link_name() 879 << " disconnected while not connected or connecting"; 880 return; 881 } 882 883 SLOG(this, 2) << "WiFi " << link_name() << " disconnected from " 884 << " (or failed to connect to) service " 885 << affected_service->unique_name(); 886 887 if (affected_service == current_service_.get() && pending_service_.get()) { 888 // Current service disconnected intentionally for network switching, 889 // set service state to idle. 890 affected_service->SetState(Service::kStateIdle); 891 } else { 892 // Perform necessary handling for disconnected service. 893 ServiceDisconnected(affected_service); 894 } 895 896 current_service_ = nullptr; 897 898 if (affected_service == selected_service()) { 899 // If our selected service has disconnected, destroy IP configuration state. 900 DropConnection(); 901 } 902 903 Error error; 904 if (!DisableNetworkForService(affected_service, &error)) { 905 if (error.type() == Error::kNotFound) { 906 SLOG(this, 2) << "WiFi " << link_name() << " disconnected from " 907 << " (or failed to connect to) service " 908 << affected_service->unique_name() << ", " 909 << "but could not find supplicant network to disable."; 910 } else { 911 LOG(FATAL) << "DisableNetwork failed on " << link_name() 912 << "for service " << affected_service->unique_name() << "."; 913 } 914 } 915 916 metrics()->NotifySignalAtDisconnect(*affected_service, 917 affected_service->SignalLevel()); 918 affected_service->NotifyCurrentEndpoint(nullptr); 919 metrics()->NotifyServiceDisconnect(*affected_service); 920 921 if (affected_service == pending_service_.get()) { 922 // The attempt to connect to |pending_service_| failed. Clear 923 // |pending_service_|, to indicate we're no longer in the middle 924 // of a connect request. 925 SetPendingService(nullptr); 926 } else if (pending_service_.get()) { 927 // We've attributed the disconnection to what was the 928 // |current_service_|, rather than the |pending_service_|. 929 // 930 // If we're wrong about that (i.e. supplicant reported this 931 // CurrentBSS change after attempting to connect to 932 // |pending_service_|), we're depending on supplicant to retry 933 // connecting to |pending_service_|, and delivering another 934 // CurrentBSS change signal in the future. 935 // 936 // Log this fact, to help us debug (in case our assumptions are 937 // wrong). 938 SLOG(this, 2) << "WiFi " << link_name() << " pending connection to service " 939 << pending_service_->unique_name() 940 << " after disconnect"; 941 } 942 943 // If we disconnect, initially scan at a faster frequency, to make sure 944 // we've found all available APs. 945 RestartFastScanAttempts(); 946 } 947 948 void WiFi::ServiceDisconnected(WiFiServiceRefPtr affected_service) { 949 SLOG(this, 2) << __func__ << " service " << affected_service->unique_name(); 950 951 // Check if service was explicitly disconnected due to failure or 952 // is explicitly disconnected by user. 953 if (!affected_service->IsInFailState() && 954 !affected_service->explicitly_disconnected() && 955 !affected_service->expecting_disconnect()) { 956 // Determine disconnect failure reason. 957 Service::ConnectFailure failure; 958 if (SuspectCredentials(affected_service, &failure)) { 959 // If we suspect bad credentials, set failure, to trigger an error 960 // mole in Chrome. 961 affected_service->SetFailure(failure); 962 LOG(ERROR) << "Connection failure is due to suspect credentials: " 963 << "returning " 964 << Service::ConnectFailureToString(failure); 965 } else { 966 // Disconnected due to inability to connect to service, most likely 967 // due to roaming out of range. 968 LOG(ERROR) << "Disconnected due to inability to connect to the service."; 969 affected_service->SetFailure(Service::kFailureOutOfRange); 970 } 971 } 972 973 // Set service state back to idle, so this service can be used for 974 // future connections. 975 affected_service->SetState(Service::kStateIdle); 976 } 977 978 // We use the term "Roam" loosely. In particular, we include the case 979 // where we "Roam" to a BSS from the disconnected state. 980 void WiFi::HandleRoam(const string& new_bss) { 981 EndpointMap::iterator endpoint_it = endpoint_by_rpcid_.find(new_bss); 982 if (endpoint_it == endpoint_by_rpcid_.end()) { 983 LOG(WARNING) << "WiFi " << link_name() << " connected to unknown BSS " 984 << new_bss; 985 return; 986 } 987 988 const WiFiEndpointConstRefPtr endpoint(endpoint_it->second); 989 WiFiServiceRefPtr service = provider_->FindServiceForEndpoint(endpoint); 990 if (!service.get()) { 991 LOG(WARNING) << "WiFi " << link_name() 992 << " could not find Service for Endpoint " 993 << endpoint->bssid_string() 994 << " (service will be unchanged)"; 995 return; 996 } 997 998 SLOG(this, 2) << "WiFi " << link_name() 999 << " roamed to Endpoint " << endpoint->bssid_string() 1000 << " " << LogSSID(endpoint->ssid_string()); 1001 1002 service->NotifyCurrentEndpoint(endpoint); 1003 1004 if (pending_service_.get() && 1005 service.get() != pending_service_.get()) { 1006 // The Service we've roamed on to is not the one we asked for. 1007 // We assume that this is transient, and that wpa_supplicant 1008 // is trying / will try to connect to |pending_service_|. 1009 // 1010 // If it succeeds, we'll end up back here, but with |service| 1011 // pointing at the same service as |pending_service_|. 1012 // 1013 // If it fails, we'll process things in HandleDisconnect. 1014 // 1015 // So we leave |pending_service_| untouched. 1016 SLOG(this, 2) << "WiFi " << link_name() 1017 << " new current Endpoint " 1018 << endpoint->bssid_string() 1019 << " is not part of pending service " 1020 << pending_service_->unique_name(); 1021 1022 // Sanity check: if we didn't roam onto |pending_service_|, we 1023 // should still be on |current_service_|. 1024 if (service.get() != current_service_.get()) { 1025 LOG(WARNING) << "WiFi " << link_name() 1026 << " new current Endpoint " 1027 << endpoint->bssid_string() 1028 << " is neither part of pending service " 1029 << pending_service_->unique_name() 1030 << " nor part of current service " 1031 << (current_service_ ? 1032 current_service_->unique_name() : 1033 "(nullptr)"); 1034 // wpa_supplicant has no knowledge of the pending_service_ at this point. 1035 // Disconnect the pending_service_, so that it can be connectable again. 1036 // Otherwise, we'd have to wait for the pending timeout to trigger the 1037 // disconnect. This will speed up the connection attempt process for 1038 // the pending_service_. 1039 DisconnectFrom(pending_service_.get()); 1040 } 1041 return; 1042 } 1043 1044 if (pending_service_.get()) { 1045 // We assume service.get() == pending_service_.get() here, because 1046 // of the return in the previous if clause. 1047 // 1048 // Boring case: we've connected to the service we asked 1049 // for. Simply update |current_service_| and |pending_service_|. 1050 current_service_ = service; 1051 SetScanState(kScanConnected, scan_method_, __func__); 1052 SetPendingService(nullptr); 1053 // Use WiFi service-specific roam threshold if it is set, otherwise use WiFi 1054 // device-wide roam threshold. 1055 if (current_service_->roam_threshold_db_set()) { 1056 supplicant_interface_proxy_->SetRoamThreshold( 1057 current_service_->roam_threshold_db()); 1058 } else { 1059 supplicant_interface_proxy_->SetRoamThreshold(roam_threshold_db_); 1060 } 1061 return; 1062 } 1063 1064 // |pending_service_| was nullptr, so we weren't attempting to connect 1065 // to a new Service. Sanity check that we're still on 1066 // |current_service_|. 1067 if (service.get() != current_service_.get()) { 1068 LOG(WARNING) 1069 << "WiFi " << link_name() 1070 << " new current Endpoint " 1071 << endpoint->bssid_string() 1072 << (current_service_.get() ? 1073 StringPrintf(" is not part of current service %s", 1074 current_service_->unique_name().c_str()) : 1075 " with no current service"); 1076 // We didn't expect to be here, but let's cope as well as we 1077 // can. Update |current_service_| to keep it in sync with 1078 // supplicant. 1079 current_service_ = service; 1080 1081 // If this service isn't already marked as actively connecting (likely, 1082 // since this service is a bit of a surprise) set the service as 1083 // associating. 1084 if (!current_service_->IsConnecting()) { 1085 current_service_->SetState(Service::kStateAssociating); 1086 } 1087 1088 return; 1089 } 1090 1091 // At this point, we know that |pending_service_| was nullptr, and that 1092 // we're still on |current_service_|. We should track this roaming 1093 // event so we can refresh our IPConfig if it succeeds. 1094 is_roaming_in_progress_ = true; 1095 1096 return; 1097 } 1098 1099 string WiFi::FindNetworkRpcidForService( 1100 const WiFiService* service, Error* error) { 1101 ReverseServiceMap::const_iterator rpcid_it = rpcid_by_service_.find(service); 1102 if (rpcid_it == rpcid_by_service_.end()) { 1103 const string error_message = 1104 StringPrintf( 1105 "WiFi %s cannot find supplicant network rpcid for service %s", 1106 link_name().c_str(), service->unique_name().c_str()); 1107 // There are contexts where this is not an error, such as when a service 1108 // is clearing whatever cached credentials may not exist. 1109 SLOG(this, 2) << error_message; 1110 if (error) { 1111 error->Populate(Error::kNotFound, error_message); 1112 } 1113 return ""; 1114 } 1115 1116 return rpcid_it->second; 1117 } 1118 1119 bool WiFi::DisableNetworkForService(const WiFiService* service, Error* error) { 1120 string rpcid = FindNetworkRpcidForService(service, error); 1121 if (rpcid.empty()) { 1122 // Error is already populated. 1123 return false; 1124 } 1125 1126 if (!DisableNetwork(rpcid)) { 1127 const string error_message = 1128 StringPrintf("WiFi %s cannot disable network for service %s: " 1129 "DBus operation failed for rpcid %s.", 1130 link_name().c_str(), service->unique_name().c_str(), 1131 rpcid.c_str()); 1132 Error::PopulateAndLog( 1133 FROM_HERE, error, Error::kOperationFailed, error_message); 1134 1135 // Make sure that such errored networks are removed, so problems do not 1136 // propagate to future connection attempts. 1137 RemoveNetwork(rpcid); 1138 rpcid_by_service_.erase(service); 1139 1140 return false; 1141 } 1142 1143 return true; 1144 } 1145 1146 bool WiFi::RemoveNetworkForService(const WiFiService* service, Error* error) { 1147 string rpcid = FindNetworkRpcidForService(service, error); 1148 if (rpcid.empty()) { 1149 // Error is already populated. 1150 return false; 1151 } 1152 1153 // Erase the rpcid from our tables regardless of failure below, since even 1154 // if in failure, we never want to use this network again. 1155 rpcid_by_service_.erase(service); 1156 1157 // TODO(quiche): Reconsider giving up immediately. Maybe give 1158 // wpa_supplicant some time to retry, first. 1159 if (!RemoveNetwork(rpcid)) { 1160 const string error_message = 1161 StringPrintf("WiFi %s cannot remove network for service %s: " 1162 "DBus operation failed for rpcid %s.", 1163 link_name().c_str(), service->unique_name().c_str(), 1164 rpcid.c_str()); 1165 Error::PopulateAndLog( 1166 FROM_HERE, error, Error::kOperationFailed, error_message); 1167 return false; 1168 } 1169 1170 return true; 1171 } 1172 1173 void WiFi::PendingScanResultsHandler() { 1174 CHECK(pending_scan_results_); 1175 SLOG(this, 2) << __func__ << " with " << pending_scan_results_->results.size() 1176 << " results and is_complete set to " 1177 << pending_scan_results_->is_complete; 1178 for (const auto result : pending_scan_results_->results) { 1179 if (result.is_removal) { 1180 BSSRemovedTask(result.path); 1181 } else { 1182 BSSAddedTask(result.path, result.properties); 1183 } 1184 } 1185 if (pending_scan_results_->is_complete) { 1186 ScanDoneTask(); 1187 } 1188 pending_scan_results_.reset(); 1189 } 1190 1191 bool WiFi::ParseWiphyIndex(const Nl80211Message& nl80211_message) { 1192 // Verify NL80211_CMD_NEW_WIPHY. 1193 if (nl80211_message.command() != NewWiphyMessage::kCommand) { 1194 LOG(ERROR) << "Received unexpected command: " << nl80211_message.command(); 1195 return false; 1196 } 1197 if (!nl80211_message.const_attributes()->GetU32AttributeValue( 1198 NL80211_ATTR_WIPHY, &wiphy_index_)) { 1199 LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY"; 1200 return false; 1201 } 1202 return true; 1203 } 1204 1205 void WiFi::OnScanStarted(const NetlinkMessage& netlink_message) { 1206 // We only handle scan triggers in this handler, which is are nl80211 messages 1207 // with the NL80211_CMD_TRIGGER_SCAN command. 1208 if (netlink_message.message_type() != Nl80211Message::GetMessageType()) { 1209 SLOG(this, 7) << __func__ << ": " 1210 << "Not a NL80211 Message"; 1211 return; 1212 } 1213 const Nl80211Message& scan_trigger_msg = 1214 *reinterpret_cast<const Nl80211Message*>(&netlink_message); 1215 if (scan_trigger_msg.command() != TriggerScanMessage::kCommand) { 1216 SLOG(this, 7) << __func__ << ": " 1217 << "Not a NL80211_CMD_TRIGGER_SCAN message"; 1218 return; 1219 } 1220 uint32_t wiphy_index; 1221 if (!scan_trigger_msg.const_attributes()->GetU32AttributeValue( 1222 NL80211_ATTR_WIPHY, &wiphy_index)) { 1223 LOG(ERROR) << "NL80211_CMD_TRIGGER_SCAN had no NL80211_ATTR_WIPHY"; 1224 return; 1225 } 1226 if (wiphy_index != wiphy_index_) { 1227 SLOG(this, 7) << __func__ << ": " 1228 << "Scan trigger not meant for this interface"; 1229 return; 1230 } 1231 bool is_active_scan = false; 1232 AttributeListConstRefPtr ssids; 1233 if (scan_trigger_msg.const_attributes()->ConstGetNestedAttributeList( 1234 NL80211_ATTR_SCAN_SSIDS, &ssids)) { 1235 AttributeIdIterator ssid_iter(*ssids); 1236 // If any SSIDs (even the empty wild card) are reported, an active scan was 1237 // launched. Otherwise, a passive scan was launched. 1238 is_active_scan = !ssid_iter.AtEnd(); 1239 } 1240 wake_on_wifi_->OnScanStarted(is_active_scan); 1241 } 1242 1243 void WiFi::BSSAddedTask(const string& path, const KeyValueStore& properties) { 1244 // Note: we assume that BSSIDs are unique across endpoints. This 1245 // means that if an AP reuses the same BSSID for multiple SSIDs, we 1246 // lose. 1247 WiFiEndpointRefPtr endpoint( 1248 new WiFiEndpoint(control_interface(), this, path, properties)); 1249 SLOG(this, 5) << "Found endpoint. " 1250 << "RPC path: " << path << ", " 1251 << LogSSID(endpoint->ssid_string()) << ", " 1252 << "bssid: " << endpoint->bssid_string() << ", " 1253 << "signal: " << endpoint->signal_strength() << ", " 1254 << "security: " << endpoint->security_mode() << ", " 1255 << "frequency: " << endpoint->frequency(); 1256 1257 if (endpoint->ssid_string().empty()) { 1258 // Don't bother trying to find or create a Service for an Endpoint 1259 // without an SSID. We wouldn't be able to connect to it anyway. 1260 return; 1261 } 1262 1263 if (endpoint->ssid()[0] == 0) { 1264 // Assume that an SSID starting with nullptr is bogus/misconfigured, 1265 // and filter it out. 1266 return; 1267 } 1268 1269 provider_->OnEndpointAdded(endpoint); 1270 1271 // Do this last, to maintain the invariant that any Endpoint we 1272 // know about has a corresponding Service. 1273 // 1274 // TODO(quiche): Write test to verify correct behavior in the case 1275 // where we get multiple BSSAdded events for a single endpoint. 1276 // (Old Endpoint's refcount should fall to zero, and old Endpoint 1277 // should be destroyed.) 1278 endpoint_by_rpcid_[path] = endpoint; 1279 endpoint->Start(); 1280 } 1281 1282 void WiFi::BSSRemovedTask(const string& path) { 1283 EndpointMap::iterator i = endpoint_by_rpcid_.find(path); 1284 if (i == endpoint_by_rpcid_.end()) { 1285 SLOG(this, 1) << "WiFi " << link_name() 1286 << " could not find BSS " << path 1287 << " to remove."; 1288 return; 1289 } 1290 1291 WiFiEndpointRefPtr endpoint = i->second; 1292 CHECK(endpoint); 1293 endpoint_by_rpcid_.erase(i); 1294 1295 WiFiServiceRefPtr service = provider_->OnEndpointRemoved(endpoint); 1296 if (!service) { 1297 return; 1298 } 1299 Error unused_error; 1300 RemoveNetworkForService(service.get(), &unused_error); 1301 1302 bool disconnect_service = !service->HasEndpoints() && 1303 (service->IsConnecting() || service->IsConnected()); 1304 1305 if (disconnect_service) { 1306 LOG(INFO) << "Disconnecting from service " << service->unique_name() 1307 << ": BSSRemoved"; 1308 DisconnectFrom(service.get()); 1309 } 1310 } 1311 1312 void WiFi::CertificationTask(const KeyValueStore& properties) { 1313 if (!current_service_) { 1314 LOG(ERROR) << "WiFi " << link_name() << " " << __func__ 1315 << " with no current service."; 1316 return; 1317 } 1318 1319 string subject; 1320 uint32_t depth; 1321 if (WPASupplicant::ExtractRemoteCertification(properties, &subject, &depth)) { 1322 current_service_->AddEAPCertification(subject, depth); 1323 } 1324 } 1325 1326 void WiFi::EAPEventTask(const string& status, const string& parameter) { 1327 if (!current_service_) { 1328 LOG(ERROR) << "WiFi " << link_name() << " " << __func__ 1329 << " with no current service."; 1330 return; 1331 } 1332 Service::ConnectFailure failure = Service::kFailureUnknown; 1333 eap_state_handler_->ParseStatus(status, parameter, &failure); 1334 if (failure == Service::kFailurePinMissing) { 1335 // wpa_supplicant can sometimes forget the PIN on disconnect from the AP. 1336 const string& pin = current_service_->eap()->pin(); 1337 Error unused_error; 1338 string rpcid = FindNetworkRpcidForService(current_service_.get(), 1339 &unused_error); 1340 if (!pin.empty() && !rpcid.empty()) { 1341 // We have a PIN configured, so we can provide it back to wpa_supplicant. 1342 LOG(INFO) << "Re-supplying PIN parameter to wpa_supplicant."; 1343 supplicant_interface_proxy_->NetworkReply( 1344 rpcid, WPASupplicant::kEAPRequestedParameterPIN, pin); 1345 failure = Service::kFailureUnknown; 1346 } 1347 } 1348 if (failure != Service::kFailureUnknown) { 1349 // Avoid a reporting failure twice by resetting EAP state handler early. 1350 eap_state_handler_->Reset(); 1351 Error unused_error; 1352 current_service_->DisconnectWithFailure(failure, &unused_error, __func__); 1353 } 1354 } 1355 1356 void WiFi::PropertiesChangedTask( 1357 const KeyValueStore& properties) { 1358 // TODO(quiche): Handle changes in other properties (e.g. signal 1359 // strength). 1360 1361 // Note that order matters here. In particular, we want to process 1362 // changes in the current BSS before changes in state. This is so 1363 // that we update the state of the correct Endpoint/Service. 1364 if (properties.ContainsRpcIdentifier( 1365 WPASupplicant::kInterfacePropertyCurrentBSS)) { 1366 CurrentBSSChanged( 1367 properties.GetRpcIdentifier( 1368 WPASupplicant::kInterfacePropertyCurrentBSS)); 1369 } 1370 1371 if (properties.ContainsString(WPASupplicant::kInterfacePropertyState)) { 1372 StateChanged(properties.GetString(WPASupplicant::kInterfacePropertyState)); 1373 } 1374 1375 if (properties.ContainsInt( 1376 WPASupplicant::kInterfacePropertyDisconnectReason)) { 1377 DisconnectReasonChanged( 1378 properties.GetInt(WPASupplicant::kInterfacePropertyDisconnectReason)); 1379 } 1380 } 1381 1382 void WiFi::ScanDoneTask() { 1383 SLOG(this, 2) << __func__ << " need_bss_flush_ " << need_bss_flush_; 1384 // Unsets this flag if it was set in InitiateScanInDarkResume since that scan 1385 // has completed. 1386 manager()->set_suppress_autoconnect(false); 1387 if (wake_on_wifi_->in_dark_resume()) { 1388 metrics()->NotifyDarkResumeScanResultsReceived(); 1389 } 1390 if (scan_session_) { 1391 // Post |ProgressiveScanTask| so it runs after any pending scan results 1392 // have been processed. This allows connections on new BSSes to be 1393 // started before we decide whether to abort the progressive scan or 1394 // continue scanning. 1395 dispatcher()->PostTask( 1396 Bind(&WiFi::ProgressiveScanTask, weak_ptr_factory_.GetWeakPtr())); 1397 } else { 1398 // Post |UpdateScanStateAfterScanDone| so it runs after any pending scan 1399 // results have been processed. This allows connections on new BSSes to be 1400 // started before we decide whether the scan was fruitful. 1401 dispatcher()->PostTask(Bind(&WiFi::UpdateScanStateAfterScanDone, 1402 weak_ptr_factory_.GetWeakPtr())); 1403 if ((provider_->NumAutoConnectableServices() < 1) && IsIdle()) { 1404 // Ensure we are also idle in case we are in the midst of connecting to 1405 // the only service that was available for auto-connect on the previous 1406 // scan (which will cause it to show up as unavailable for auto-connect 1407 // when we query the WiFiProvider this time). 1408 wake_on_wifi_->OnNoAutoConnectableServicesAfterScan( 1409 provider_->GetSsidsConfiguredForAutoConnect(), 1410 Bind(&WiFi::RemoveSupplicantNetworks, weak_ptr_factory_.GetWeakPtr()), 1411 Bind(&WiFi::TriggerPassiveScan, weak_ptr_factory_.GetWeakPtr())); 1412 } 1413 } 1414 if (need_bss_flush_) { 1415 CHECK(supplicant_interface_proxy_); 1416 // Compute |max_age| relative to |resumed_at_|, to account for the 1417 // time taken to scan. 1418 struct timeval now; 1419 uint32_t max_age; 1420 time_->GetTimeMonotonic(&now); 1421 max_age = kMaxBSSResumeAgeSeconds + (now.tv_sec - resumed_at_.tv_sec); 1422 supplicant_interface_proxy_->FlushBSS(max_age); 1423 need_bss_flush_ = false; 1424 } 1425 StartScanTimer(); 1426 } 1427 1428 void WiFi::ScanFailedTask() { 1429 SLOG(this, 2) << __func__; 1430 SetScanState(kScanIdle, kScanMethodNone, __func__); 1431 } 1432 1433 void WiFi::UpdateScanStateAfterScanDone() { 1434 if (scan_method_ == kScanMethodFull) { 1435 // Only notify the Manager on completion of full scans, since the manager 1436 // will replace any cached geolocation info with the BSSes we have right 1437 // now. 1438 manager()->OnDeviceGeolocationInfoUpdated(this); 1439 } 1440 if (scan_state_ == kScanBackgroundScanning) { 1441 // Going directly to kScanIdle (instead of to kScanFoundNothing) inhibits 1442 // some UMA reporting in SetScanState. That's desired -- we don't want 1443 // to report background scan results to UMA since the drivers may play 1444 // background scans over a longer period in order to not interfere with 1445 // traffic. 1446 SetScanState(kScanIdle, kScanMethodNone, __func__); 1447 } else if (scan_state_ != kScanIdle && IsIdle()) { 1448 SetScanState(kScanFoundNothing, scan_method_, __func__); 1449 } 1450 } 1451 1452 void WiFi::ScanTask() { 1453 SLOG(this, 2) << "WiFi " << link_name() << " scan requested."; 1454 if (!enabled()) { 1455 SLOG(this, 2) << "Ignoring scan request while device is not enabled."; 1456 SetScanState(kScanIdle, kScanMethodNone, __func__); // Probably redundant. 1457 return; 1458 } 1459 if (!supplicant_present_ || !supplicant_interface_proxy_.get()) { 1460 SLOG(this, 2) << "Ignoring scan request while supplicant is not present."; 1461 SetScanState(kScanIdle, kScanMethodNone, __func__); 1462 return; 1463 } 1464 if ((pending_service_.get() && pending_service_->IsConnecting()) || 1465 (current_service_.get() && current_service_->IsConnecting())) { 1466 SLOG(this, 2) << "Ignoring scan request while connecting to an AP."; 1467 return; 1468 } 1469 KeyValueStore scan_args; 1470 scan_args.SetString(WPASupplicant::kPropertyScanType, 1471 WPASupplicant::kScanTypeActive); 1472 1473 ByteArrays hidden_ssids = provider_->GetHiddenSSIDList(); 1474 if (!hidden_ssids.empty()) { 1475 // TODO(pstew): Devise a better method for time-sharing with SSIDs that do 1476 // not fit in. 1477 if (hidden_ssids.size() >= WPASupplicant::kScanMaxSSIDsPerScan) { 1478 hidden_ssids.erase( 1479 hidden_ssids.begin() + WPASupplicant::kScanMaxSSIDsPerScan - 1, 1480 hidden_ssids.end()); 1481 } 1482 // Add Broadcast SSID, signified by an empty ByteArray. If we specify 1483 // SSIDs to wpa_supplicant, we need to explicitly specify the default 1484 // behavior of doing a broadcast probe. 1485 hidden_ssids.push_back(ByteArray()); 1486 1487 scan_args.SetByteArrays(WPASupplicant::kPropertyScanSSIDs, hidden_ssids); 1488 } 1489 1490 if (!supplicant_interface_proxy_->Scan(scan_args)) { 1491 // A scan may fail if, for example, the wpa_supplicant vanishing 1492 // notification is posted after this task has already started running. 1493 LOG(WARNING) << "Scan failed"; 1494 return; 1495 } 1496 1497 // Only set the scan state/method if we are starting a full scan from 1498 // scratch. Keep the existing method if this is a failover from a 1499 // progressive scan. 1500 if (scan_state_ != kScanScanning) { 1501 SetScanState(IsIdle() ? kScanScanning : kScanBackgroundScanning, 1502 kScanMethodFull, __func__); 1503 } 1504 } 1505 1506 void WiFi::ProgressiveScanTask() { 1507 SLOG(this, 2) << __func__ << " - scan requested for " << link_name(); 1508 if (!enabled()) { 1509 LOG(INFO) << "Ignoring scan request while device is not enabled."; 1510 SetScanState(kScanIdle, kScanMethodNone, __func__); // Probably redundant. 1511 return; 1512 } 1513 if (!scan_session_) { 1514 SLOG(this, 2) << "No scan session -- returning"; 1515 SetScanState(kScanIdle, kScanMethodNone, __func__); 1516 return; 1517 } 1518 // TODO(wdg): We don't currently support progressive background scans. If 1519 // we did, we couldn't bail out, here, if we're connected. Progressive scan 1520 // state will have to be modified to include whether there was a connection 1521 // when the scan started. Then, this code would only bail out if we didn't 1522 // start with a connection but one exists at this point. 1523 if (!IsIdle()) { 1524 SLOG(this, 2) << "Ignoring scan request while connecting to an AP."; 1525 scan_session_.reset(); 1526 return; 1527 } 1528 if (scan_session_->HasMoreFrequencies()) { 1529 SLOG(this, 2) << "Initiating a scan -- returning"; 1530 SetScanState(kScanScanning, kScanMethodProgressive, __func__); 1531 // After us initiating a scan, supplicant will gather the scan results and 1532 // send us zero or more |BSSAdded| events followed by a |ScanDone|. 1533 scan_session_->InitiateScan(); 1534 return; 1535 } 1536 LOG(ERROR) << "A complete progressive scan turned-up nothing -- " 1537 << "do a regular scan"; 1538 scan_session_.reset(); 1539 SetScanState(kScanScanning, kScanMethodProgressiveFinishedToFull, __func__); 1540 LOG(INFO) << "Scan [full] on " << link_name() 1541 << " (connected to nothing on progressive scan) from " << __func__; 1542 ScanTask(); 1543 } 1544 1545 void WiFi::SetSchedScanTask(bool enable) { 1546 if (!supplicant_present_ || !supplicant_interface_proxy_.get()) { 1547 SLOG(this, 2) << "Ignoring sched scan configure request " 1548 << "while supplicant is not present."; 1549 return; 1550 } 1551 if (!supplicant_interface_proxy_->SetSchedScan(enable)) { 1552 LOG(WARNING) << "Failed to set SchedScan"; 1553 } 1554 } 1555 1556 void WiFi::OnFailedProgressiveScan() { 1557 LOG(ERROR) << "Couldn't issue a scan on " << link_name() 1558 << " -- doing a regular scan"; 1559 scan_session_.reset(); 1560 SetScanState(kScanScanning, kScanMethodProgressiveErrorToFull, __func__); 1561 LOG(INFO) << "Scan [full] on " << link_name() 1562 << " (failover from progressive scan) from " << __func__; 1563 ScanTask(); 1564 } 1565 1566 string WiFi::GetServiceLeaseName(const WiFiService& service) { 1567 return service.GetStorageIdentifier(); 1568 } 1569 1570 void WiFi::DestroyServiceLease(const WiFiService& service) { 1571 DestroyIPConfigLease(GetServiceLeaseName(service)); 1572 } 1573 1574 void WiFi::StateChanged(const string& new_state) { 1575 const string old_state = supplicant_state_; 1576 supplicant_state_ = new_state; 1577 LOG(INFO) << "WiFi " << link_name() << " " << __func__ << " " 1578 << old_state << " -> " << new_state; 1579 1580 if (new_state == WPASupplicant::kInterfaceStateCompleted || 1581 new_state == WPASupplicant::kInterfaceState4WayHandshake) { 1582 mac80211_monitor_->UpdateConnectedState(true); 1583 } else { 1584 mac80211_monitor_->UpdateConnectedState(false); 1585 } 1586 1587 if (old_state == WPASupplicant::kInterfaceStateDisconnected && 1588 new_state != WPASupplicant::kInterfaceStateDisconnected) { 1589 // The state has been changed from disconnect to something else, clearing 1590 // out disconnect reason to avoid confusion about future disconnects. 1591 DisconnectReasonChanged(kDefaultDisconnectReason); 1592 } 1593 1594 // Identify the service to which the state change applies. If 1595 // |pending_service_| is non-NULL, then the state change applies to 1596 // |pending_service_|. Otherwise, it applies to |current_service_|. 1597 // 1598 // This policy is driven by the fact that the |pending_service_| 1599 // doesn't become the |current_service_| until wpa_supplicant 1600 // reports a CurrentBSS change to the |pending_service_|. And the 1601 // CurrentBSS change won't be reported until the |pending_service_| 1602 // reaches the WPASupplicant::kInterfaceStateCompleted state. 1603 WiFiService* affected_service = 1604 pending_service_.get() ? pending_service_.get() : current_service_.get(); 1605 if (!affected_service) { 1606 SLOG(this, 2) << "WiFi " << link_name() << " " << __func__ 1607 << " with no service"; 1608 return; 1609 } 1610 1611 if (new_state == WPASupplicant::kInterfaceStateCompleted) { 1612 if (affected_service->IsConnected()) { 1613 StopReconnectTimer(); 1614 EnableHighBitrates(); 1615 if (is_roaming_in_progress_) { 1616 // This means wpa_supplicant completed a roam without an intervening 1617 // disconnect. We should renew our DHCP lease just in case the new 1618 // AP is on a different subnet than where we started. 1619 is_roaming_in_progress_ = false; 1620 const IPConfigRefPtr& ip_config = ipconfig(); 1621 if (ip_config) { 1622 LOG(INFO) << link_name() << " renewing L3 configuration after roam."; 1623 ip_config->RenewIP(); 1624 } 1625 } 1626 } else if (has_already_completed_) { 1627 LOG(INFO) << link_name() << " L3 configuration already started."; 1628 } else { 1629 provider_->IncrementConnectCount(affected_service->frequency()); 1630 if (AcquireIPConfigWithLeaseName( 1631 GetServiceLeaseName(*affected_service))) { 1632 LOG(INFO) << link_name() << " is up; started L3 configuration."; 1633 affected_service->SetState(Service::kStateConfiguring); 1634 if (affected_service->IsSecurityMatch(kSecurityWep)) { 1635 // With the overwhelming majority of WEP networks, we cannot assume 1636 // our credentials are correct just because we have successfully 1637 // connected. It is more useful to track received data as the L3 1638 // configuration proceeds to see if we can decrypt anything. 1639 receive_byte_count_at_connect_ = GetReceiveByteCount(); 1640 } else { 1641 affected_service->ResetSuspectedCredentialFailures(); 1642 } 1643 } else { 1644 LOG(ERROR) << "Unable to acquire DHCP config."; 1645 } 1646 } 1647 has_already_completed_ = true; 1648 } else if (new_state == WPASupplicant::kInterfaceStateAssociated) { 1649 affected_service->SetState(Service::kStateAssociating); 1650 } else if (new_state == WPASupplicant::kInterfaceStateAuthenticating || 1651 new_state == WPASupplicant::kInterfaceStateAssociating || 1652 new_state == WPASupplicant::kInterfaceState4WayHandshake || 1653 new_state == WPASupplicant::kInterfaceStateGroupHandshake) { 1654 // Ignore transitions into these states from Completed, to avoid 1655 // bothering the user when roaming, or re-keying. 1656 if (old_state != WPASupplicant::kInterfaceStateCompleted) 1657 affected_service->SetState(Service::kStateAssociating); 1658 // TODO(quiche): On backwards transitions, we should probably set 1659 // a timeout for getting back into the completed state. At present, 1660 // we depend on wpa_supplicant eventually reporting that CurrentBSS 1661 // has changed. But there may be cases where that signal is not sent. 1662 // (crbug.com/206208) 1663 } else if (new_state == WPASupplicant::kInterfaceStateDisconnected && 1664 affected_service == current_service_ && 1665 affected_service->IsConnected()) { 1666 // This means that wpa_supplicant failed in a re-connect attempt, but 1667 // may still be reconnecting. Give wpa_supplicant a limited amount of 1668 // time to transition out this condition by either connecting or changing 1669 // CurrentBSS. 1670 StartReconnectTimer(); 1671 } else { 1672 // Other transitions do not affect Service state. 1673 // 1674 // Note in particular that we ignore a State change into 1675 // kInterfaceStateDisconnected, in favor of observing the corresponding 1676 // change in CurrentBSS. 1677 } 1678 } 1679 1680 bool WiFi::SuspectCredentials( 1681 WiFiServiceRefPtr service, Service::ConnectFailure* failure) const { 1682 if (service->IsSecurityMatch(kSecurityPsk)) { 1683 if (supplicant_state_ == WPASupplicant::kInterfaceState4WayHandshake && 1684 service->AddSuspectedCredentialFailure()) { 1685 if (failure) { 1686 *failure = Service::kFailureBadPassphrase; 1687 } 1688 return true; 1689 } 1690 } else if (service->IsSecurityMatch(kSecurity8021x)) { 1691 if (eap_state_handler_->is_eap_in_progress() && 1692 service->AddSuspectedCredentialFailure()) { 1693 if (failure) { 1694 *failure = Service::kFailureEAPAuthentication; 1695 } 1696 return true; 1697 } 1698 } 1699 1700 return false; 1701 } 1702 1703 // static 1704 bool WiFi::SanitizeSSID(string* ssid) { 1705 CHECK(ssid); 1706 1707 size_t ssid_len = ssid->length(); 1708 size_t i; 1709 bool changed = false; 1710 1711 for (i = 0; i < ssid_len; ++i) { 1712 if (!IsPrintableAsciiChar((*ssid)[i])) { 1713 (*ssid)[i] = '?'; 1714 changed = true; 1715 } 1716 } 1717 1718 return changed; 1719 } 1720 1721 // static 1722 string WiFi::LogSSID(const string& ssid) { 1723 string out; 1724 for (const auto& chr : ssid) { 1725 // Replace '[' and ']' (in addition to non-printable characters) so that 1726 // it's easy to match the right substring through a non-greedy regex. 1727 if (chr == '[' || chr == ']' || !IsPrintableAsciiChar(chr)) { 1728 base::StringAppendF(&out, "\\x%02x", chr); 1729 } else { 1730 out += chr; 1731 } 1732 } 1733 return StringPrintf("[SSID=%s]", out.c_str()); 1734 } 1735 1736 void WiFi::OnLinkMonitorFailure() { 1737 // Invoke base class call first to allow it to determine the reliability of 1738 // the link. 1739 Device::OnLinkMonitorFailure(); 1740 1741 // If we have never found the gateway, let's be conservative and not 1742 // do anything, in case this network topology does not have a gateway. 1743 if (!link_monitor()->IsGatewayFound()) { 1744 LOG(INFO) << "In " << __func__ << "(): " 1745 << "Skipping reassociate since gateway was never found."; 1746 return; 1747 } 1748 1749 if (!supplicant_present_) { 1750 LOG(ERROR) << "In " << __func__ << "(): " 1751 << "wpa_supplicant is not present. Cannot reassociate."; 1752 return; 1753 } 1754 1755 // Skip reassociate attempt if service is not reliable, meaning multiple link 1756 // failures in short period of time. 1757 if (current_service_->unreliable()) { 1758 LOG(INFO) << "Current service is unreliable, skipping reassociate attempt."; 1759 return; 1760 } 1761 1762 // This will force a transition out of connected, if we are actually 1763 // connected. 1764 if (!supplicant_interface_proxy_->Reattach()) { 1765 LOG(ERROR) << "In " << __func__ << "(): failed to call Reattach()."; 1766 return; 1767 } 1768 1769 // If we don't eventually get a transition back into a connected state, 1770 // there is something wrong. 1771 StartReconnectTimer(); 1772 LOG(INFO) << "In " << __func__ << "(): Called Reattach()."; 1773 } 1774 1775 void WiFi::OnUnreliableLink() { 1776 Device::OnUnreliableLink(); 1777 1778 // Disable HT40 for the current network. 1779 SetHT40EnableForService(current_service_.get(), false); 1780 } 1781 1782 bool WiFi::ShouldUseArpGateway() const { 1783 return !IsUsingStaticIP(); 1784 } 1785 1786 void WiFi::DisassociateFromService(const WiFiServiceRefPtr& service) { 1787 SLOG(this, 2) << "In " << __func__ << " for service: " 1788 << service->unique_name(); 1789 DisconnectFromIfActive(service.get()); 1790 if (service == selected_service()) { 1791 DropConnection(); 1792 } 1793 Error unused_error; 1794 RemoveNetworkForService(service.get(), &unused_error); 1795 } 1796 1797 vector<GeolocationInfo> WiFi::GetGeolocationObjects() const { 1798 vector<GeolocationInfo> objects; 1799 for (const auto& endpoint_entry : endpoint_by_rpcid_) { 1800 GeolocationInfo geoinfo; 1801 const WiFiEndpointRefPtr& endpoint = endpoint_entry.second; 1802 geoinfo.AddField(kGeoMacAddressProperty, endpoint->bssid_string()); 1803 geoinfo.AddField(kGeoSignalStrengthProperty, 1804 StringPrintf("%d", endpoint->signal_strength())); 1805 geoinfo.AddField( 1806 kGeoChannelProperty, 1807 StringPrintf("%d", 1808 Metrics::WiFiFrequencyToChannel(endpoint->frequency()))); 1809 // TODO(gauravsh): Include age field. crbug.com/217554 1810 objects.push_back(geoinfo); 1811 } 1812 return objects; 1813 } 1814 1815 void WiFi::HelpRegisterDerivedInt32( 1816 PropertyStore* store, 1817 const string& name, 1818 int32_t(WiFi::*get)(Error* error), 1819 bool(WiFi::*set)(const int32_t& value, Error* error)) { 1820 store->RegisterDerivedInt32( 1821 name, 1822 Int32Accessor(new CustomAccessor<WiFi, int32_t>(this, get, set))); 1823 } 1824 1825 void WiFi::HelpRegisterDerivedUint16( 1826 PropertyStore* store, 1827 const string& name, 1828 uint16_t(WiFi::*get)(Error* error), 1829 bool(WiFi::*set)(const uint16_t& value, Error* error)) { 1830 store->RegisterDerivedUint16( 1831 name, 1832 Uint16Accessor(new CustomAccessor<WiFi, uint16_t>(this, get, set))); 1833 } 1834 1835 void WiFi::HelpRegisterConstDerivedBool( 1836 PropertyStore* store, 1837 const string& name, 1838 bool(WiFi::*get)(Error* error)) { 1839 store->RegisterDerivedBool( 1840 name, 1841 BoolAccessor(new CustomAccessor<WiFi, bool>(this, get, nullptr))); 1842 } 1843 1844 void WiFi::OnBeforeSuspend(const ResultCallback& callback) { 1845 if (!enabled()) { 1846 callback.Run(Error(Error::kSuccess)); 1847 return; 1848 } 1849 LOG(INFO) << __func__ << ": " 1850 << (IsConnectedToCurrentService() ? "connected" : "not connected"); 1851 StopScanTimer(); 1852 supplicant_process_proxy_->ExpectDisconnect(); 1853 uint32_t time_to_next_lease_renewal; 1854 bool have_dhcp_lease = 1855 TimeToNextDHCPLeaseRenewal(&time_to_next_lease_renewal); 1856 wake_on_wifi_->OnBeforeSuspend( 1857 IsConnectedToCurrentService(), 1858 provider_->GetSsidsConfiguredForAutoConnect(), 1859 callback, 1860 Bind(&Device::RenewDHCPLease, weak_ptr_factory_.GetWeakPtr()), 1861 Bind(&WiFi::RemoveSupplicantNetworks, weak_ptr_factory_.GetWeakPtr()), 1862 have_dhcp_lease, 1863 time_to_next_lease_renewal); 1864 } 1865 1866 void WiFi::OnDarkResume(const ResultCallback& callback) { 1867 if (!enabled()) { 1868 callback.Run(Error(Error::kSuccess)); 1869 return; 1870 } 1871 LOG(INFO) << __func__ << ": " 1872 << (IsConnectedToCurrentService() ? "connected" : "not connected"); 1873 StopScanTimer(); 1874 wake_on_wifi_->OnDarkResume( 1875 IsConnectedToCurrentService(), 1876 provider_->GetSsidsConfiguredForAutoConnect(), 1877 callback, 1878 Bind(&Device::RenewDHCPLease, weak_ptr_factory_.GetWeakPtr()), 1879 Bind(&WiFi::InitiateScanInDarkResume, weak_ptr_factory_.GetWeakPtr()), 1880 Bind(&WiFi::RemoveSupplicantNetworks, weak_ptr_factory_.GetWeakPtr())); 1881 } 1882 1883 void WiFi::OnAfterResume() { 1884 LOG(INFO) << __func__ << ": " 1885 << (IsConnectedToCurrentService() ? "connected" : "not connected"); 1886 Device::OnAfterResume(); // May refresh ipconfig_ 1887 dispatcher()->PostDelayedTask(Bind(&WiFi::ReportConnectedToServiceAfterWake, 1888 weak_ptr_factory_.GetWeakPtr()), 1889 kPostWakeConnectivityReportDelayMilliseconds); 1890 wake_on_wifi_->OnAfterResume(); 1891 1892 // We want to flush the BSS cache, but we don't want to conflict 1893 // with an active connection attempt. So record the need to flush, 1894 // and take care of flushing when the next scan completes. 1895 // 1896 // Note that supplicant will automatically expire old cache 1897 // entries (after, e.g., a BSS is not found in two consecutive 1898 // scans). However, our explicit flush accelerates re-association 1899 // in cases where a BSS disappeared while we were asleep. (See, 1900 // e.g. WiFiRoaming.005SuspendRoam.) 1901 time_->GetTimeMonotonic(&resumed_at_); 1902 need_bss_flush_ = true; 1903 1904 if (!IsConnectedToCurrentService()) { 1905 InitiateScan(kProgressiveScan); 1906 } 1907 1908 // Since we stopped the scan timer before suspending, start it again here. 1909 StartScanTimer(); 1910 1911 // Enable HT40 for current service in case if it was disabled previously due 1912 // to unreliable link. 1913 if (current_service_) { 1914 SetHT40EnableForService(current_service_.get(), true); 1915 } 1916 } 1917 1918 void WiFi::AbortScan() { 1919 if (scan_session_) { 1920 scan_session_.reset(); 1921 } 1922 SetScanState(kScanIdle, kScanMethodNone, __func__); 1923 } 1924 1925 void WiFi::InitiateScan(ScanType scan_type) { 1926 LOG(INFO) << __func__; 1927 // Abort any current scan (at the shill-level; let any request that's 1928 // already gone out finish) since we don't know when it started. 1929 AbortScan(); 1930 1931 if (IsIdle()) { 1932 // Not scanning/connecting/connected, so let's get things rolling. 1933 Scan(scan_type, nullptr, __func__); 1934 RestartFastScanAttempts(); 1935 } else { 1936 SLOG(this, 1) << __func__ 1937 << " skipping scan, already connecting or connected."; 1938 } 1939 } 1940 1941 void WiFi::InitiateScanInDarkResume(const FreqSet& freqs) { 1942 LOG(INFO) << __func__; 1943 AbortScan(); 1944 if (!IsIdle()) { 1945 SLOG(this, 1) << __func__ 1946 << " skipping scan, already connecting or connected."; 1947 return; 1948 } 1949 1950 CHECK(supplicant_interface_proxy_); 1951 // Force complete flush of BSS cache since we want WPA supplicant and shill to 1952 // have an accurate view of what endpoints are available in dark resume. This 1953 // prevents either from performing incorrect actions that can prolong dark 1954 // resume (e.g. attempting to auto-connect to a WiFi service whose endpoint 1955 // disappeared before the dark resume). 1956 if (!supplicant_interface_proxy_->FlushBSS(0)) { 1957 LOG(WARNING) << __func__ 1958 << ": Failed to flush wpa_supplicant BSS cache"; 1959 } 1960 // Suppress any autoconnect attempts until this scan is done and endpoints 1961 // are updated. 1962 manager()->set_suppress_autoconnect(true); 1963 1964 TriggerPassiveScan(freqs); 1965 } 1966 1967 void WiFi::TriggerPassiveScan(const FreqSet& freqs) { 1968 LOG(INFO) << __func__; 1969 TriggerScanMessage trigger_scan; 1970 trigger_scan.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX, 1971 interface_index()); 1972 if (!freqs.empty()) { 1973 SLOG(this, 3) << __func__ << ": " << "Scanning on specific channels"; 1974 trigger_scan.attributes()->CreateNl80211Attribute( 1975 NL80211_ATTR_SCAN_FREQUENCIES, NetlinkMessage::MessageContext()); 1976 1977 AttributeListRefPtr frequency_list; 1978 if (!trigger_scan.attributes()->GetNestedAttributeList( 1979 NL80211_ATTR_SCAN_FREQUENCIES, &frequency_list) || 1980 !frequency_list) { 1981 LOG(ERROR) << __func__ << ": " 1982 << "Couldn't get NL80211_ATTR_SCAN_FREQUENCIES"; 1983 } 1984 trigger_scan.attributes()->SetNestedAttributeHasAValue( 1985 NL80211_ATTR_SCAN_FREQUENCIES); 1986 1987 string attribute_name; 1988 int i = 0; 1989 for (uint32_t freq : freqs) { 1990 SLOG(this, 7) << __func__ << ": " 1991 << "Frequency-" << i << ": " << freq; 1992 attribute_name = StringPrintf("Frequency-%d", i); 1993 frequency_list->CreateU32Attribute(i, attribute_name.c_str()); 1994 frequency_list->SetU32AttributeValue(i, freq); 1995 ++i; 1996 } 1997 } 1998 1999 netlink_manager_->SendNl80211Message( 2000 &trigger_scan, 2001 Bind(&WiFi::OnTriggerPassiveScanResponse, weak_ptr_factory_.GetWeakPtr()), 2002 Bind(&NetlinkManager::OnAckDoNothing), 2003 Bind(&NetlinkManager::OnNetlinkMessageError)); 2004 } 2005 2006 void WiFi::OnConnected() { 2007 Device::OnConnected(); 2008 EnableHighBitrates(); 2009 if (current_service_ && 2010 current_service_->IsSecurityMatch(kSecurityWep)) { 2011 // With a WEP network, we are now reasonably certain the credentials are 2012 // correct, whereas with other network types we were able to determine 2013 // this earlier when the association process succeeded. 2014 current_service_->ResetSuspectedCredentialFailures(); 2015 } 2016 RequestStationInfo(); 2017 } 2018 2019 void WiFi::OnIPConfigFailure() { 2020 if (!current_service_) { 2021 LOG(ERROR) << "WiFi " << link_name() << " " << __func__ 2022 << " with no current service."; 2023 return; 2024 } 2025 if (current_service_->IsSecurityMatch(kSecurityWep) && 2026 GetReceiveByteCount() == receive_byte_count_at_connect_ && 2027 current_service_->AddSuspectedCredentialFailure()) { 2028 // If we've connected to a WEP network and haven't successfully 2029 // decrypted any bytes at all during the configuration process, 2030 // it is fair to suspect that our credentials to this network 2031 // may not be correct. 2032 Error error; 2033 current_service_->DisconnectWithFailure(Service::kFailureBadPassphrase, 2034 &error, 2035 __func__); 2036 return; 2037 } 2038 2039 Device::OnIPConfigFailure(); 2040 } 2041 2042 void WiFi::AddWakeOnPacketConnection(const string& ip_endpoint, Error* error) { 2043 wake_on_wifi_->AddWakeOnPacketConnection(ip_endpoint, error); 2044 } 2045 2046 void WiFi::RemoveWakeOnPacketConnection(const string& ip_endpoint, 2047 Error* error) { 2048 wake_on_wifi_->RemoveWakeOnPacketConnection(ip_endpoint, error); 2049 } 2050 2051 void WiFi::RemoveAllWakeOnPacketConnections(Error* error) { 2052 wake_on_wifi_->RemoveAllWakeOnPacketConnections(error); 2053 } 2054 2055 void WiFi::RestartFastScanAttempts() { 2056 fast_scans_remaining_ = kNumFastScanAttempts; 2057 StartScanTimer(); 2058 } 2059 2060 void WiFi::StartScanTimer() { 2061 SLOG(this, 2) << __func__; 2062 if (scan_interval_seconds_ == 0) { 2063 StopScanTimer(); 2064 return; 2065 } 2066 scan_timer_callback_.Reset( 2067 Bind(&WiFi::ScanTimerHandler, weak_ptr_factory_.GetWeakPtr())); 2068 // Repeat the first few scans after disconnect relatively quickly so we 2069 // have reasonable trust that no APs we are looking for are present. 2070 size_t wait_time_milliseconds = fast_scans_remaining_ > 0 ? 2071 kFastScanIntervalSeconds * 1000 : scan_interval_seconds_ * 1000; 2072 dispatcher()->PostDelayedTask(scan_timer_callback_.callback(), 2073 wait_time_milliseconds); 2074 SLOG(this, 5) << "Next scan scheduled for " << wait_time_milliseconds << "ms"; 2075 } 2076 2077 void WiFi::StopScanTimer() { 2078 SLOG(this, 2) << __func__; 2079 scan_timer_callback_.Cancel(); 2080 } 2081 2082 void WiFi::ScanTimerHandler() { 2083 SLOG(this, 2) << "WiFi Device " << link_name() << ": " << __func__; 2084 if (manager()->IsSuspending()) { 2085 SLOG(this, 5) << "Not scanning: still in suspend"; 2086 return; 2087 } 2088 if (scan_state_ == kScanIdle && IsIdle()) { 2089 Scan(kProgressiveScan, nullptr, __func__); 2090 if (fast_scans_remaining_ > 0) { 2091 --fast_scans_remaining_; 2092 } 2093 } else { 2094 if (scan_state_ != kScanIdle) { 2095 SLOG(this, 5) << "Skipping scan: scan_state_ is " << scan_state_; 2096 } 2097 if (current_service_) { 2098 SLOG(this, 5) << "Skipping scan: current_service_ is service " 2099 << current_service_->unique_name(); 2100 } 2101 if (pending_service_) { 2102 SLOG(this, 5) << "Skipping scan: pending_service_ is service" 2103 << pending_service_->unique_name(); 2104 } 2105 } 2106 StartScanTimer(); 2107 } 2108 2109 void WiFi::StartPendingTimer() { 2110 pending_timeout_callback_.Reset( 2111 Bind(&WiFi::PendingTimeoutHandler, weak_ptr_factory_.GetWeakPtr())); 2112 dispatcher()->PostDelayedTask(pending_timeout_callback_.callback(), 2113 kPendingTimeoutSeconds * 1000); 2114 } 2115 2116 void WiFi::StopPendingTimer() { 2117 SLOG(this, 2) << "WiFi Device " << link_name() << ": " << __func__; 2118 pending_timeout_callback_.Cancel(); 2119 } 2120 2121 void WiFi::SetPendingService(const WiFiServiceRefPtr& service) { 2122 SLOG(this, 2) << "WiFi " << link_name() << " setting pending service to " 2123 << (service ? service->unique_name(): "NULL"); 2124 if (service) { 2125 SetScanState(kScanConnecting, scan_method_, __func__); 2126 service->SetState(Service::kStateAssociating); 2127 StartPendingTimer(); 2128 } else { 2129 // SetPendingService(nullptr) is called in the following cases: 2130 // a) |ConnectTo|->|DisconnectFrom|. Connecting to a service, disconnect 2131 // the old service (scan_state_ == kScanTransitionToConnecting). No 2132 // state transition is needed here. 2133 // b) |HandleRoam|. Connected to a service, it's no longer pending 2134 // (scan_state_ == kScanIdle). No state transition is needed here. 2135 // c) |DisconnectFrom| and |HandleDisconnect|. Disconnected/disconnecting 2136 // from a service not during a scan (scan_state_ == kScanIdle). No 2137 // state transition is needed here. 2138 // d) |DisconnectFrom| and |HandleDisconnect|. Disconnected/disconnecting 2139 // from a service during a scan (scan_state_ == kScanScanning or 2140 // kScanConnecting). This is an odd case -- let's discard any 2141 // statistics we're gathering by transitioning directly into kScanIdle. 2142 if (scan_state_ == kScanScanning || 2143 scan_state_ == kScanBackgroundScanning || 2144 scan_state_ == kScanConnecting) { 2145 SetScanState(kScanIdle, kScanMethodNone, __func__); 2146 } 2147 if (pending_service_) { 2148 StopPendingTimer(); 2149 } 2150 } 2151 pending_service_ = service; 2152 } 2153 2154 void WiFi::PendingTimeoutHandler() { 2155 Error unused_error; 2156 LOG(INFO) << "WiFi Device " << link_name() << ": " << __func__; 2157 CHECK(pending_service_); 2158 SetScanState(kScanFoundNothing, scan_method_, __func__); 2159 WiFiServiceRefPtr pending_service = pending_service_; 2160 pending_service_->DisconnectWithFailure( 2161 Service::kFailureOutOfRange, &unused_error, __func__); 2162 2163 // A hidden service may have no endpoints, since wpa_supplicant 2164 // failed to attain a CurrentBSS. If so, the service has no 2165 // reference to |this| device and cannot call WiFi::DisconnectFrom() 2166 // to reset pending_service_. In this case, we must perform the 2167 // disconnect here ourselves. 2168 if (pending_service_) { 2169 CHECK(!pending_service_->HasEndpoints()); 2170 LOG(INFO) << "Hidden service was not found."; 2171 DisconnectFrom(pending_service_.get()); 2172 } 2173 2174 // DisconnectWithFailure will leave the pending service's state in failure 2175 // state. Reset its state back to idle, to allow it to be connectable again. 2176 pending_service->SetState(Service::kStateIdle); 2177 } 2178 2179 void WiFi::StartReconnectTimer() { 2180 if (!reconnect_timeout_callback_.IsCancelled()) { 2181 LOG(INFO) << "WiFi Device " << link_name() << ": " << __func__ 2182 << ": reconnect timer already running."; 2183 return; 2184 } 2185 LOG(INFO) << "WiFi Device " << link_name() << ": " << __func__; 2186 reconnect_timeout_callback_.Reset( 2187 Bind(&WiFi::ReconnectTimeoutHandler, weak_ptr_factory_.GetWeakPtr())); 2188 dispatcher()->PostDelayedTask(reconnect_timeout_callback_.callback(), 2189 kReconnectTimeoutSeconds * 1000); 2190 } 2191 2192 void WiFi::StopReconnectTimer() { 2193 SLOG(this, 2) << "WiFi Device " << link_name() << ": " << __func__; 2194 reconnect_timeout_callback_.Cancel(); 2195 } 2196 2197 void WiFi::ReconnectTimeoutHandler() { 2198 LOG(INFO) << "WiFi Device " << link_name() << ": " << __func__; 2199 reconnect_timeout_callback_.Cancel(); 2200 CHECK(current_service_); 2201 current_service_->SetFailure(Service::kFailureConnect); 2202 DisconnectFrom(current_service_.get()); 2203 } 2204 2205 void WiFi::OnSupplicantAppear() { 2206 LOG(INFO) << "WPA supplicant appeared."; 2207 if (supplicant_present_) { 2208 // Restart the WiFi device if it's started already. This will reset the 2209 // state and connect the device to the new WPA supplicant instance. 2210 if (enabled()) { 2211 Restart(); 2212 } 2213 return; 2214 } 2215 supplicant_present_ = true; 2216 ConnectToSupplicant(); 2217 } 2218 2219 void WiFi::OnSupplicantVanish() { 2220 LOG(INFO) << "WPA supplicant vanished."; 2221 if (!supplicant_present_) { 2222 return; 2223 } 2224 supplicant_present_ = false; 2225 // Restart the WiFi device if it's started already. This will effectively 2226 // suspend the device until the WPA supplicant reappears. 2227 if (enabled()) { 2228 Restart(); 2229 } 2230 } 2231 2232 void WiFi::OnWiFiDebugScopeChanged(bool enabled) { 2233 SLOG(this, 2) << "WiFi debug scope changed; enable is now " << enabled; 2234 if (!Device::enabled() || !supplicant_present_) { 2235 SLOG(this, 2) << "Supplicant process proxy not connected."; 2236 return; 2237 } 2238 string current_level; 2239 if (!supplicant_process_proxy_->GetDebugLevel(¤t_level)) { 2240 LOG(ERROR) << __func__ << ": Failed to get wpa_supplicant debug level."; 2241 return; 2242 } 2243 2244 if (current_level != WPASupplicant::kDebugLevelInfo && 2245 current_level != WPASupplicant::kDebugLevelDebug) { 2246 SLOG(this, 2) << "WiFi debug level is currently " 2247 << current_level 2248 << "; assuming that it is being controlled elsewhere."; 2249 return; 2250 } 2251 string new_level = enabled ? WPASupplicant::kDebugLevelDebug : 2252 WPASupplicant::kDebugLevelInfo; 2253 2254 if (new_level == current_level) { 2255 SLOG(this, 2) << "WiFi debug level is already the desired level " 2256 << current_level; 2257 return; 2258 } 2259 2260 if (!supplicant_process_proxy_->SetDebugLevel(new_level)) { 2261 LOG(ERROR) << __func__ << ": Failed to set wpa_supplicant debug level."; 2262 } 2263 } 2264 2265 void WiFi::SetConnectionDebugging(bool enabled) { 2266 if (is_debugging_connection_ == enabled) { 2267 return; 2268 } 2269 OnWiFiDebugScopeChanged( 2270 enabled || 2271 ScopeLogger::GetInstance()->IsScopeEnabled(ScopeLogger::kWiFi)); 2272 is_debugging_connection_ = enabled; 2273 } 2274 2275 void WiFi::SetSupplicantInterfaceProxy( 2276 SupplicantInterfaceProxyInterface* supplicant_interface_proxy) { 2277 if (supplicant_interface_proxy) { 2278 supplicant_interface_proxy_.reset(supplicant_interface_proxy); 2279 tdls_manager_.reset(new TDLSManager(dispatcher(), 2280 supplicant_interface_proxy, 2281 link_name())); 2282 } else { 2283 supplicant_interface_proxy_.reset(); 2284 tdls_manager_.reset(); 2285 } 2286 } 2287 2288 void WiFi::ConnectToSupplicant() { 2289 LOG(INFO) << link_name() << ": " << (enabled() ? "enabled" : "disabled") 2290 << " supplicant: " 2291 << (supplicant_present_ ? "present" : "absent") 2292 << " proxy: " 2293 << (supplicant_interface_proxy_.get() ? "non-null" : "null"); 2294 // The check for |supplicant_interface_proxy_| is mainly for testing, 2295 // to avoid recreation of supplicant interface proxy. 2296 if (!enabled() || !supplicant_present_ || supplicant_interface_proxy_) { 2297 return; 2298 } 2299 OnWiFiDebugScopeChanged( 2300 ScopeLogger::GetInstance()->IsScopeEnabled(ScopeLogger::kWiFi)); 2301 2302 KeyValueStore create_interface_args; 2303 create_interface_args.SetString(WPASupplicant::kInterfacePropertyName, 2304 link_name()); 2305 create_interface_args.SetString(WPASupplicant::kInterfacePropertyDriver, 2306 WPASupplicant::kDriverNL80211); 2307 create_interface_args.SetString(WPASupplicant::kInterfacePropertyConfigFile, 2308 WPASupplicant::kSupplicantConfPath); 2309 if (!supplicant_process_proxy_->CreateInterface( 2310 create_interface_args, &supplicant_interface_path_)) { 2311 // Interface might've already been created, attempt to retrieve it. 2312 if (!supplicant_process_proxy_->GetInterface(link_name(), 2313 &supplicant_interface_path_)) { 2314 // TODO(quiche): Is it okay to crash here, if device is missing? 2315 LOG(ERROR) << __func__ << ": Failed to create interface with supplicant."; 2316 return; 2317 } 2318 } 2319 2320 SetSupplicantInterfaceProxy( 2321 control_interface()->CreateSupplicantInterfaceProxy( 2322 this, supplicant_interface_path_)); 2323 2324 RTNLHandler::GetInstance()->SetInterfaceFlags(interface_index(), IFF_UP, 2325 IFF_UP); 2326 // TODO(quiche) Set ApScan=1 and BSSExpireAge=190, like flimflam does? 2327 2328 // Clear out any networks that might previously have been configured 2329 // for this interface. 2330 supplicant_interface_proxy_->RemoveAllNetworks(); 2331 2332 // Flush interface's BSS cache, so that we get BSSAdded signals for 2333 // all BSSes (not just new ones since the last scan). 2334 supplicant_interface_proxy_->FlushBSS(0); 2335 2336 // TODO(pstew): Disable fast_reauth until supplicant can properly deal 2337 // with RADIUS servers that respond strangely to such requests. 2338 // crbug.com/208561 2339 if (!supplicant_interface_proxy_->SetFastReauth(false)) { 2340 LOG(ERROR) << "Failed to disable fast_reauth. " 2341 << "May be running an older version of wpa_supplicant."; 2342 } 2343 2344 if (!supplicant_interface_proxy_->SetRoamThreshold(roam_threshold_db_)) { 2345 LOG(ERROR) << "Failed to set roam_threshold. " 2346 << "May be running an older version of wpa_supplicant."; 2347 } 2348 2349 // Helps with passing WiFiRoaming.001SSIDSwitchBack. 2350 if (!supplicant_interface_proxy_->SetScanInterval(kRescanIntervalSeconds)) { 2351 LOG(ERROR) << "Failed to set scan_interval. " 2352 << "May be running an older version of wpa_supplicant."; 2353 } 2354 2355 if (!supplicant_interface_proxy_->SetDisableHighBitrates(true)) { 2356 LOG(ERROR) << "Failed to disable high bitrates. " 2357 << "May be running an older version of wpa_supplicant."; 2358 } 2359 2360 Scan(kProgressiveScan, nullptr, __func__); 2361 StartScanTimer(); 2362 } 2363 2364 void WiFi::EnableHighBitrates() { 2365 LOG(INFO) << "Enabling high bitrates."; 2366 if (!supplicant_interface_proxy_->EnableHighBitrates()) { 2367 LOG(ERROR) << "Failed to enable high rates"; 2368 } 2369 } 2370 2371 void WiFi::Restart() { 2372 LOG(INFO) << link_name() << " restarting."; 2373 WiFiRefPtr me = this; // Make sure we don't get destructed. 2374 // Go through the manager rather than starting and stopping the device 2375 // directly so that the device can be configured with the profile. 2376 manager()->DeregisterDevice(me); 2377 manager()->RegisterDevice(me); 2378 } 2379 2380 void WiFi::GetPhyInfo() { 2381 GetWiphyMessage get_wiphy; 2382 get_wiphy.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX, 2383 interface_index()); 2384 netlink_manager_->SendNl80211Message( 2385 &get_wiphy, 2386 Bind(&WiFi::OnNewWiphy, weak_ptr_factory_.GetWeakPtr()), 2387 Bind(&NetlinkManager::OnAckDoNothing), 2388 Bind(&NetlinkManager::OnNetlinkMessageError)); 2389 } 2390 2391 void WiFi::OnNewWiphy(const Nl80211Message& nl80211_message) { 2392 // Verify NL80211_CMD_NEW_WIPHY. 2393 if (nl80211_message.command() != NewWiphyMessage::kCommand) { 2394 LOG(ERROR) << "Received unexpected command:" 2395 << nl80211_message.command(); 2396 return; 2397 } 2398 2399 if (!nl80211_message.const_attributes()->GetStringAttributeValue( 2400 NL80211_ATTR_WIPHY_NAME, &phy_name_)) { 2401 LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY_NAME"; 2402 return; 2403 } 2404 mac80211_monitor_->Start(phy_name_); 2405 2406 wake_on_wifi_->ParseWakeOnWiFiCapabilities(nl80211_message); 2407 if (ParseWiphyIndex(nl80211_message)) { 2408 wake_on_wifi_->OnWiphyIndexReceived(wiphy_index_); 2409 } 2410 2411 // The attributes, for this message, are complicated. 2412 // NL80211_ATTR_BANDS contains an array of bands... 2413 AttributeListConstRefPtr wiphy_bands; 2414 if (!nl80211_message.const_attributes()->ConstGetNestedAttributeList( 2415 NL80211_ATTR_WIPHY_BANDS, &wiphy_bands)) { 2416 LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY_BANDS"; 2417 return; 2418 } 2419 2420 AttributeIdIterator band_iter(*wiphy_bands); 2421 for (; !band_iter.AtEnd(); band_iter.Advance()) { 2422 AttributeListConstRefPtr wiphy_band; 2423 if (!wiphy_bands->ConstGetNestedAttributeList(band_iter.GetId(), 2424 &wiphy_band)) { 2425 LOG(WARNING) << "WiFi band " << band_iter.GetId() << " not found"; 2426 continue; 2427 } 2428 2429 // ...Each band has a FREQS attribute... 2430 AttributeListConstRefPtr frequencies; 2431 if (!wiphy_band->ConstGetNestedAttributeList(NL80211_BAND_ATTR_FREQS, 2432 &frequencies)) { 2433 LOG(ERROR) << "BAND " << band_iter.GetId() 2434 << " had no 'frequencies' attribute"; 2435 continue; 2436 } 2437 2438 // ...And each FREQS attribute contains an array of information about the 2439 // frequency... 2440 AttributeIdIterator freq_iter(*frequencies); 2441 for (; !freq_iter.AtEnd(); freq_iter.Advance()) { 2442 AttributeListConstRefPtr frequency; 2443 if (frequencies->ConstGetNestedAttributeList(freq_iter.GetId(), 2444 &frequency)) { 2445 // ...Including the frequency, itself (the part we want). 2446 uint32_t frequency_value = 0; 2447 if (frequency->GetU32AttributeValue(NL80211_FREQUENCY_ATTR_FREQ, 2448 &frequency_value)) { 2449 SLOG(this, 7) << "Found frequency[" << freq_iter.GetId() 2450 << "] = " << frequency_value; 2451 all_scan_frequencies_.insert(frequency_value); 2452 } 2453 } 2454 } 2455 } 2456 } 2457 2458 void WiFi::OnTriggerPassiveScanResponse(const Nl80211Message& netlink_message) { 2459 LOG(WARNING) << "Didn't expect _this_netlink message (" 2460 << netlink_message.command() << " here:"; 2461 netlink_message.Print(0, 0); 2462 return; 2463 } 2464 2465 KeyValueStore WiFi::GetLinkStatistics(Error* /*error*/) { 2466 return link_statistics_; 2467 } 2468 2469 bool WiFi::GetScanPending(Error* /* error */) { 2470 return scan_state_ == kScanScanning || scan_state_ == kScanBackgroundScanning; 2471 } 2472 2473 void WiFi::SetScanState(ScanState new_state, 2474 ScanMethod new_method, 2475 const char* reason) { 2476 if (new_state == kScanIdle) 2477 new_method = kScanMethodNone; 2478 if (new_state == kScanConnected) { 2479 // The scan method shouldn't be changed by the connection process, so 2480 // we'll put a CHECK, here, to verify. NOTE: this assumption is also 2481 // enforced by the parameters to the call to |ReportScanResultToUma|. 2482 CHECK(new_method == scan_method_); 2483 } 2484 2485 int log_level = 6; 2486 bool state_or_method_changed = true; 2487 bool is_terminal_state = false; 2488 if (new_state == scan_state_ && new_method == scan_method_) { 2489 log_level = 7; 2490 state_or_method_changed = false; 2491 } else if (new_state == kScanConnected || new_state == kScanFoundNothing) { 2492 // These 'terminal' states are slightly more interesting than the 2493 // intermediate states. 2494 // NOTE: Since background scan goes directly to kScanIdle (skipping over 2495 // the states required to set |is_terminal_state|), ReportScanResultToUma, 2496 // below, doesn't get called. That's intentional. 2497 log_level = 5; 2498 is_terminal_state = true; 2499 } 2500 2501 base::TimeDelta elapsed_time; 2502 if (new_state == kScanScanning || new_state == kScanBackgroundScanning) { 2503 if (!scan_timer_.Start()) { 2504 LOG(ERROR) << "Scan start unreliable"; 2505 } 2506 } else { 2507 if (!scan_timer_.GetElapsedTime(&elapsed_time)) { 2508 LOG(ERROR) << "Scan time unreliable"; 2509 } 2510 } 2511 SLOG(this, log_level) << (reason ? reason : "<unknown>") 2512 << " - " << link_name() 2513 << ": Scan state: " 2514 << ScanStateString(scan_state_, scan_method_) 2515 << " -> " << ScanStateString(new_state, new_method) 2516 << " @ " << elapsed_time.InMillisecondsF() 2517 << " ms into scan."; 2518 if (!state_or_method_changed) 2519 return; 2520 2521 // Actually change the state. 2522 ScanState old_state = scan_state_; 2523 ScanMethod old_method = scan_method_; 2524 bool old_scan_pending = GetScanPending(nullptr); 2525 scan_state_ = new_state; 2526 scan_method_ = new_method; 2527 bool new_scan_pending = GetScanPending(nullptr); 2528 if (old_scan_pending != new_scan_pending) { 2529 adaptor()->EmitBoolChanged(kScanningProperty, new_scan_pending); 2530 } 2531 switch (new_state) { 2532 case kScanIdle: 2533 metrics()->ResetScanTimer(interface_index()); 2534 metrics()->ResetConnectTimer(interface_index()); 2535 if (scan_session_) { 2536 scan_session_.reset(); 2537 } 2538 break; 2539 case kScanScanning: // FALLTHROUGH 2540 case kScanBackgroundScanning: 2541 if (new_state != old_state) { 2542 metrics()->NotifyDeviceScanStarted(interface_index()); 2543 } 2544 break; 2545 case kScanConnecting: 2546 metrics()->NotifyDeviceScanFinished(interface_index()); 2547 // TODO(wdg): Provide |is_auto_connecting| to this interface. For now, 2548 // I'll lie (because I don't care about the auto-connect metrics). 2549 metrics()->NotifyDeviceConnectStarted(interface_index(), false); 2550 break; 2551 case kScanConnected: 2552 metrics()->NotifyDeviceConnectFinished(interface_index()); 2553 break; 2554 case kScanFoundNothing: 2555 // Note that finishing a scan that hasn't started (if, for example, we 2556 // get here when we fail to complete a connection) does nothing. 2557 metrics()->NotifyDeviceScanFinished(interface_index()); 2558 metrics()->ResetConnectTimer(interface_index()); 2559 break; 2560 case kScanTransitionToConnecting: // FALLTHROUGH 2561 default: 2562 break; 2563 } 2564 if (is_terminal_state) { 2565 ReportScanResultToUma(new_state, old_method); 2566 // Now that we've logged a terminal state, let's call ourselves to 2567 // transition to the idle state. 2568 SetScanState(kScanIdle, kScanMethodNone, reason); 2569 } 2570 } 2571 2572 // static 2573 string WiFi::ScanStateString(ScanState state, ScanMethod method) { 2574 switch (state) { 2575 case kScanIdle: 2576 return "IDLE"; 2577 case kScanScanning: 2578 DCHECK(method != kScanMethodNone) << "Scanning with no scan method."; 2579 switch (method) { 2580 case kScanMethodFull: 2581 return "FULL_START"; 2582 case kScanMethodProgressive: 2583 return "PROGRESSIVE_START"; 2584 case kScanMethodProgressiveErrorToFull: 2585 return "PROGRESSIVE_ERROR_FULL_START"; 2586 case kScanMethodProgressiveFinishedToFull: 2587 return "PROGRESSIVE_FINISHED_FULL_START"; 2588 default: 2589 NOTREACHED(); 2590 } 2591 case kScanBackgroundScanning: 2592 return "BACKGROUND_START"; 2593 case kScanTransitionToConnecting: 2594 return "TRANSITION_TO_CONNECTING"; 2595 case kScanConnecting: 2596 switch (method) { 2597 case kScanMethodNone: 2598 return "CONNECTING (not scan related)"; 2599 case kScanMethodFull: 2600 return "FULL_CONNECTING"; 2601 case kScanMethodProgressive: 2602 return "PROGRESSIVE_CONNECTING"; 2603 case kScanMethodProgressiveErrorToFull: 2604 return "PROGRESSIVE_ERROR_FULL_CONNECTING"; 2605 case kScanMethodProgressiveFinishedToFull: 2606 return "PROGRESSIVE_FINISHED_FULL_CONNECTING"; 2607 default: 2608 NOTREACHED(); 2609 } 2610 case kScanConnected: 2611 switch (method) { 2612 case kScanMethodNone: 2613 return "CONNECTED (not scan related; e.g., from a supplicant roam)"; 2614 case kScanMethodFull: 2615 return "FULL_CONNECTED"; 2616 case kScanMethodProgressive: 2617 return "PROGRESSIVE_CONNECTED"; 2618 case kScanMethodProgressiveErrorToFull: 2619 return "PROGRESSIVE_ERROR_FULL_CONNECTED"; 2620 case kScanMethodProgressiveFinishedToFull: 2621 return "PROGRESSIVE_FINISHED_FULL_CONNECTED"; 2622 default: 2623 NOTREACHED(); 2624 } 2625 case kScanFoundNothing: 2626 switch (method) { 2627 case kScanMethodNone: 2628 return "CONNECT FAILED (not scan related)"; 2629 case kScanMethodFull: 2630 return "FULL_NOCONNECTION"; 2631 case kScanMethodProgressive: 2632 // This is possible if shill started to connect but timed out before 2633 // the connection was completed. 2634 return "PROGRESSIVE_FINISHED_NOCONNECTION"; 2635 case kScanMethodProgressiveErrorToFull: 2636 return "PROGRESSIVE_ERROR_FULL_NOCONNECTION"; 2637 case kScanMethodProgressiveFinishedToFull: 2638 return "PROGRESSIVE_FINISHED_FULL_NOCONNECTION"; 2639 default: 2640 NOTREACHED(); 2641 } 2642 default: 2643 NOTREACHED(); 2644 } 2645 return ""; // To shut up the compiler (that doesn't understand NOTREACHED). 2646 } 2647 2648 void WiFi::ReportScanResultToUma(ScanState state, ScanMethod method) { 2649 Metrics::WiFiScanResult result = Metrics::kScanResultMax; 2650 if (state == kScanConnected) { 2651 switch (method) { 2652 case kScanMethodFull: 2653 result = Metrics::kScanResultFullScanConnected; 2654 break; 2655 case kScanMethodProgressive: 2656 result = Metrics::kScanResultProgressiveConnected; 2657 break; 2658 case kScanMethodProgressiveErrorToFull: 2659 result = Metrics::kScanResultProgressiveErrorButFullConnected; 2660 break; 2661 case kScanMethodProgressiveFinishedToFull: 2662 result = Metrics::kScanResultProgressiveAndFullConnected; 2663 break; 2664 default: 2665 // OK: Connect resulting from something other than scan. 2666 break; 2667 } 2668 } else if (state == kScanFoundNothing) { 2669 switch (method) { 2670 case kScanMethodFull: 2671 result = Metrics::kScanResultFullScanFoundNothing; 2672 break; 2673 case kScanMethodProgressiveErrorToFull: 2674 result = Metrics::kScanResultProgressiveErrorAndFullFoundNothing; 2675 break; 2676 case kScanMethodProgressiveFinishedToFull: 2677 result = Metrics::kScanResultProgressiveAndFullFoundNothing; 2678 break; 2679 default: 2680 // OK: Connect failed, not scan related. 2681 break; 2682 } 2683 } 2684 2685 if (result != Metrics::kScanResultMax) { 2686 metrics()->SendEnumToUMA(Metrics::kMetricScanResult, 2687 result, 2688 Metrics::kScanResultMax); 2689 } 2690 } 2691 2692 void WiFi::RequestStationInfo() { 2693 if (!IsConnectedToCurrentService()) { 2694 LOG(ERROR) << "Not collecting station info because we are not connected."; 2695 return; 2696 } 2697 2698 EndpointMap::iterator endpoint_it = endpoint_by_rpcid_.find(supplicant_bss_); 2699 if (endpoint_it == endpoint_by_rpcid_.end()) { 2700 LOG(ERROR) << "Can't get endpoint for current supplicant BSS " 2701 << supplicant_bss_; 2702 return; 2703 } 2704 2705 GetStationMessage get_station; 2706 if (!get_station.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX, 2707 interface_index())) { 2708 LOG(ERROR) << "Could not add IFINDEX attribute for GetStation message."; 2709 return; 2710 } 2711 2712 const WiFiEndpointConstRefPtr endpoint(endpoint_it->second); 2713 if (!get_station.attributes()->SetRawAttributeValue( 2714 NL80211_ATTR_MAC, 2715 ByteString::CreateFromHexString(endpoint->bssid_hex()))) { 2716 LOG(ERROR) << "Could not add MAC attribute for GetStation message."; 2717 return; 2718 } 2719 2720 netlink_manager_->SendNl80211Message( 2721 &get_station, 2722 Bind(&WiFi::OnReceivedStationInfo, weak_ptr_factory_.GetWeakPtr()), 2723 Bind(&NetlinkManager::OnAckDoNothing), 2724 Bind(&NetlinkManager::OnNetlinkMessageError)); 2725 2726 request_station_info_callback_.Reset( 2727 Bind(&WiFi::RequestStationInfo, weak_ptr_factory_.GetWeakPtr())); 2728 dispatcher()->PostDelayedTask(request_station_info_callback_.callback(), 2729 kRequestStationInfoPeriodSeconds * 1000); 2730 } 2731 2732 void WiFi::OnReceivedStationInfo(const Nl80211Message& nl80211_message) { 2733 // Verify NL80211_CMD_NEW_STATION 2734 if (nl80211_message.command() != NewStationMessage::kCommand) { 2735 LOG(ERROR) << "Received unexpected command:" 2736 << nl80211_message.command(); 2737 return; 2738 } 2739 2740 if (!IsConnectedToCurrentService()) { 2741 LOG(ERROR) << "Not accepting station info because we are not connected."; 2742 return; 2743 } 2744 2745 EndpointMap::iterator endpoint_it = endpoint_by_rpcid_.find(supplicant_bss_); 2746 if (endpoint_it == endpoint_by_rpcid_.end()) { 2747 LOG(ERROR) << "Can't get endpoint for current supplicant BSS." 2748 << supplicant_bss_; 2749 return; 2750 } 2751 2752 ByteString station_bssid; 2753 if (!nl80211_message.const_attributes()->GetRawAttributeValue( 2754 NL80211_ATTR_MAC, &station_bssid)) { 2755 LOG(ERROR) << "Unable to get MAC attribute from received station info."; 2756 return; 2757 } 2758 2759 WiFiEndpointRefPtr endpoint(endpoint_it->second); 2760 2761 if (!station_bssid.Equals( 2762 ByteString::CreateFromHexString(endpoint->bssid_hex()))) { 2763 LOG(ERROR) << "Received station info for a non-current BSS."; 2764 return; 2765 } 2766 2767 AttributeListConstRefPtr station_info; 2768 if (!nl80211_message.const_attributes()->ConstGetNestedAttributeList( 2769 NL80211_ATTR_STA_INFO, &station_info)) { 2770 LOG(ERROR) << "Received station info had no NL80211_ATTR_STA_INFO."; 2771 return; 2772 } 2773 2774 uint8_t signal; 2775 if (!station_info->GetU8AttributeValue(NL80211_STA_INFO_SIGNAL, &signal)) { 2776 LOG(ERROR) << "Received station info had no NL80211_STA_INFO_SIGNAL."; 2777 return; 2778 } 2779 2780 endpoint->UpdateSignalStrength(static_cast<signed char>(signal)); 2781 2782 link_statistics_.Clear(); 2783 2784 map<int, string> u32_property_map = { 2785 { NL80211_STA_INFO_INACTIVE_TIME, kInactiveTimeMillisecondsProperty }, 2786 { NL80211_STA_INFO_RX_PACKETS, kPacketReceiveSuccessesProperty }, 2787 { NL80211_STA_INFO_TX_FAILED, kPacketTransmitFailuresProperty }, 2788 { NL80211_STA_INFO_TX_PACKETS, kPacketTransmitSuccessesProperty }, 2789 { NL80211_STA_INFO_TX_RETRIES, kTransmitRetriesProperty } 2790 }; 2791 2792 for (const auto& kv : u32_property_map) { 2793 uint32_t value; 2794 if (station_info->GetU32AttributeValue(kv.first, &value)) { 2795 link_statistics_.SetUint(kv.second, value); 2796 } 2797 } 2798 2799 map<int, string> s8_property_map = { 2800 { NL80211_STA_INFO_SIGNAL, kLastReceiveSignalDbmProperty }, 2801 { NL80211_STA_INFO_SIGNAL_AVG, kAverageReceiveSignalDbmProperty } 2802 }; 2803 2804 for (const auto& kv : s8_property_map) { 2805 uint8_t value; 2806 if (station_info->GetU8AttributeValue(kv.first, &value)) { 2807 // Despite these values being reported as a U8 by the kernel, these 2808 // should be interpreted as signed char. 2809 link_statistics_.SetInt(kv.second, static_cast<signed char>(value)); 2810 } 2811 } 2812 2813 AttributeListConstRefPtr transmit_info; 2814 if (station_info->ConstGetNestedAttributeList( 2815 NL80211_STA_INFO_TX_BITRATE, &transmit_info)) { 2816 uint32_t rate = 0; // In 100Kbps. 2817 uint16_t u16_rate = 0; // In 100Kbps. 2818 uint8_t mcs = 0; 2819 uint8_t nss = 0; 2820 bool band_flag = false; 2821 bool is_short_gi = false; 2822 string mcs_info; 2823 string nss_info; 2824 string band_info; 2825 2826 if (transmit_info->GetU16AttributeValue( 2827 NL80211_RATE_INFO_BITRATE, &u16_rate)) { 2828 rate = static_cast<uint32_t>(u16_rate); 2829 } else { 2830 transmit_info->GetU32AttributeValue(NL80211_RATE_INFO_BITRATE32, &rate); 2831 } 2832 2833 if (transmit_info->GetU8AttributeValue(NL80211_RATE_INFO_MCS, &mcs)) { 2834 mcs_info = StringPrintf(" MCS %d", mcs); 2835 } else if (transmit_info->GetU8AttributeValue( 2836 NL80211_RATE_INFO_VHT_MCS, &mcs)) { 2837 mcs_info = StringPrintf(" VHT-MCS %d", mcs); 2838 } 2839 2840 if (transmit_info->GetU8AttributeValue(NL80211_RATE_INFO_VHT_NSS, &nss)) { 2841 nss_info = StringPrintf(" VHT-NSS %d", nss); 2842 } 2843 2844 if (transmit_info->GetFlagAttributeValue(NL80211_RATE_INFO_40_MHZ_WIDTH, 2845 &band_flag) && band_flag) { 2846 band_info = StringPrintf(" 40MHz"); 2847 } else if (transmit_info->GetFlagAttributeValue( 2848 NL80211_RATE_INFO_80_MHZ_WIDTH, &band_flag) && band_flag) { 2849 band_info = StringPrintf(" 80MHz"); 2850 } else if (transmit_info->GetFlagAttributeValue( 2851 NL80211_RATE_INFO_80P80_MHZ_WIDTH, &band_flag) && band_flag) { 2852 band_info = StringPrintf(" 80+80MHz"); 2853 } else if (transmit_info->GetFlagAttributeValue( 2854 NL80211_RATE_INFO_160_MHZ_WIDTH, &band_flag) && band_flag) { 2855 band_info = StringPrintf(" 160MHz"); 2856 } 2857 2858 transmit_info->GetFlagAttributeValue(NL80211_RATE_INFO_SHORT_GI, 2859 &is_short_gi); 2860 if (rate) { 2861 link_statistics_.SetString(kTransmitBitrateProperty, 2862 StringPrintf("%d.%d MBit/s%s%s%s%s", 2863 rate / 10, rate % 10, 2864 mcs_info.c_str(), 2865 band_info.c_str(), 2866 is_short_gi ? " short GI" : "", 2867 nss_info.c_str())); 2868 metrics()->NotifyWifiTxBitrate(rate/10); 2869 } 2870 } 2871 } 2872 2873 void WiFi::StopRequestingStationInfo() { 2874 SLOG(this, 2) << "WiFi Device " << link_name() << ": " << __func__; 2875 request_station_info_callback_.Cancel(); 2876 link_statistics_.Clear(); 2877 } 2878 2879 void WiFi::TDLSDiscoverResponse(const string& peer_address) { 2880 LOG(INFO) << __func__ << " TDLS discover response from " << peer_address; 2881 2882 if (!tdls_manager_) { 2883 LOG(ERROR) << "TDLS manager not setup - not connected to supplicant"; 2884 return; 2885 } 2886 tdls_manager_->OnDiscoverResponseReceived(peer_address); 2887 } 2888 2889 string WiFi::PerformTDLSOperation(const string& operation, 2890 const string& peer, 2891 Error* error) { 2892 SLOG(this, 2) << "TDLS command received: " << operation 2893 << " for peer " << peer; 2894 if (!tdls_manager_) { 2895 LOG(ERROR) << "TDLS manager not setup - not connected to supplicant"; 2896 return ""; 2897 } 2898 2899 string peer_mac_address; 2900 if (!ResolvePeerMacAddress(peer, &peer_mac_address, error)) { 2901 return ""; 2902 } 2903 2904 return tdls_manager_->PerformOperation(peer_mac_address, operation, error); 2905 } 2906 2907 // Traffic monitor is enabled for wifi. 2908 bool WiFi::IsTrafficMonitorEnabled() const { 2909 return true; 2910 } 2911 2912 void WiFi::RemoveSupplicantNetworks() { 2913 for (const auto& map_entry : rpcid_by_service_) { 2914 RemoveNetwork(map_entry.second); 2915 } 2916 rpcid_by_service_.clear(); 2917 } 2918 2919 void WiFi::OnIPConfigUpdated(const IPConfigRefPtr& ipconfig, 2920 bool new_lease_acquired) { 2921 Device::OnIPConfigUpdated(ipconfig, new_lease_acquired); 2922 if (new_lease_acquired) { 2923 SLOG(this, 3) << __func__ << ": " 2924 << "IPv4 DHCP lease obtained"; 2925 uint32_t time_to_next_lease_renewal; 2926 bool have_dhcp_lease = 2927 TimeToNextDHCPLeaseRenewal(&time_to_next_lease_renewal); 2928 wake_on_wifi_->OnConnectedAndReachable(have_dhcp_lease, 2929 time_to_next_lease_renewal); 2930 } else { 2931 SLOG(this, 3) << __func__ << ": " 2932 << "Gateway ARP received"; 2933 // Do nothing since we are waiting until the DHCP lease is actually 2934 // obtained. 2935 return; 2936 } 2937 } 2938 2939 void WiFi::OnIPv6ConfigUpdated() { 2940 Device::OnIPv6ConfigUpdated(); 2941 if (!IsConnectedToCurrentService()) { 2942 return; 2943 } 2944 SLOG(this, 3) << __func__ << ": " 2945 << "IPv6 configuration obtained"; 2946 uint32_t time_to_next_lease_renewal; 2947 bool have_dhcp_lease = 2948 TimeToNextDHCPLeaseRenewal(&time_to_next_lease_renewal); 2949 wake_on_wifi_->OnConnectedAndReachable(have_dhcp_lease, 2950 time_to_next_lease_renewal); 2951 } 2952 2953 bool WiFi::IsConnectedToCurrentService() { 2954 return (current_service_ && current_service_->IsConnected()); 2955 } 2956 2957 void WiFi::ReportConnectedToServiceAfterWake() { 2958 wake_on_wifi_->ReportConnectedToServiceAfterWake( 2959 IsConnectedToCurrentService()); 2960 } 2961 2962 bool WiFi::RequestRoam(const std::string& addr, Error* error) { 2963 if (!supplicant_interface_proxy_->Roam(addr)) { 2964 LOG(WARNING) << "Request roam to " << addr << " failed."; 2965 return false; 2966 } 2967 return true; 2968 } 2969 2970 } // namespace shill 2971