wake_on_wifi.cc revision ff59a1896ea250b4450b54db697692e0b1949528
1// Copyright 2014 The Chromium OS Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "shill/wifi/wake_on_wifi.h" 6 7#include <errno.h> 8#include <linux/nl80211.h> 9#include <stdio.h> 10 11#include <algorithm> 12#include <set> 13#include <string> 14#include <utility> 15#include <vector> 16 17#include <base/cancelable_callback.h> 18#include <chromeos/dbus/service_constants.h> 19#include <components/timers/alarm_timer.h> 20 21#include "shill/error.h" 22#include "shill/event_dispatcher.h" 23#include "shill/ip_address_store.h" 24#include "shill/logging.h" 25#include "shill/metrics.h" 26#include "shill/net/event_history.h" 27#include "shill/net/netlink_manager.h" 28#include "shill/net/nl80211_message.h" 29#include "shill/property_accessor.h" 30#include "shill/wifi/wifi.h" 31 32using base::Bind; 33using base::Closure; 34using std::pair; 35using std::set; 36using std::string; 37using std::vector; 38using timers::AlarmTimer; 39 40namespace shill { 41 42namespace Logging { 43static auto kModuleLogScope = ScopeLogger::kWiFi; 44static std::string ObjectID(WakeOnWiFi *w) { return "(wake_on_wifi)"; } 45} 46 47const char WakeOnWiFi::kWakeOnIPAddressPatternsNotSupported[] = 48 "Wake on IP address patterns not supported by this WiFi device"; 49const char WakeOnWiFi::kWakeOnPacketDisabled[] = 50 "Wake on Packet feature disabled, so do nothing"; 51const char WakeOnWiFi::kWakeOnWiFiDisabled[] = "Wake on WiFi is disabled"; 52const uint32_t WakeOnWiFi::kDefaultWiphyIndex = 999; 53const int WakeOnWiFi::kVerifyWakeOnWiFiSettingsDelayMilliseconds = 300; 54const int WakeOnWiFi::kMaxSetWakeOnPacketRetries = 2; 55const int WakeOnWiFi::kMetricsReportingFrequencySeconds = 600; 56const uint32_t WakeOnWiFi::kDefaultWakeToScanPeriodSeconds = 900; 57const uint32_t WakeOnWiFi::kDefaultNetDetectScanPeriodSeconds = 120; 58const uint32_t WakeOnWiFi::kImmediateDHCPLeaseRenewalThresholdSeconds = 60; 59// We tolerate no more than 5 dark resumes where we wake up disconnected per 60// minute before throttling the feature (i.e. disabling wake on WiFi on the 61// NIC). 62const int WakeOnWiFi::kDarkResumeFrequencySamplingPeriodMinutes = 1; 63const int WakeOnWiFi::kMaxDarkResumesPerPeriod = 5; 64// If a connection is not established during dark resume, give up and prepare 65// the system to wake on SSID 1 second before suspending again. 66// TODO(samueltan): link this to 67// Manager::kTerminationActionsTimeoutMilliseconds rather than hard-coding 68// this value. 69int64_t WakeOnWiFi::DarkResumeActionsTimeoutMilliseconds = 18500; 70 71WakeOnWiFi::WakeOnWiFi(NetlinkManager *netlink_manager, 72 EventDispatcher *dispatcher, Metrics *metrics) 73 : dispatcher_(dispatcher), 74 netlink_manager_(netlink_manager), 75 metrics_(metrics), 76 report_metrics_callback_( 77 Bind(&WakeOnWiFi::ReportMetrics, base::Unretained(this))), 78 num_set_wake_on_packet_retries_(0), 79 wake_on_wifi_max_patterns_(0), 80 wiphy_index_(kDefaultWiphyIndex), 81 wiphy_index_received_(false), 82#if defined(DISABLE_WAKE_ON_WIFI) 83 wake_on_wifi_features_enabled_(kWakeOnWiFiFeaturesEnabledNotSupported), 84#else 85 // Wake on WiFi features temporarily disabled at run-time for boards that 86 // support wake on WiFi. 87 // TODO(samueltan): re-enable once pending issues have been resolved. 88 wake_on_wifi_features_enabled_(kWakeOnWiFiFeaturesEnabledNone), 89#endif // DISABLE_WAKE_ON_WIFI 90 dhcp_lease_renewal_timer_(true, false), 91 wake_to_scan_timer_(true, false), 92 in_dark_resume_(false), 93 wake_to_scan_period_seconds_(kDefaultWakeToScanPeriodSeconds), 94 net_detect_scan_period_seconds_(kDefaultNetDetectScanPeriodSeconds), 95 dark_resumes_since_last_suspend_(kMaxDarkResumesPerPeriod), 96 weak_ptr_factory_(this) { 97} 98 99WakeOnWiFi::~WakeOnWiFi() {} 100 101void WakeOnWiFi::InitPropertyStore(PropertyStore *store) { 102 store->RegisterDerivedString( 103 kWakeOnWiFiFeaturesEnabledProperty, 104 StringAccessor(new CustomAccessor<WakeOnWiFi, string>( 105 this, &WakeOnWiFi::GetWakeOnWiFiFeaturesEnabled, 106 &WakeOnWiFi::SetWakeOnWiFiFeaturesEnabled))); 107 store->RegisterUint32(kWakeToScanPeriodSecondsProperty, 108 &wake_to_scan_period_seconds_); 109 store->RegisterUint32(kNetDetectScanPeriodSecondsProperty, 110 &net_detect_scan_period_seconds_); 111} 112 113void WakeOnWiFi::StartMetricsTimer() { 114#if !defined(DISABLE_WAKE_ON_WIFI) 115 dispatcher_->PostDelayedTask(report_metrics_callback_.callback(), 116 kMetricsReportingFrequencySeconds * 1000); 117#endif // DISABLE_WAKE_ON_WIFI 118} 119 120string WakeOnWiFi::GetWakeOnWiFiFeaturesEnabled(Error *error) { 121 return wake_on_wifi_features_enabled_; 122} 123 124bool WakeOnWiFi::SetWakeOnWiFiFeaturesEnabled(const std::string &enabled, 125 Error *error) { 126#if defined(DISABLE_WAKE_ON_WIFI) 127 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported, 128 "Wake on WiFi is not supported"); 129 return false; 130#else 131 if (wake_on_wifi_features_enabled_ == enabled) { 132 return false; 133 } 134 if (enabled != kWakeOnWiFiFeaturesEnabledPacket && 135 enabled != kWakeOnWiFiFeaturesEnabledSSID && 136 enabled != kWakeOnWiFiFeaturesEnabledPacketSSID && 137 enabled != kWakeOnWiFiFeaturesEnabledNone) { 138 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 139 "Invalid Wake on WiFi feature"); 140 return false; 141 } 142 wake_on_wifi_features_enabled_ = enabled; 143 return true; 144#endif // DISABLE_WAKE_ON_WIFI 145} 146 147void WakeOnWiFi::RunAndResetSuspendActionsDoneCallback(const Error &error) { 148 if (!suspend_actions_done_callback_.is_null()) { 149 suspend_actions_done_callback_.Run(error); 150 suspend_actions_done_callback_.Reset(); 151 } 152} 153 154bool WakeOnWiFi::ByteStringPairIsLessThan( 155 const std::pair<ByteString, ByteString> &lhs, 156 const std::pair<ByteString, ByteString> &rhs) { 157 // Treat the first value of the pair as the key. 158 return ByteString::IsLessThan(lhs.first, rhs.first); 159} 160 161// static 162void WakeOnWiFi::SetMask(ByteString *mask, uint32_t pattern_len, 163 uint32_t offset) { 164 // Round up number of bytes required for the mask. 165 int result_mask_len = (pattern_len + 8 - 1) / 8; 166 vector<unsigned char> result_mask(result_mask_len, 0); 167 // Set mask bits from offset to (pattern_len - 1) 168 int mask_index; 169 for (uint32_t curr_mask_bit = offset; curr_mask_bit < pattern_len; 170 ++curr_mask_bit) { 171 mask_index = curr_mask_bit / 8; 172 result_mask[mask_index] |= 1 << (curr_mask_bit % 8); 173 } 174 mask->Clear(); 175 mask->Append(ByteString(result_mask)); 176} 177 178// static 179bool WakeOnWiFi::CreateIPAddressPatternAndMask(const IPAddress &ip_addr, 180 ByteString *pattern, 181 ByteString *mask) { 182 if (ip_addr.family() == IPAddress::kFamilyIPv4) { 183 WakeOnWiFi::CreateIPV4PatternAndMask(ip_addr, pattern, mask); 184 return true; 185 } else if (ip_addr.family() == IPAddress::kFamilyIPv6) { 186 WakeOnWiFi::CreateIPV6PatternAndMask(ip_addr, pattern, mask); 187 return true; 188 } else { 189 LOG(ERROR) << "Unrecognized IP Address type."; 190 return false; 191 } 192} 193 194// static 195void WakeOnWiFi::CreateIPV4PatternAndMask(const IPAddress &ip_addr, 196 ByteString *pattern, 197 ByteString *mask) { 198 struct { 199 struct ethhdr eth_hdr; 200 struct iphdr ipv4_hdr; 201 } __attribute__((__packed__)) pattern_bytes; 202 memset(&pattern_bytes, 0, sizeof(pattern_bytes)); 203 CHECK_EQ(sizeof(pattern_bytes.ipv4_hdr.saddr), ip_addr.GetLength()); 204 memcpy(&pattern_bytes.ipv4_hdr.saddr, ip_addr.GetConstData(), 205 ip_addr.GetLength()); 206 int src_ip_offset = 207 reinterpret_cast<unsigned char *>(&pattern_bytes.ipv4_hdr.saddr) - 208 reinterpret_cast<unsigned char *>(&pattern_bytes); 209 int pattern_len = src_ip_offset + ip_addr.GetLength(); 210 pattern->Clear(); 211 pattern->Append(ByteString( 212 reinterpret_cast<const unsigned char *>(&pattern_bytes), pattern_len)); 213 WakeOnWiFi::SetMask(mask, pattern_len, src_ip_offset); 214} 215 216// static 217void WakeOnWiFi::CreateIPV6PatternAndMask(const IPAddress &ip_addr, 218 ByteString *pattern, 219 ByteString *mask) { 220 struct { 221 struct ethhdr eth_hdr; 222 struct ip6_hdr ipv6_hdr; 223 } __attribute__((__packed__)) pattern_bytes; 224 memset(&pattern_bytes, 0, sizeof(pattern_bytes)); 225 CHECK_EQ(sizeof(pattern_bytes.ipv6_hdr.ip6_src), ip_addr.GetLength()); 226 memcpy(&pattern_bytes.ipv6_hdr.ip6_src, ip_addr.GetConstData(), 227 ip_addr.GetLength()); 228 int src_ip_offset = 229 reinterpret_cast<unsigned char *>(&pattern_bytes.ipv6_hdr.ip6_src) - 230 reinterpret_cast<unsigned char *>(&pattern_bytes); 231 int pattern_len = src_ip_offset + ip_addr.GetLength(); 232 pattern->Clear(); 233 pattern->Append(ByteString( 234 reinterpret_cast<const unsigned char *>(&pattern_bytes), pattern_len)); 235 WakeOnWiFi::SetMask(mask, pattern_len, src_ip_offset); 236} 237 238// static 239bool WakeOnWiFi::ConfigureWiphyIndex(Nl80211Message *msg, int32_t index) { 240 if (!msg->attributes()->CreateU32Attribute(NL80211_ATTR_WIPHY, 241 "WIPHY index")) { 242 return false; 243 } 244 if (!msg->attributes()->SetU32AttributeValue(NL80211_ATTR_WIPHY, index)) { 245 return false; 246 } 247 return true; 248} 249 250// static 251bool WakeOnWiFi::ConfigureDisableWakeOnWiFiMessage( 252 SetWakeOnPacketConnMessage *msg, uint32_t wiphy_index, Error *error) { 253 if (!ConfigureWiphyIndex(msg, wiphy_index)) { 254 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 255 "Failed to configure Wiphy index."); 256 return false; 257 } 258 return true; 259} 260 261// static 262bool WakeOnWiFi::ConfigureSetWakeOnWiFiSettingsMessage( 263 SetWakeOnPacketConnMessage *msg, const set<WakeOnWiFiTrigger> &trigs, 264 const IPAddressStore &addrs, uint32_t wiphy_index, Error *error) { 265 if (trigs.empty()) { 266 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 267 "No triggers to configure."); 268 return false; 269 } 270 if (trigs.find(kPattern) != trigs.end() && addrs.Empty()) { 271 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 272 "No IP addresses to configure."); 273 return false; 274 } 275 if (!ConfigureWiphyIndex(msg, wiphy_index)) { 276 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 277 "Failed to configure Wiphy index."); 278 return false; 279 } 280 if (!msg->attributes()->CreateNestedAttribute(NL80211_ATTR_WOWLAN_TRIGGERS, 281 "WoWLAN Triggers")) { 282 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 283 "Could not create nested attribute " 284 "NL80211_ATTR_WOWLAN_TRIGGERS for " 285 "SetWakeOnPacketConnMessage."); 286 return false; 287 } 288 if (!msg->attributes()->SetNestedAttributeHasAValue( 289 NL80211_ATTR_WOWLAN_TRIGGERS)) { 290 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 291 "Could not set nested attribute " 292 "NL80211_ATTR_WOWLAN_TRIGGERS for " 293 "SetWakeOnPacketConnMessage."); 294 return false; 295 } 296 297 AttributeListRefPtr triggers; 298 if (!msg->attributes()->GetNestedAttributeList(NL80211_ATTR_WOWLAN_TRIGGERS, 299 &triggers)) { 300 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 301 "Could not get nested attribute list " 302 "NL80211_ATTR_WOWLAN_TRIGGERS for " 303 "SetWakeOnPacketConnMessage."); 304 return false; 305 } 306 // Add triggers. 307 for (WakeOnWiFiTrigger t : trigs) { 308 switch (t) { 309 case kDisconnect: { 310 if (!triggers->CreateFlagAttribute(NL80211_WOWLAN_TRIG_DISCONNECT, 311 "Wake on Disconnect")) { 312 LOG(ERROR) << __func__ << "Could not create flag attribute " 313 "NL80211_WOWLAN_TRIG_DISCONNECT"; 314 return false; 315 } 316 if (!triggers->SetFlagAttributeValue(NL80211_WOWLAN_TRIG_DISCONNECT, 317 true)) { 318 LOG(ERROR) << __func__ << "Could not set flag attribute " 319 "NL80211_WOWLAN_TRIG_DISCONNECT"; 320 return false; 321 } 322 break; 323 } 324 case kPattern: { 325 if (!triggers->CreateNestedAttribute(NL80211_WOWLAN_TRIG_PKT_PATTERN, 326 "Pattern trigger")) { 327 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 328 "Could not create nested attribute " 329 "NL80211_WOWLAN_TRIG_PKT_PATTERN for " 330 "SetWakeOnPacketConnMessage."); 331 return false; 332 } 333 if (!triggers->SetNestedAttributeHasAValue( 334 NL80211_WOWLAN_TRIG_PKT_PATTERN)) { 335 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 336 "Could not set nested attribute " 337 "NL80211_WOWLAN_TRIG_PKT_PATTERN for " 338 "SetWakeOnPacketConnMessage."); 339 return false; 340 } 341 AttributeListRefPtr patterns; 342 if (!triggers->GetNestedAttributeList(NL80211_WOWLAN_TRIG_PKT_PATTERN, 343 &patterns)) { 344 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 345 "Could not get nested attribute list " 346 "NL80211_WOWLAN_TRIG_PKT_PATTERN for " 347 "SetWakeOnPacketConnMessage."); 348 return false; 349 } 350 uint8_t patnum = 1; 351 for (const IPAddress &addr : addrs.GetIPAddresses()) { 352 if (!CreateSinglePattern(addr, patterns, patnum++, error)) { 353 return false; 354 } 355 } 356 break; 357 } 358 case kSSID: { 359 // TODO(samueltan): construct wake on SSID trigger when available. 360 break; 361 } 362 default: { 363 LOG(ERROR) << __func__ << ": Unrecognized trigger"; 364 return false; 365 } 366 } 367 } 368 return true; 369} 370 371// static 372bool WakeOnWiFi::CreateSinglePattern(const IPAddress &ip_addr, 373 AttributeListRefPtr patterns, 374 uint8_t patnum, Error *error) { 375 ByteString pattern; 376 ByteString mask; 377 WakeOnWiFi::CreateIPAddressPatternAndMask(ip_addr, &pattern, &mask); 378 if (!patterns->CreateNestedAttribute(patnum, "Pattern info")) { 379 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 380 "Could not create nested attribute " 381 "patnum for SetWakeOnPacketConnMessage."); 382 return false; 383 } 384 if (!patterns->SetNestedAttributeHasAValue(patnum)) { 385 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 386 "Could not set nested attribute " 387 "patnum for SetWakeOnPacketConnMessage."); 388 return false; 389 } 390 391 AttributeListRefPtr pattern_info; 392 if (!patterns->GetNestedAttributeList(patnum, &pattern_info)) { 393 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 394 "Could not get nested attribute list " 395 "patnum for SetWakeOnPacketConnMessage."); 396 return false; 397 } 398 // Add mask. 399 if (!pattern_info->CreateRawAttribute(NL80211_PKTPAT_MASK, "Mask")) { 400 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 401 "Could not add attribute NL80211_PKTPAT_MASK to " 402 "pattern_info."); 403 return false; 404 } 405 if (!pattern_info->SetRawAttributeValue(NL80211_PKTPAT_MASK, mask)) { 406 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 407 "Could not set attribute NL80211_PKTPAT_MASK in " 408 "pattern_info."); 409 return false; 410 } 411 412 // Add pattern. 413 if (!pattern_info->CreateRawAttribute(NL80211_PKTPAT_PATTERN, "Pattern")) { 414 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 415 "Could not add attribute NL80211_PKTPAT_PATTERN to " 416 "pattern_info."); 417 return false; 418 } 419 if (!pattern_info->SetRawAttributeValue(NL80211_PKTPAT_PATTERN, pattern)) { 420 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 421 "Could not set attribute NL80211_PKTPAT_PATTERN in " 422 "pattern_info."); 423 return false; 424 } 425 426 // Add offset. 427 if (!pattern_info->CreateU32Attribute(NL80211_PKTPAT_OFFSET, "Offset")) { 428 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 429 "Could not add attribute NL80211_PKTPAT_OFFSET to " 430 "pattern_info."); 431 return false; 432 } 433 if (!pattern_info->SetU32AttributeValue(NL80211_PKTPAT_OFFSET, 0)) { 434 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 435 "Could not set attribute NL80211_PKTPAT_OFFSET in " 436 "pattern_info."); 437 return false; 438 } 439 return true; 440} 441 442// static 443bool WakeOnWiFi::ConfigureGetWakeOnWiFiSettingsMessage( 444 GetWakeOnPacketConnMessage *msg, uint32_t wiphy_index, Error *error) { 445 if (!ConfigureWiphyIndex(msg, wiphy_index)) { 446 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 447 "Failed to configure Wiphy index."); 448 return false; 449 } 450 return true; 451} 452 453// static 454bool WakeOnWiFi::WakeOnWiFiSettingsMatch(const Nl80211Message &msg, 455 const set<WakeOnWiFiTrigger> &trigs, 456 const IPAddressStore &addrs) { 457 if (msg.command() != NL80211_CMD_GET_WOWLAN && 458 msg.command() != NL80211_CMD_SET_WOWLAN) { 459 LOG(ERROR) << "Invalid message command"; 460 return false; 461 } 462 AttributeListConstRefPtr triggers; 463 if (!msg.const_attributes()->ConstGetNestedAttributeList( 464 NL80211_ATTR_WOWLAN_TRIGGERS, &triggers)) { 465 // No triggers in the returned message, which is valid iff we expect there 466 // to be no triggers programmed into the NIC. 467 return trigs.empty(); 468 } 469 // If the disconnect trigger is found and set, but we did not expect this 470 // trigger, we have a mismatch. 471 bool wake_on_disconnect = false; 472 triggers->GetFlagAttributeValue(NL80211_WOWLAN_TRIG_DISCONNECT, 473 &wake_on_disconnect); 474 if (trigs.find(kDisconnect) == trigs.end() && wake_on_disconnect) { 475 return false; 476 } 477 // Check each trigger. 478 for (WakeOnWiFiTrigger t : trigs) { 479 switch (t) { 480 case kDisconnect: { 481 if (!wake_on_disconnect) { 482 return false; 483 } 484 break; 485 } 486 case kPattern: { 487 // Create pattern and masks that we expect to find in |msg|. 488 set<pair<ByteString, ByteString>, 489 bool (*)(const pair<ByteString, ByteString> &, 490 const pair<ByteString, ByteString> &)> 491 expected_patt_mask_pairs(ByteStringPairIsLessThan); 492 ByteString temp_pattern; 493 ByteString temp_mask; 494 for (const IPAddress &addr : addrs.GetIPAddresses()) { 495 temp_pattern.Clear(); 496 temp_mask.Clear(); 497 CreateIPAddressPatternAndMask(addr, &temp_pattern, &temp_mask); 498 expected_patt_mask_pairs.emplace(temp_pattern, temp_mask); 499 } 500 // Check these expected pattern and masks against those actually 501 // contained in |msg|. 502 AttributeListConstRefPtr patterns; 503 if (!triggers->ConstGetNestedAttributeList( 504 NL80211_WOWLAN_TRIG_PKT_PATTERN, &patterns)) { 505 LOG(ERROR) << "Could not get nested attribute list " 506 "NL80211_WOWLAN_TRIG_PKT_PATTERN."; 507 return false; 508 } 509 bool mismatch_found = false; 510 size_t num_mismatch = expected_patt_mask_pairs.size(); 511 int pattern_index; 512 AttributeIdIterator pattern_iter(*patterns); 513 AttributeListConstRefPtr pattern_info; 514 ByteString returned_mask; 515 ByteString returned_pattern; 516 while (!pattern_iter.AtEnd()) { 517 returned_mask.Clear(); 518 returned_pattern.Clear(); 519 pattern_index = pattern_iter.GetId(); 520 if (!patterns->ConstGetNestedAttributeList(pattern_index, 521 &pattern_info)) { 522 LOG(ERROR) << "Could not get nested attribute list index " 523 << pattern_index << " in patterns."; 524 return false; 525 } 526 if (!pattern_info->GetRawAttributeValue(NL80211_PKTPAT_MASK, 527 &returned_mask)) { 528 LOG(ERROR) << "Could not get attribute NL80211_PKTPAT_MASK in " 529 "pattern_info."; 530 return false; 531 } 532 if (!pattern_info->GetRawAttributeValue(NL80211_PKTPAT_PATTERN, 533 &returned_pattern)) { 534 LOG(ERROR) << "Could not get attribute NL80211_PKTPAT_PATTERN in " 535 "pattern_info."; 536 return false; 537 } 538 if (expected_patt_mask_pairs.find(pair<ByteString, ByteString>( 539 returned_pattern, returned_mask)) == 540 expected_patt_mask_pairs.end()) { 541 mismatch_found = true; 542 break; 543 } else { 544 --num_mismatch; 545 } 546 pattern_iter.Advance(); 547 } 548 if (mismatch_found || num_mismatch) { 549 return false; 550 } 551 break; 552 } 553 case kSSID: { 554 // TODO(samueltan): parse wake on SSID trigger when available. 555 break; 556 } 557 default: { 558 LOG(ERROR) << __func__ << ": Unrecognized trigger"; 559 return false; 560 } 561 } 562 } 563 return true; 564} 565 566void WakeOnWiFi::AddWakeOnPacketConnection(const string &ip_endpoint, 567 Error *error) { 568#if !defined(DISABLE_WAKE_ON_WIFI) 569 if (wake_on_wifi_triggers_supported_.find(kPattern) == 570 wake_on_wifi_triggers_supported_.end()) { 571 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported, 572 kWakeOnIPAddressPatternsNotSupported); 573 return; 574 } 575 IPAddress ip_addr(ip_endpoint); 576 if (!ip_addr.IsValid()) { 577 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 578 "Invalid ip_address " + ip_endpoint); 579 return; 580 } 581 if (wake_on_wifi_triggers_.size() >= wake_on_wifi_max_patterns_) { 582 Error::PopulateAndLog( 583 FROM_HERE, error, Error::kOperationFailed, 584 "Max number of IP address patterns already registered"); 585 return; 586 } 587 wake_on_packet_connections_.AddUnique(ip_addr); 588#else 589 Error::PopulateAndLog( 590 FROM_HERE, error, Error::kNotSupported, kWakeOnWiFiDisabled); 591#endif // DISABLE_WAKE_ON_WIFI 592} 593 594void WakeOnWiFi::RemoveWakeOnPacketConnection(const string &ip_endpoint, 595 Error *error) { 596#if !defined(DISABLE_WAKE_ON_WIFI) 597 if (wake_on_wifi_triggers_supported_.find(kPattern) == 598 wake_on_wifi_triggers_supported_.end()) { 599 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported, 600 kWakeOnIPAddressPatternsNotSupported); 601 return; 602 } 603 IPAddress ip_addr(ip_endpoint); 604 if (!ip_addr.IsValid()) { 605 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 606 "Invalid ip_address " + ip_endpoint); 607 return; 608 } 609 if (!wake_on_packet_connections_.Contains(ip_addr)) { 610 Error::PopulateAndLog(FROM_HERE, error, Error::kNotFound, 611 "No such IP address match registered to wake device"); 612 return; 613 } 614 wake_on_packet_connections_.Remove(ip_addr); 615#else 616 Error::PopulateAndLog( 617 FROM_HERE, error, Error::kNotSupported, kWakeOnWiFiDisabled); 618#endif // DISABLE_WAKE_ON_WIFI 619} 620 621void WakeOnWiFi::RemoveAllWakeOnPacketConnections(Error *error) { 622#if !defined(DISABLE_WAKE_ON_WIFI) 623 if (wake_on_wifi_triggers_supported_.find(kPattern) == 624 wake_on_wifi_triggers_supported_.end()) { 625 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported, 626 kWakeOnIPAddressPatternsNotSupported); 627 return; 628 } 629 wake_on_packet_connections_.Clear(); 630#else 631 Error::PopulateAndLog( 632 FROM_HERE, error, Error::kNotSupported, kWakeOnWiFiDisabled); 633#endif // DISABLE_WAKE_ON_WIFI 634} 635 636void WakeOnWiFi::OnWakeOnWiFiSettingsErrorResponse( 637 NetlinkManager::AuxilliaryMessageType type, 638 const NetlinkMessage *raw_message) { 639 Error error(Error::kOperationFailed); 640 switch (type) { 641 case NetlinkManager::kErrorFromKernel: 642 if (!raw_message) { 643 error.Populate(Error::kOperationFailed, "Unknown error from kernel"); 644 break; 645 } 646 if (raw_message->message_type() == ErrorAckMessage::GetMessageType()) { 647 const ErrorAckMessage *error_ack_message = 648 dynamic_cast<const ErrorAckMessage *>(raw_message); 649 if (error_ack_message->error() == EOPNOTSUPP) { 650 error.Populate(Error::kNotSupported); 651 } 652 } 653 break; 654 655 case NetlinkManager::kUnexpectedResponseType: 656 error.Populate(Error::kNotRegistered, 657 "Message not handled by regular message handler:"); 658 break; 659 660 case NetlinkManager::kTimeoutWaitingForResponse: 661 // CMD_SET_WOWLAN messages do not receive responses, so this error type 662 // is received when NetlinkManager times out the message handler. Return 663 // immediately rather than run the done callback since this event does 664 // not signify the completion of suspend actions. 665 return; 666 break; 667 668 default: 669 error.Populate( 670 Error::kOperationFailed, 671 "Unexpected auxilliary message type: " + std::to_string(type)); 672 break; 673 } 674 RunAndResetSuspendActionsDoneCallback(error); 675} 676 677// static 678void WakeOnWiFi::OnSetWakeOnPacketConnectionResponse( 679 const Nl80211Message &nl80211_message) { 680 // NOP because kernel does not send a response to NL80211_CMD_SET_WOWLAN 681 // requests. 682} 683 684void WakeOnWiFi::RequestWakeOnPacketSettings() { 685 SLOG(this, 3) << __func__; 686 Error e; 687 GetWakeOnPacketConnMessage get_wowlan_msg; 688 if (!ConfigureGetWakeOnWiFiSettingsMessage(&get_wowlan_msg, wiphy_index_, 689 &e)) { 690 LOG(ERROR) << e.message(); 691 return; 692 } 693 netlink_manager_->SendNl80211Message( 694 &get_wowlan_msg, Bind(&WakeOnWiFi::VerifyWakeOnWiFiSettings, 695 weak_ptr_factory_.GetWeakPtr()), 696 Bind(&NetlinkManager::OnAckDoNothing), 697 Bind(&NetlinkManager::OnNetlinkMessageError)); 698} 699 700void WakeOnWiFi::VerifyWakeOnWiFiSettings( 701 const Nl80211Message &nl80211_message) { 702 SLOG(this, 3) << __func__; 703 if (WakeOnWiFiSettingsMatch(nl80211_message, wake_on_wifi_triggers_, 704 wake_on_packet_connections_)) { 705 SLOG(this, 2) << __func__ << ": " 706 << "Wake-on-packet settings successfully verified"; 707 metrics_->NotifyVerifyWakeOnWiFiSettingsResult( 708 Metrics::kVerifyWakeOnWiFiSettingsResultSuccess); 709 RunAndResetSuspendActionsDoneCallback(Error(Error::kSuccess)); 710 } else { 711 LOG(ERROR) << __func__ << " failed: discrepancy between wake-on-packet " 712 "settings on NIC and those in local data " 713 "structure detected"; 714 metrics_->NotifyVerifyWakeOnWiFiSettingsResult( 715 Metrics::kVerifyWakeOnWiFiSettingsResultFailure); 716 RetrySetWakeOnPacketConnections(); 717 } 718} 719 720void WakeOnWiFi::ApplyWakeOnWiFiSettings() { 721 SLOG(this, 3) << __func__; 722 if (!wiphy_index_received_) { 723 LOG(ERROR) << "Interface index not yet received"; 724 return; 725 } 726 if (wake_on_wifi_triggers_.empty()) { 727 LOG(INFO) << "No triggers to be programmed, so disable wake on WiFi"; 728 DisableWakeOnWiFi(); 729 return; 730 } 731 Error error; 732 SetWakeOnPacketConnMessage set_wowlan_msg; 733 if (!ConfigureSetWakeOnWiFiSettingsMessage( 734 &set_wowlan_msg, wake_on_wifi_triggers_, wake_on_packet_connections_, 735 wiphy_index_, &error)) { 736 LOG(ERROR) << error.message(); 737 RunAndResetSuspendActionsDoneCallback( 738 Error(Error::kOperationFailed, error.message())); 739 return; 740 } 741 if (!netlink_manager_->SendNl80211Message( 742 &set_wowlan_msg, 743 Bind(&WakeOnWiFi::OnSetWakeOnPacketConnectionResponse), 744 Bind(&NetlinkManager::OnAckDoNothing), 745 Bind(&WakeOnWiFi::OnWakeOnWiFiSettingsErrorResponse, 746 weak_ptr_factory_.GetWeakPtr()))) { 747 RunAndResetSuspendActionsDoneCallback( 748 Error(Error::kOperationFailed, "SendNl80211Message failed")); 749 return; 750 } 751 752 verify_wake_on_packet_settings_callback_.Reset( 753 Bind(&WakeOnWiFi::RequestWakeOnPacketSettings, 754 weak_ptr_factory_.GetWeakPtr())); 755 dispatcher_->PostDelayedTask( 756 verify_wake_on_packet_settings_callback_.callback(), 757 kVerifyWakeOnWiFiSettingsDelayMilliseconds); 758} 759 760void WakeOnWiFi::DisableWakeOnWiFi() { 761 SLOG(this, 3) << __func__; 762 Error error; 763 SetWakeOnPacketConnMessage disable_wowlan_msg; 764 if (!ConfigureDisableWakeOnWiFiMessage(&disable_wowlan_msg, wiphy_index_, 765 &error)) { 766 LOG(ERROR) << error.message(); 767 RunAndResetSuspendActionsDoneCallback( 768 Error(Error::kOperationFailed, error.message())); 769 return; 770 } 771 wake_on_wifi_triggers_.clear(); 772 if (!netlink_manager_->SendNl80211Message( 773 &disable_wowlan_msg, 774 Bind(&WakeOnWiFi::OnSetWakeOnPacketConnectionResponse), 775 Bind(&NetlinkManager::OnAckDoNothing), 776 Bind(&WakeOnWiFi::OnWakeOnWiFiSettingsErrorResponse, 777 weak_ptr_factory_.GetWeakPtr()))) { 778 RunAndResetSuspendActionsDoneCallback( 779 Error(Error::kOperationFailed, "SendNl80211Message failed")); 780 return; 781 } 782 783 verify_wake_on_packet_settings_callback_.Reset( 784 Bind(&WakeOnWiFi::RequestWakeOnPacketSettings, 785 weak_ptr_factory_.GetWeakPtr())); 786 dispatcher_->PostDelayedTask( 787 verify_wake_on_packet_settings_callback_.callback(), 788 kVerifyWakeOnWiFiSettingsDelayMilliseconds); 789} 790 791void WakeOnWiFi::RetrySetWakeOnPacketConnections() { 792 SLOG(this, 3) << __func__; 793 if (num_set_wake_on_packet_retries_ < kMaxSetWakeOnPacketRetries) { 794 ApplyWakeOnWiFiSettings(); 795 ++num_set_wake_on_packet_retries_; 796 } else { 797 SLOG(this, 3) << __func__ << ": max retry attempts reached"; 798 num_set_wake_on_packet_retries_ = 0; 799 RunAndResetSuspendActionsDoneCallback(Error(Error::kOperationFailed)); 800 } 801} 802 803bool WakeOnWiFi::WakeOnPacketEnabledAndSupported() { 804 if (wake_on_wifi_features_enabled_ == kWakeOnWiFiFeaturesEnabledNone || 805 wake_on_wifi_features_enabled_ == 806 kWakeOnWiFiFeaturesEnabledNotSupported || 807 wake_on_wifi_features_enabled_ == kWakeOnWiFiFeaturesEnabledSSID) { 808 return false; 809 } 810 if (wake_on_wifi_triggers_supported_.find(kPattern) == 811 wake_on_wifi_triggers_supported_.end()) { 812 return false; 813 } 814 return true; 815} 816 817bool WakeOnWiFi::WakeOnSSIDEnabledAndSupported() { 818 if (wake_on_wifi_features_enabled_ == kWakeOnWiFiFeaturesEnabledNone || 819 wake_on_wifi_features_enabled_ == 820 kWakeOnWiFiFeaturesEnabledNotSupported || 821 wake_on_wifi_features_enabled_ == kWakeOnWiFiFeaturesEnabledPacket) { 822 return false; 823 } 824 if (wake_on_wifi_triggers_supported_.find(kDisconnect) == 825 wake_on_wifi_triggers_supported_.end() || 826 wake_on_wifi_triggers_supported_.find(kSSID) == 827 wake_on_wifi_triggers_supported_.end()) { 828 return false; 829 } 830 return true; 831} 832 833void WakeOnWiFi::ReportMetrics() { 834 Metrics::WakeOnWiFiFeaturesEnabledState reported_state; 835 if (wake_on_wifi_features_enabled_ == kWakeOnWiFiFeaturesEnabledNone) { 836 reported_state = Metrics::kWakeOnWiFiFeaturesEnabledStateNone; 837 } else if (wake_on_wifi_features_enabled_ == 838 kWakeOnWiFiFeaturesEnabledPacket) { 839 reported_state = Metrics::kWakeOnWiFiFeaturesEnabledStatePacket; 840 } else if (wake_on_wifi_features_enabled_ == kWakeOnWiFiFeaturesEnabledSSID) { 841 reported_state = Metrics::kWakeOnWiFiFeaturesEnabledStateSSID; 842 } else if (wake_on_wifi_features_enabled_ == 843 kWakeOnWiFiFeaturesEnabledPacketSSID) { 844 reported_state = Metrics::kWakeOnWiFiFeaturesEnabledStatePacketSSID; 845 } else { 846 LOG(ERROR) << __func__ << ": " 847 << "Invalid wake on WiFi features state"; 848 return; 849 } 850 metrics_->NotifyWakeOnWiFiFeaturesEnabledState(reported_state); 851 StartMetricsTimer(); 852} 853 854void WakeOnWiFi::ParseWakeOnWiFiCapabilities( 855 const Nl80211Message &nl80211_message) { 856 // Verify NL80211_CMD_NEW_WIPHY. 857 if (nl80211_message.command() != NewWiphyMessage::kCommand) { 858 LOG(ERROR) << "Received unexpected command:" << nl80211_message.command(); 859 return; 860 } 861 AttributeListConstRefPtr triggers_supported; 862 if (nl80211_message.const_attributes()->ConstGetNestedAttributeList( 863 NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, &triggers_supported)) { 864 bool disconnect_supported = false; 865 if (triggers_supported->GetFlagAttributeValue( 866 NL80211_WOWLAN_TRIG_DISCONNECT, &disconnect_supported)) { 867 if (disconnect_supported) { 868 wake_on_wifi_triggers_supported_.insert(WakeOnWiFi::kDisconnect); 869 SLOG(this, 7) << "Waking on disconnect supported by this WiFi device"; 870 } 871 } 872 ByteString data; 873 if (triggers_supported->GetRawAttributeValue( 874 NL80211_WOWLAN_TRIG_PKT_PATTERN, &data)) { 875 struct nl80211_pattern_support *patt_support = 876 reinterpret_cast<struct nl80211_pattern_support *>(data.GetData()); 877 // Determine the IPV4 and IPV6 pattern lengths we will use by 878 // constructing dummy patterns and getting their lengths. 879 ByteString dummy_pattern; 880 ByteString dummy_mask; 881 WakeOnWiFi::CreateIPV4PatternAndMask(IPAddress("192.168.0.20"), 882 &dummy_pattern, &dummy_mask); 883 size_t ipv4_pattern_len = dummy_pattern.GetLength(); 884 WakeOnWiFi::CreateIPV6PatternAndMask( 885 IPAddress("FEDC:BA98:7654:3210:FEDC:BA98:7654:3210"), &dummy_pattern, 886 &dummy_mask); 887 size_t ipv6_pattern_len = dummy_pattern.GetLength(); 888 // Check if the pattern matching capabilities of this WiFi device will 889 // allow IPV4 and IPV6 patterns to be used. 890 if (patt_support->min_pattern_len <= 891 std::min(ipv4_pattern_len, ipv6_pattern_len) && 892 patt_support->max_pattern_len >= 893 std::max(ipv4_pattern_len, ipv6_pattern_len)) { 894 wake_on_wifi_triggers_supported_.insert(WakeOnWiFi::kPattern); 895 wake_on_wifi_max_patterns_ = patt_support->max_patterns; 896 SLOG(this, 7) << "Waking on up to " << wake_on_wifi_max_patterns_ 897 << " registered patterns of " 898 << patt_support->min_pattern_len << "-" 899 << patt_support->max_pattern_len 900 << " bytes supported by this WiFi device"; 901 } 902 } 903 // TODO(samueltan): remove this placeholder when wake on SSID capability 904 // can be parsed from NL80211 message. 905 wake_on_wifi_triggers_supported_.insert(WakeOnWiFi::kSSID); 906 } 907} 908 909void WakeOnWiFi::ParseWiphyIndex(const Nl80211Message &nl80211_message) { 910 // Verify NL80211_CMD_NEW_WIPHY. 911 if (nl80211_message.command() != NewWiphyMessage::kCommand) { 912 LOG(ERROR) << "Received unexpected command:" << nl80211_message.command(); 913 return; 914 } 915 if (!nl80211_message.const_attributes()->GetU32AttributeValue( 916 NL80211_ATTR_WIPHY, &wiphy_index_)) { 917 LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY"; 918 return; 919 } 920 wiphy_index_received_ = true; 921} 922 923void WakeOnWiFi::OnBeforeSuspend( 924 bool is_connected, 925 bool has_service_configured_for_autoconnect, 926 const ResultCallback &done_callback, 927 const Closure &renew_dhcp_lease_callback, 928 const Closure &remove_supplicant_networks_callback, 929 bool have_dhcp_lease, 930 uint32_t time_to_next_lease_renewal) { 931 LOG(INFO) << __func__ << ": " 932 << (is_connected ? "connected" : "not connected"); 933#if defined(DISABLE_WAKE_ON_WIFI) 934 // Wake on WiFi disabled, so immediately report success. 935 done_callback.Run(Error(Error::kSuccess)); 936#else 937 suspend_actions_done_callback_ = done_callback; 938 dark_resumes_since_last_suspend_.Clear(); 939 if (have_dhcp_lease && is_connected && 940 time_to_next_lease_renewal < kImmediateDHCPLeaseRenewalThresholdSeconds) { 941 // Renew DHCP lease immediately if we have one that is expiring soon. 942 renew_dhcp_lease_callback.Run(); 943 dispatcher_->PostTask( 944 Bind(&WakeOnWiFi::BeforeSuspendActions, weak_ptr_factory_.GetWeakPtr(), 945 is_connected, has_service_configured_for_autoconnect, false, 946 time_to_next_lease_renewal, remove_supplicant_networks_callback)); 947 } else { 948 dispatcher_->PostTask(Bind( 949 &WakeOnWiFi::BeforeSuspendActions, weak_ptr_factory_.GetWeakPtr(), 950 is_connected, has_service_configured_for_autoconnect, have_dhcp_lease, 951 time_to_next_lease_renewal, remove_supplicant_networks_callback)); 952 } 953#endif // DISABLE_WAKE_ON_WIFI 954} 955 956void WakeOnWiFi::OnAfterResume() { 957 LOG(INFO) << __func__; 958#if !defined(DISABLE_WAKE_ON_WIFI) 959 wake_to_scan_timer_.Stop(); 960 dhcp_lease_renewal_timer_.Stop(); 961 if (WakeOnPacketEnabledAndSupported() || WakeOnSSIDEnabledAndSupported()) { 962 // Unconditionally disable wake on WiFi on resume if these features 963 // were enabled before the last suspend. 964 DisableWakeOnWiFi(); 965 } 966#endif // DISABLE_WAKE_ON_WIFI 967} 968 969void WakeOnWiFi::OnDarkResume( 970 bool is_connected, 971 bool has_service_configured_for_autoconnect, 972 const ResultCallback &done_callback, 973 const Closure &renew_dhcp_lease_callback, 974 const Closure &initiate_scan_callback, 975 const Closure &remove_supplicant_networks_callback) { 976 LOG(INFO) << __func__ << ": " 977 << (is_connected ? "connected" : "not connected"); 978#if defined(DISABLE_WAKE_ON_WIFI) 979 done_callback.Run(Error(Error::kSuccess)); 980#else 981 suspend_actions_done_callback_ = done_callback; 982 if (!is_connected) { 983 // Only record dark resume events where we wake up disconnected, since there 984 // are valid scenarios where we would dark resume frequently in a connected 985 // state (e.g. when wake on packet is enabled when there is a brief spike in 986 // incoming network traffic). 987 dark_resumes_since_last_suspend_.RecordEventAndExpireEventsBefore( 988 kDarkResumeFrequencySamplingPeriodMinutes * 60, true); 989 } 990 if (dark_resumes_since_last_suspend_.Size() >= 991 static_cast<size_t>(kMaxDarkResumesPerPeriod)) { 992 LOG(ERROR) << __func__ << ": " 993 << "Too many dark resumes; disabling wake on WiFi"; 994 // If too many dark resumes have triggered recently, we are probably 995 // thrashing. Stop this by disabling wake on WiFi on the NIC and 996 // stopping all RTC timers that might trigger another dark resume. 997 dhcp_lease_renewal_timer_.Stop(); 998 wake_to_scan_timer_.Stop(); 999 DisableWakeOnWiFi(); 1000 dark_resumes_since_last_suspend_.Clear(); 1001 return; 1002 } 1003 // Only set dark resume to true after checking if we need to disable wake on 1004 // WiFi since calling WakeOnWiFi::DisableWakeOnWiFi directly bypasses 1005 // WakeOnWiFi::BeforeSuspendActions where |in_dark_resume_| is set to false. 1006 in_dark_resume_ = true; 1007 // Assume that we are disconnected if we time out. Consequently, we do not 1008 // need to start a DHCP lease renewal timer. 1009 dark_resume_actions_timeout_callback_.Reset( 1010 Bind(&WakeOnWiFi::BeforeSuspendActions, weak_ptr_factory_.GetWeakPtr(), 1011 false, has_service_configured_for_autoconnect, false, 0, 1012 remove_supplicant_networks_callback)); 1013 dispatcher_->PostDelayedTask(dark_resume_actions_timeout_callback_.callback(), 1014 DarkResumeActionsTimeoutMilliseconds); 1015 1016 if (is_connected) { 1017 renew_dhcp_lease_callback.Run(); 1018 } else { 1019 remove_supplicant_networks_callback.Run(); 1020 metrics_->NotifyDarkResumeInitiateScan(); 1021 initiate_scan_callback.Run(); 1022 } 1023#endif // DISABLE_WAKE_ON_WIFI 1024} 1025 1026void WakeOnWiFi::BeforeSuspendActions( 1027 bool is_connected, 1028 bool has_service_configured_for_autoconnect, 1029 bool start_lease_renewal_timer, 1030 uint32_t time_to_next_lease_renewal, 1031 const Closure &remove_supplicant_networks_callback) { 1032 SLOG(this, 3) << __func__ << ": " 1033 << (is_connected ? "connected" : "not connected"); 1034 // Note: No conditional compilation because all entry points to this functions 1035 // are already conditionally compiled based on DISABLE_WAKE_ON_WIFI. 1036 1037 // Create copy so callback can be run despite calling Cancel(). 1038 Closure supplicant_callback_copy(remove_supplicant_networks_callback); 1039 dark_resume_actions_timeout_callback_.Cancel(); 1040 1041 // Add relevant triggers to be programmed into the NIC. 1042 wake_on_wifi_triggers_.clear(); 1043 if (!wake_on_packet_connections_.Empty() && 1044 WakeOnPacketEnabledAndSupported() && is_connected) { 1045 SLOG(this, 3) << "Enabling wake on pattern"; 1046 wake_on_wifi_triggers_.insert(kPattern); 1047 } 1048 if (WakeOnSSIDEnabledAndSupported()) { 1049 if (is_connected) { 1050 SLOG(this, 3) << "Enabling wake on disconnect"; 1051 wake_on_wifi_triggers_.insert(kDisconnect); 1052 wake_on_wifi_triggers_.erase(kSSID); 1053 wake_to_scan_timer_.Stop(); 1054 if (start_lease_renewal_timer) { 1055 // Timer callback is NO-OP since dark resume logic will initiate DHCP 1056 // lease renewal. 1057 dhcp_lease_renewal_timer_.Start( 1058 FROM_HERE, base::TimeDelta::FromSeconds(time_to_next_lease_renewal), 1059 Bind(&WakeOnWiFi::OnTimerWakeDoNothing, base::Unretained(this))); 1060 } 1061 } else { 1062 SLOG(this, 3) << "Enabling wake on SSID"; 1063 // Force a disconnect in case supplicant is currently in the process of 1064 // connecting, and remove all networks so scans triggered in dark resume 1065 // are passive. 1066 supplicant_callback_copy.Run(); 1067 wake_on_wifi_triggers_.erase(kDisconnect); 1068 wake_on_wifi_triggers_.insert(kSSID); 1069 dhcp_lease_renewal_timer_.Stop(); 1070 if (has_service_configured_for_autoconnect) { 1071 // Only makes sense to wake to scan in dark resume if there is at least 1072 // one WiFi service that we can auto-connect to after the scan. 1073 // Timer callback is NO-OP since dark resume logic will initiate scan. 1074 wake_to_scan_timer_.Start( 1075 FROM_HERE, 1076 base::TimeDelta::FromSeconds(wake_to_scan_period_seconds_), 1077 Bind(&WakeOnWiFi::OnTimerWakeDoNothing, base::Unretained(this))); 1078 } 1079 } 1080 } 1081 1082 if (!in_dark_resume_ && wake_on_wifi_triggers_.empty()) { 1083 // No need program NIC on normal resume in this case since wake on WiFi 1084 // would already have been disabled on the last (non-dark) resume. 1085 LOG(INFO) << "No need to disable wake on WiFi on NIC in regular " 1086 "suspend"; 1087 RunAndResetSuspendActionsDoneCallback(Error(Error::kSuccess)); 1088 return; 1089 } 1090 1091 in_dark_resume_ = false; 1092 ApplyWakeOnWiFiSettings(); 1093} 1094 1095void WakeOnWiFi::OnDHCPLeaseObtained(bool start_lease_renewal_timer, 1096 uint32_t time_to_next_lease_renewal) { 1097 SLOG(this, 3) << __func__; 1098 if (in_dark_resume_) { 1099#if defined(DISABLE_WAKE_ON_WIFI) 1100 SLOG(this, 2) << "Wake on WiFi not supported, so do nothing"; 1101#else 1102 // If we obtain a DHCP lease, we are connected, so the callback to have 1103 // supplicant remove networks will not be invoked in 1104 // WakeOnWiFi::BeforeSuspendActions. Likewise, we will not use the value of 1105 // |has_service_configured_for_autoconnect| argument, so pass an arbitrary 1106 // value. 1107 BeforeSuspendActions(true, true, start_lease_renewal_timer, 1108 time_to_next_lease_renewal, base::Closure()); 1109#endif // DISABLE_WAKE_ON_WIFI 1110 } else { 1111 SLOG(this, 2) << "Not in dark resume, so do nothing"; 1112 } 1113} 1114 1115void WakeOnWiFi::ReportConnectedToServiceAfterWake(bool is_connected) { 1116#if defined(DISABLE_WAKE_ON_WIFI) 1117 metrics_->NotifyConnectedToServiceAfterWake( 1118 is_connected 1119 ? Metrics::kWiFiConnetionStatusAfterWakeOnWiFiDisabledWakeConnected 1120 : Metrics:: 1121 kWiFiConnetionStatusAfterWakeOnWiFiDisabledWakeNotConnected); 1122#else 1123 if (WakeOnSSIDEnabledAndSupported()) { 1124 // Only logged if wake on WiFi is supported and wake on SSID was enabled to 1125 // maintain connectivity while suspended. 1126 metrics_->NotifyConnectedToServiceAfterWake( 1127 is_connected 1128 ? Metrics::kWiFiConnetionStatusAfterWakeOnWiFiEnabledWakeConnected 1129 : Metrics:: 1130 kWiFiConnetionStatusAfterWakeOnWiFiEnabledWakeNotConnected); 1131 } else { 1132 metrics_->NotifyConnectedToServiceAfterWake( 1133 is_connected 1134 ? Metrics::kWiFiConnetionStatusAfterWakeOnWiFiDisabledWakeConnected 1135 : Metrics:: 1136 kWiFiConnetionStatusAfterWakeOnWiFiDisabledWakeNotConnected); 1137 } 1138#endif // DISABLE_WAKE_ON_WIFI 1139} 1140 1141void WakeOnWiFi::OnNoAutoConnectableServicesAfterScan( 1142 bool has_service_configured_for_autoconnect, 1143 const Closure &remove_supplicant_networks_callback) { 1144#if !defined(DISABLE_WAKE_ON_WIFI) 1145 SLOG(this, 3) << __func__ << ": " 1146 << (in_dark_resume_ ? "In dark resume" : "Not in dark resume"); 1147 if (in_dark_resume_) { 1148 // Assume that if there are no services available for auto-connect, then we 1149 // cannot be connected. Therefore, no need for lease renewal parameters. 1150 BeforeSuspendActions(false, has_service_configured_for_autoconnect, false, 1151 0, remove_supplicant_networks_callback); 1152 } 1153#endif // DISABLE_WAKE_ON_WIFI 1154} 1155 1156} // namespace shill 1157