wake_on_wifi.cc revision d1bec5d563afc9074a1875e2302d5ecf54c95f95
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::kWakeOnWiFiNotSupported[] = "Wake on WiFi not supported"; 50const int WakeOnWiFi::kVerifyWakeOnWiFiSettingsDelayMilliseconds = 300; 51const int WakeOnWiFi::kMaxSetWakeOnPacketRetries = 2; 52const int WakeOnWiFi::kMetricsReportingFrequencySeconds = 600; 53const uint32_t WakeOnWiFi::kDefaultWakeToScanPeriodSeconds = 900; 54const uint32_t WakeOnWiFi::kDefaultNetDetectScanPeriodSeconds = 120; 55const uint32_t WakeOnWiFi::kImmediateDHCPLeaseRenewalThresholdSeconds = 60; 56// We tolerate no more than 3 dark resumes per minute and 10 dark resumes per 57// 10 minutes before we disable wake on WiFi on the NIC. 58const int WakeOnWiFi::kDarkResumeFrequencySamplingPeriodShortMinutes = 1; 59const int WakeOnWiFi::kDarkResumeFrequencySamplingPeriodLongMinutes = 10; 60const int WakeOnWiFi::kMaxDarkResumesPerPeriodShort = 3; 61const int WakeOnWiFi::kMaxDarkResumesPerPeriodLong = 10; 62// If a connection is not established during dark resume, give up and prepare 63// the system to wake on SSID 1 second before suspending again. 64// TODO(samueltan): link this to 65// Manager::kTerminationActionsTimeoutMilliseconds rather than hard-coding 66// this value. 67int64_t WakeOnWiFi::DarkResumeActionsTimeoutMilliseconds = 18500; 68 69WakeOnWiFi::WakeOnWiFi(NetlinkManager *netlink_manager, 70 EventDispatcher *dispatcher, Metrics *metrics) 71 : dispatcher_(dispatcher), 72 netlink_manager_(netlink_manager), 73 metrics_(metrics), 74 report_metrics_callback_( 75 Bind(&WakeOnWiFi::ReportMetrics, base::Unretained(this))), 76 num_set_wake_on_packet_retries_(0), 77 wake_on_wifi_max_patterns_(0), 78 wake_on_wifi_max_ssids_(0), 79 wiphy_index_(0), 80 wiphy_index_received_(false), 81#if defined(DISABLE_WAKE_ON_WIFI) 82 wake_on_wifi_features_enabled_(kWakeOnWiFiFeaturesEnabledNotSupported), 83#else 84 // Wake on WiFi features disabled by default at run-time for boards that 85 // support wake on WiFi. Rely on Chrome to enable appropriate features via 86 // DBus. 87 wake_on_wifi_features_enabled_(kWakeOnWiFiFeaturesEnabledNone), 88#endif // DISABLE_WAKE_ON_WIFI 89 dhcp_lease_renewal_timer_(true, false), 90 wake_to_scan_timer_(true, false), 91 in_dark_resume_(false), 92 wake_to_scan_period_seconds_(kDefaultWakeToScanPeriodSeconds), 93 net_detect_scan_period_seconds_(kDefaultNetDetectScanPeriodSeconds), 94 last_wake_reason_(kWakeTriggerUnsupported), 95 force_wake_to_scan_timer_(false), 96 weak_ptr_factory_(this) { 97 netlink_manager_->AddBroadcastHandler(Bind( 98 &WakeOnWiFi::OnWakeupReasonReceived, weak_ptr_factory_.GetWeakPtr())); 99} 100 101WakeOnWiFi::~WakeOnWiFi() {} 102 103void WakeOnWiFi::InitPropertyStore(PropertyStore *store) { 104 store->RegisterDerivedString( 105 kWakeOnWiFiFeaturesEnabledProperty, 106 StringAccessor(new CustomAccessor<WakeOnWiFi, string>( 107 this, &WakeOnWiFi::GetWakeOnWiFiFeaturesEnabled, 108 &WakeOnWiFi::SetWakeOnWiFiFeaturesEnabled))); 109 store->RegisterUint32(kWakeToScanPeriodSecondsProperty, 110 &wake_to_scan_period_seconds_); 111 store->RegisterUint32(kNetDetectScanPeriodSecondsProperty, 112 &net_detect_scan_period_seconds_); 113 store->RegisterBool(kForceWakeToScanTimerProperty, 114 &force_wake_to_scan_timer_); 115} 116 117void WakeOnWiFi::StartMetricsTimer() { 118#if !defined(DISABLE_WAKE_ON_WIFI) 119 dispatcher_->PostDelayedTask(report_metrics_callback_.callback(), 120 kMetricsReportingFrequencySeconds * 1000); 121#endif // DISABLE_WAKE_ON_WIFI 122} 123 124string WakeOnWiFi::GetWakeOnWiFiFeaturesEnabled(Error *error) { 125 return wake_on_wifi_features_enabled_; 126} 127 128bool WakeOnWiFi::SetWakeOnWiFiFeaturesEnabled(const std::string &enabled, 129 Error *error) { 130#if defined(DISABLE_WAKE_ON_WIFI) 131 error->Populate(Error::kNotSupported, kWakeOnWiFiNotSupported); 132 SLOG(this, 7) << __func__ << ": " << kWakeOnWiFiNotSupported; 133 return false; 134#else 135 if (wake_on_wifi_features_enabled_ == enabled) { 136 return false; 137 } 138 if (enabled != kWakeOnWiFiFeaturesEnabledPacket && 139 enabled != kWakeOnWiFiFeaturesEnabledSSID && 140 enabled != kWakeOnWiFiFeaturesEnabledPacketSSID && 141 enabled != kWakeOnWiFiFeaturesEnabledNone) { 142 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 143 "Invalid Wake on WiFi feature"); 144 return false; 145 } 146 wake_on_wifi_features_enabled_ = enabled; 147 return true; 148#endif // DISABLE_WAKE_ON_WIFI 149} 150 151void WakeOnWiFi::RunAndResetSuspendActionsDoneCallback(const Error &error) { 152 if (!suspend_actions_done_callback_.is_null()) { 153 suspend_actions_done_callback_.Run(error); 154 suspend_actions_done_callback_.Reset(); 155 } 156} 157 158// static 159bool WakeOnWiFi::ByteStringPairIsLessThan( 160 const std::pair<ByteString, ByteString> &lhs, 161 const std::pair<ByteString, ByteString> &rhs) { 162 // Treat the first value of the pair as the key. 163 return ByteString::IsLessThan(lhs.first, rhs.first); 164} 165 166// static 167void WakeOnWiFi::SetMask(ByteString *mask, uint32_t pattern_len, 168 uint32_t offset) { 169 // Round up number of bytes required for the mask. 170 int result_mask_len = (pattern_len + 8 - 1) / 8; 171 vector<unsigned char> result_mask(result_mask_len, 0); 172 // Set mask bits from offset to (pattern_len - 1) 173 int mask_index; 174 for (uint32_t curr_mask_bit = offset; curr_mask_bit < pattern_len; 175 ++curr_mask_bit) { 176 mask_index = curr_mask_bit / 8; 177 result_mask[mask_index] |= 1 << (curr_mask_bit % 8); 178 } 179 mask->Clear(); 180 mask->Append(ByteString(result_mask)); 181} 182 183// static 184bool WakeOnWiFi::CreateIPAddressPatternAndMask(const IPAddress &ip_addr, 185 ByteString *pattern, 186 ByteString *mask) { 187 if (ip_addr.family() == IPAddress::kFamilyIPv4) { 188 WakeOnWiFi::CreateIPV4PatternAndMask(ip_addr, pattern, mask); 189 return true; 190 } else if (ip_addr.family() == IPAddress::kFamilyIPv6) { 191 WakeOnWiFi::CreateIPV6PatternAndMask(ip_addr, pattern, mask); 192 return true; 193 } else { 194 LOG(ERROR) << "Unrecognized IP Address type."; 195 return false; 196 } 197} 198 199// static 200void WakeOnWiFi::CreateIPV4PatternAndMask(const IPAddress &ip_addr, 201 ByteString *pattern, 202 ByteString *mask) { 203 struct { 204 struct ethhdr eth_hdr; 205 struct iphdr ipv4_hdr; 206 } __attribute__((__packed__)) pattern_bytes; 207 memset(&pattern_bytes, 0, sizeof(pattern_bytes)); 208 CHECK_EQ(sizeof(pattern_bytes.ipv4_hdr.saddr), ip_addr.GetLength()); 209 memcpy(&pattern_bytes.ipv4_hdr.saddr, ip_addr.GetConstData(), 210 ip_addr.GetLength()); 211 int src_ip_offset = 212 reinterpret_cast<unsigned char *>(&pattern_bytes.ipv4_hdr.saddr) - 213 reinterpret_cast<unsigned char *>(&pattern_bytes); 214 int pattern_len = src_ip_offset + ip_addr.GetLength(); 215 pattern->Clear(); 216 pattern->Append(ByteString( 217 reinterpret_cast<const unsigned char *>(&pattern_bytes), pattern_len)); 218 WakeOnWiFi::SetMask(mask, pattern_len, src_ip_offset); 219} 220 221// static 222void WakeOnWiFi::CreateIPV6PatternAndMask(const IPAddress &ip_addr, 223 ByteString *pattern, 224 ByteString *mask) { 225 struct { 226 struct ethhdr eth_hdr; 227 struct ip6_hdr ipv6_hdr; 228 } __attribute__((__packed__)) pattern_bytes; 229 memset(&pattern_bytes, 0, sizeof(pattern_bytes)); 230 CHECK_EQ(sizeof(pattern_bytes.ipv6_hdr.ip6_src), ip_addr.GetLength()); 231 memcpy(&pattern_bytes.ipv6_hdr.ip6_src, ip_addr.GetConstData(), 232 ip_addr.GetLength()); 233 int src_ip_offset = 234 reinterpret_cast<unsigned char *>(&pattern_bytes.ipv6_hdr.ip6_src) - 235 reinterpret_cast<unsigned char *>(&pattern_bytes); 236 int pattern_len = src_ip_offset + ip_addr.GetLength(); 237 pattern->Clear(); 238 pattern->Append(ByteString( 239 reinterpret_cast<const unsigned char *>(&pattern_bytes), pattern_len)); 240 WakeOnWiFi::SetMask(mask, pattern_len, src_ip_offset); 241} 242 243// static 244bool WakeOnWiFi::ConfigureWiphyIndex(Nl80211Message *msg, int32_t index) { 245 if (!msg->attributes()->CreateU32Attribute(NL80211_ATTR_WIPHY, 246 "WIPHY index")) { 247 return false; 248 } 249 if (!msg->attributes()->SetU32AttributeValue(NL80211_ATTR_WIPHY, index)) { 250 return false; 251 } 252 return true; 253} 254 255// static 256bool WakeOnWiFi::ConfigureDisableWakeOnWiFiMessage( 257 SetWakeOnPacketConnMessage *msg, uint32_t wiphy_index, Error *error) { 258 if (!ConfigureWiphyIndex(msg, wiphy_index)) { 259 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 260 "Failed to configure Wiphy index."); 261 return false; 262 } 263 return true; 264} 265 266// static 267bool WakeOnWiFi::ConfigureSetWakeOnWiFiSettingsMessage( 268 SetWakeOnPacketConnMessage *msg, const set<WakeOnWiFiTrigger> &trigs, 269 const IPAddressStore &addrs, uint32_t wiphy_index, 270 uint32_t net_detect_scan_period_seconds, 271 const vector<ByteString> &ssid_whitelist, 272 Error *error) { 273 if (trigs.empty()) { 274 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 275 "No triggers to configure."); 276 return false; 277 } 278 if (trigs.find(kWakeTriggerPattern) != trigs.end() && addrs.Empty()) { 279 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 280 "No IP addresses to configure."); 281 return false; 282 } 283 if (!ConfigureWiphyIndex(msg, wiphy_index)) { 284 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 285 "Failed to configure Wiphy index."); 286 return false; 287 } 288 if (!msg->attributes()->CreateNestedAttribute(NL80211_ATTR_WOWLAN_TRIGGERS, 289 "WoWLAN Triggers")) { 290 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 291 "Could not create nested attribute " 292 "NL80211_ATTR_WOWLAN_TRIGGERS"); 293 return false; 294 } 295 if (!msg->attributes()->SetNestedAttributeHasAValue( 296 NL80211_ATTR_WOWLAN_TRIGGERS)) { 297 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 298 "Could not set nested attribute " 299 "NL80211_ATTR_WOWLAN_TRIGGERS"); 300 return false; 301 } 302 303 AttributeListRefPtr triggers; 304 if (!msg->attributes()->GetNestedAttributeList(NL80211_ATTR_WOWLAN_TRIGGERS, 305 &triggers)) { 306 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 307 "Could not get nested attribute list " 308 "NL80211_ATTR_WOWLAN_TRIGGERS"); 309 return false; 310 } 311 // Add triggers. 312 for (WakeOnWiFiTrigger t : trigs) { 313 switch (t) { 314 case kWakeTriggerDisconnect: { 315 if (!triggers->CreateFlagAttribute(NL80211_WOWLAN_TRIG_DISCONNECT, 316 "Wake on Disconnect")) { 317 LOG(ERROR) << __func__ << "Could not create flag attribute " 318 "NL80211_WOWLAN_TRIG_DISCONNECT"; 319 return false; 320 } 321 if (!triggers->SetFlagAttributeValue(NL80211_WOWLAN_TRIG_DISCONNECT, 322 true)) { 323 LOG(ERROR) << __func__ << "Could not set flag attribute " 324 "NL80211_WOWLAN_TRIG_DISCONNECT"; 325 return false; 326 } 327 break; 328 } 329 case kWakeTriggerPattern: { 330 if (!triggers->CreateNestedAttribute(NL80211_WOWLAN_TRIG_PKT_PATTERN, 331 "Pattern trigger")) { 332 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 333 "Could not create nested attribute " 334 "NL80211_WOWLAN_TRIG_PKT_PATTERN"); 335 return false; 336 } 337 if (!triggers->SetNestedAttributeHasAValue( 338 NL80211_WOWLAN_TRIG_PKT_PATTERN)) { 339 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 340 "Could not set nested attribute " 341 "NL80211_WOWLAN_TRIG_PKT_PATTERN"); 342 return false; 343 } 344 AttributeListRefPtr patterns; 345 if (!triggers->GetNestedAttributeList(NL80211_WOWLAN_TRIG_PKT_PATTERN, 346 &patterns)) { 347 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 348 "Could not get nested attribute list " 349 "NL80211_WOWLAN_TRIG_PKT_PATTERN"); 350 return false; 351 } 352 uint8_t patnum = 1; 353 for (const IPAddress &addr : addrs.GetIPAddresses()) { 354 if (!CreateSinglePattern(addr, patterns, patnum++, error)) { 355 return false; 356 } 357 } 358 break; 359 } 360 case kWakeTriggerSSID: { 361 if (!triggers->CreateNestedAttribute(NL80211_WOWLAN_TRIG_NET_DETECT, 362 "Wake on SSID trigger")) { 363 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 364 "Could not create nested attribute " 365 "NL80211_WOWLAN_TRIG_NET_DETECT"); 366 return false; 367 } 368 if (!triggers->SetNestedAttributeHasAValue( 369 NL80211_WOWLAN_TRIG_NET_DETECT)) { 370 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 371 "Could not set nested attribute " 372 "NL80211_WOWLAN_TRIG_NET_DETECT"); 373 return false; 374 } 375 AttributeListRefPtr scan_attributes; 376 if (!triggers->GetNestedAttributeList(NL80211_WOWLAN_TRIG_NET_DETECT, 377 &scan_attributes)) { 378 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 379 "Could not get nested attribute list " 380 "NL80211_WOWLAN_TRIG_NET_DETECT"); 381 return false; 382 } 383 if (!scan_attributes->CreateU32Attribute( 384 NL80211_ATTR_SCHED_SCAN_INTERVAL, 385 "NL80211_ATTR_SCHED_SCAN_INTERVAL")) { 386 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 387 "Could not get create U32 attribute " 388 "NL80211_ATTR_SCHED_SCAN_INTERVAL"); 389 return false; 390 } 391 if (!scan_attributes->SetU32AttributeValue( 392 NL80211_ATTR_SCHED_SCAN_INTERVAL, 393 net_detect_scan_period_seconds * 1000)) { 394 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 395 "Could not get set U32 attribute " 396 "NL80211_ATTR_SCHED_SCAN_INTERVAL"); 397 return false; 398 } 399 if (!scan_attributes->CreateNestedAttribute( 400 NL80211_ATTR_SCHED_SCAN_MATCH, 401 "NL80211_ATTR_SCHED_SCAN_MATCH")) { 402 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 403 "Could not create nested attribute list " 404 "NL80211_ATTR_SCHED_SCAN_MATCH"); 405 return false; 406 } 407 if (!scan_attributes->SetNestedAttributeHasAValue( 408 NL80211_ATTR_SCHED_SCAN_MATCH)) { 409 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 410 "Could not set nested attribute " 411 "NL80211_ATTR_SCAN_SSIDS"); 412 return false; 413 } 414 AttributeListRefPtr ssids; 415 if (!scan_attributes->GetNestedAttributeList( 416 NL80211_ATTR_SCHED_SCAN_MATCH, &ssids)) { 417 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 418 "Could not get nested attribute list " 419 "NL80211_ATTR_SCHED_SCAN_MATCH"); 420 return false; 421 } 422 int ssid_num = 0; 423 for (const ByteString &ssid_bytes : 424 ssid_whitelist) { 425 if (!ssids->CreateNestedAttribute( 426 ssid_num, "NL80211_ATTR_SCHED_SCAN_MATCH_SINGLE")) { 427 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 428 "Could not create nested attribute list " 429 "NL80211_ATTR_SCHED_SCAN_MATCH_SINGLE"); 430 return false; 431 } 432 if (!ssids->SetNestedAttributeHasAValue(ssid_num)) { 433 Error::PopulateAndLog( 434 FROM_HERE, error, Error::kOperationFailed, 435 "Could not set value for nested attribute list " 436 "NL80211_ATTR_SCHED_SCAN_MATCH_SINGLE"); 437 return false; 438 } 439 AttributeListRefPtr single_ssid; 440 if (!ssids->GetNestedAttributeList(ssid_num, &single_ssid)) { 441 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 442 "Could not get nested attribute list " 443 "NL80211_ATTR_SCHED_SCAN_MATCH_SINGLE"); 444 return false; 445 } 446 if (!single_ssid->CreateRawAttribute( 447 NL80211_SCHED_SCAN_MATCH_ATTR_SSID, 448 "NL80211_SCHED_SCAN_MATCH_ATTR_SSID")) { 449 Error::PopulateAndLog( 450 FROM_HERE, error, Error::kOperationFailed, 451 "Could not create NL80211_SCHED_SCAN_MATCH_ATTR_SSID"); 452 return false; 453 } 454 if (!single_ssid->SetRawAttributeValue( 455 NL80211_SCHED_SCAN_MATCH_ATTR_SSID, ssid_bytes)) { 456 Error::PopulateAndLog( 457 FROM_HERE, error, Error::kOperationFailed, 458 "Could not set NL80211_SCHED_SCAN_MATCH_ATTR_SSID"); 459 return false; 460 } 461 ++ssid_num; 462 } 463 break; 464 } 465 default: { 466 LOG(ERROR) << __func__ << ": Unrecognized trigger"; 467 return false; 468 } 469 } 470 } 471 return true; 472} 473 474// static 475bool WakeOnWiFi::CreateSinglePattern(const IPAddress &ip_addr, 476 AttributeListRefPtr patterns, 477 uint8_t patnum, Error *error) { 478 ByteString pattern; 479 ByteString mask; 480 WakeOnWiFi::CreateIPAddressPatternAndMask(ip_addr, &pattern, &mask); 481 if (!patterns->CreateNestedAttribute(patnum, "Pattern info")) { 482 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 483 "Could not create nested attribute " 484 "patnum for SetWakeOnPacketConnMessage."); 485 return false; 486 } 487 if (!patterns->SetNestedAttributeHasAValue(patnum)) { 488 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 489 "Could not set nested attribute " 490 "patnum for SetWakeOnPacketConnMessage."); 491 return false; 492 } 493 494 AttributeListRefPtr pattern_info; 495 if (!patterns->GetNestedAttributeList(patnum, &pattern_info)) { 496 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 497 "Could not get nested attribute list " 498 "patnum for SetWakeOnPacketConnMessage."); 499 return false; 500 } 501 // Add mask. 502 if (!pattern_info->CreateRawAttribute(NL80211_PKTPAT_MASK, "Mask")) { 503 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 504 "Could not add attribute NL80211_PKTPAT_MASK to " 505 "pattern_info."); 506 return false; 507 } 508 if (!pattern_info->SetRawAttributeValue(NL80211_PKTPAT_MASK, mask)) { 509 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 510 "Could not set attribute NL80211_PKTPAT_MASK in " 511 "pattern_info."); 512 return false; 513 } 514 515 // Add pattern. 516 if (!pattern_info->CreateRawAttribute(NL80211_PKTPAT_PATTERN, "Pattern")) { 517 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 518 "Could not add attribute NL80211_PKTPAT_PATTERN to " 519 "pattern_info."); 520 return false; 521 } 522 if (!pattern_info->SetRawAttributeValue(NL80211_PKTPAT_PATTERN, pattern)) { 523 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 524 "Could not set attribute NL80211_PKTPAT_PATTERN in " 525 "pattern_info."); 526 return false; 527 } 528 529 // Add offset. 530 if (!pattern_info->CreateU32Attribute(NL80211_PKTPAT_OFFSET, "Offset")) { 531 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 532 "Could not add attribute NL80211_PKTPAT_OFFSET to " 533 "pattern_info."); 534 return false; 535 } 536 if (!pattern_info->SetU32AttributeValue(NL80211_PKTPAT_OFFSET, 0)) { 537 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 538 "Could not set attribute NL80211_PKTPAT_OFFSET in " 539 "pattern_info."); 540 return false; 541 } 542 return true; 543} 544 545// static 546bool WakeOnWiFi::ConfigureGetWakeOnWiFiSettingsMessage( 547 GetWakeOnPacketConnMessage *msg, uint32_t wiphy_index, Error *error) { 548 if (!ConfigureWiphyIndex(msg, wiphy_index)) { 549 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 550 "Failed to configure Wiphy index."); 551 return false; 552 } 553 return true; 554} 555 556// static 557bool WakeOnWiFi::WakeOnWiFiSettingsMatch( 558 const Nl80211Message &msg, const set<WakeOnWiFiTrigger> &trigs, 559 const IPAddressStore &addrs, uint32_t net_detect_scan_period_seconds, 560 const vector<ByteString> &ssid_whitelist) { 561 if (msg.command() != NL80211_CMD_GET_WOWLAN && 562 msg.command() != NL80211_CMD_SET_WOWLAN) { 563 LOG(ERROR) << __func__ << ": " 564 << "Invalid message command"; 565 return false; 566 } 567 AttributeListConstRefPtr triggers; 568 if (!msg.const_attributes()->ConstGetNestedAttributeList( 569 NL80211_ATTR_WOWLAN_TRIGGERS, &triggers)) { 570 // No triggers in the returned message, which is valid iff we expect there 571 // to be no triggers programmed into the NIC. 572 return trigs.empty(); 573 } 574 // If we find a trigger in |msg| that we do not have a corresponding flag 575 // for in |trigs|, we have a mismatch. 576 bool unused_flag; 577 AttributeListConstRefPtr unused_list; 578 if (triggers->GetFlagAttributeValue(NL80211_WOWLAN_TRIG_DISCONNECT, 579 &unused_flag) && 580 trigs.find(kWakeTriggerDisconnect) == trigs.end()) { 581 SLOG(WiFi, nullptr, 3) 582 << __func__ << "Wake on disconnect trigger not expected but found"; 583 return false; 584 } 585 if (triggers->ConstGetNestedAttributeList(NL80211_WOWLAN_TRIG_PKT_PATTERN, 586 &unused_list) && 587 trigs.find(kWakeTriggerPattern) == trigs.end()) { 588 SLOG(WiFi, nullptr, 3) << __func__ 589 << "Wake on pattern trigger not expected but found"; 590 return false; 591 } 592 if (triggers->ConstGetNestedAttributeList(NL80211_WOWLAN_TRIG_NET_DETECT, 593 &unused_list) && 594 trigs.find(kWakeTriggerSSID) == trigs.end()) { 595 SLOG(WiFi, nullptr, 3) << __func__ 596 << "Wake on SSID trigger not expected but found"; 597 return false; 598 } 599 // Check that each expected trigger is present in |msg| with matching 600 // setting values. 601 for (WakeOnWiFiTrigger t : trigs) { 602 switch (t) { 603 case kWakeTriggerDisconnect: { 604 bool wake_on_disconnect; 605 if (!triggers->GetFlagAttributeValue(NL80211_WOWLAN_TRIG_DISCONNECT, 606 &wake_on_disconnect)) { 607 LOG(ERROR) << __func__ << ": " 608 << "Could not get the flag NL80211_WOWLAN_TRIG_DISCONNECT"; 609 return false; 610 } 611 if (!wake_on_disconnect) { 612 SLOG(WiFi, nullptr, 3) << __func__ 613 << "Wake on disconnect flag not set."; 614 return false; 615 } 616 break; 617 } 618 case kWakeTriggerPattern: { 619 // Create pattern and masks that we expect to find in |msg|. 620 set<pair<ByteString, ByteString>, 621 bool (*)(const pair<ByteString, ByteString> &, 622 const pair<ByteString, ByteString> &)> 623 expected_patt_mask_pairs(ByteStringPairIsLessThan); 624 ByteString temp_pattern; 625 ByteString temp_mask; 626 for (const IPAddress &addr : addrs.GetIPAddresses()) { 627 temp_pattern.Clear(); 628 temp_mask.Clear(); 629 CreateIPAddressPatternAndMask(addr, &temp_pattern, &temp_mask); 630 expected_patt_mask_pairs.emplace(temp_pattern, temp_mask); 631 } 632 // Check these expected pattern and masks against those actually 633 // contained in |msg|. 634 AttributeListConstRefPtr patterns; 635 if (!triggers->ConstGetNestedAttributeList( 636 NL80211_WOWLAN_TRIG_PKT_PATTERN, &patterns)) { 637 LOG(ERROR) << __func__ << ": " 638 << "Could not get nested attribute list " 639 "NL80211_WOWLAN_TRIG_PKT_PATTERN"; 640 return false; 641 } 642 bool pattern_mismatch_found = false; 643 size_t pattern_num_mismatch = expected_patt_mask_pairs.size(); 644 int pattern_index; 645 AttributeIdIterator pattern_iter(*patterns); 646 AttributeListConstRefPtr pattern_info; 647 ByteString returned_mask; 648 ByteString returned_pattern; 649 while (!pattern_iter.AtEnd()) { 650 returned_mask.Clear(); 651 returned_pattern.Clear(); 652 pattern_index = pattern_iter.GetId(); 653 if (!patterns->ConstGetNestedAttributeList(pattern_index, 654 &pattern_info)) { 655 LOG(ERROR) << __func__ << ": " 656 << "Could not get nested pattern attribute list #" 657 << pattern_index; 658 return false; 659 } 660 if (!pattern_info->GetRawAttributeValue(NL80211_PKTPAT_MASK, 661 &returned_mask)) { 662 LOG(ERROR) << __func__ << ": " 663 << "Could not get attribute NL80211_PKTPAT_MASK"; 664 return false; 665 } 666 if (!pattern_info->GetRawAttributeValue(NL80211_PKTPAT_PATTERN, 667 &returned_pattern)) { 668 LOG(ERROR) << __func__ << ": " 669 << "Could not get attribute NL80211_PKTPAT_PATTERN"; 670 return false; 671 } 672 if (expected_patt_mask_pairs.find(pair<ByteString, ByteString>( 673 returned_pattern, returned_mask)) == 674 expected_patt_mask_pairs.end()) { 675 pattern_mismatch_found = true; 676 break; 677 } else { 678 --pattern_num_mismatch; 679 } 680 pattern_iter.Advance(); 681 } 682 if (pattern_mismatch_found || pattern_num_mismatch) { 683 SLOG(WiFi, nullptr, 3) << __func__ 684 << "Wake on pattern pattern/mask mismatch"; 685 return false; 686 } 687 break; 688 } 689 case kWakeTriggerSSID: { 690 set<ByteString, bool (*)(const ByteString &, const ByteString &)> 691 expected_ssids(ssid_whitelist.begin(), ssid_whitelist.end(), 692 ByteString::IsLessThan); 693 AttributeListConstRefPtr scan_attributes; 694 if (!triggers->ConstGetNestedAttributeList( 695 NL80211_WOWLAN_TRIG_NET_DETECT, &scan_attributes)) { 696 LOG(ERROR) << __func__ << ": " 697 << "Could not get nested attribute list " 698 "NL80211_WOWLAN_TRIG_NET_DETECT"; 699 return false; 700 } 701 uint32_t interval; 702 if (!scan_attributes->GetU32AttributeValue( 703 NL80211_ATTR_SCHED_SCAN_INTERVAL, &interval)) { 704 LOG(ERROR) << __func__ << ": " 705 << "Could not get set U32 attribute " 706 "NL80211_ATTR_SCHED_SCAN_INTERVAL"; 707 return false; 708 } 709 if (interval != net_detect_scan_period_seconds * 1000) { 710 SLOG(WiFi, nullptr, 3) << __func__ 711 << "Net Detect scan period mismatch"; 712 return false; 713 } 714 AttributeListConstRefPtr ssids; 715 if (!scan_attributes->ConstGetNestedAttributeList( 716 NL80211_ATTR_SCHED_SCAN_MATCH, &ssids)) { 717 LOG(ERROR) << __func__ << ": " 718 << "Could not get nested attribute list " 719 "NL80211_ATTR_SCHED_SCAN_MATCH"; 720 return false; 721 } 722 bool ssid_mismatch_found = false; 723 size_t ssid_num_mismatch = expected_ssids.size(); 724 AttributeIdIterator ssid_iter(*ssids); 725 AttributeListConstRefPtr single_ssid; 726 ByteString ssid; 727 int ssid_index; 728 while (!ssid_iter.AtEnd()) { 729 ssid.Clear(); 730 ssid_index = ssid_iter.GetId(); 731 if (!ssids->ConstGetNestedAttributeList(ssid_index, &single_ssid)) { 732 LOG(ERROR) << __func__ << ": " 733 << "Could not get nested ssid attribute list #" 734 << ssid_index; 735 return false; 736 } 737 if (!single_ssid->GetRawAttributeValue( 738 NL80211_SCHED_SCAN_MATCH_ATTR_SSID, &ssid)) { 739 LOG(ERROR) << __func__ << ": " 740 << "Could not get attribute " 741 "NL80211_SCHED_SCAN_MATCH_ATTR_SSID"; 742 return false; 743 } 744 if (expected_ssids.find(ssid) == expected_ssids.end()) { 745 ssid_mismatch_found = true; 746 break; 747 } else { 748 --ssid_num_mismatch; 749 } 750 ssid_iter.Advance(); 751 } 752 if (ssid_mismatch_found || ssid_num_mismatch) { 753 SLOG(WiFi, nullptr, 3) << __func__ << "Net Detect SSID mismatch"; 754 return false; 755 } 756 break; 757 } 758 default: { 759 LOG(ERROR) << __func__ << ": Unrecognized trigger"; 760 return false; 761 } 762 } 763 } 764 return true; 765} 766 767void WakeOnWiFi::AddWakeOnPacketConnection(const string &ip_endpoint, 768 Error *error) { 769#if !defined(DISABLE_WAKE_ON_WIFI) 770 if (wake_on_wifi_triggers_supported_.find(kWakeTriggerPattern) == 771 wake_on_wifi_triggers_supported_.end()) { 772 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported, 773 kWakeOnIPAddressPatternsNotSupported); 774 return; 775 } 776 IPAddress ip_addr(ip_endpoint); 777 if (!ip_addr.IsValid()) { 778 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 779 "Invalid ip_address " + ip_endpoint); 780 return; 781 } 782 if (wake_on_packet_connections_.Count() >= wake_on_wifi_max_patterns_) { 783 Error::PopulateAndLog( 784 FROM_HERE, error, Error::kOperationFailed, 785 "Max number of IP address patterns already registered"); 786 return; 787 } 788 wake_on_packet_connections_.AddUnique(ip_addr); 789#else 790 error->Populate(Error::kNotSupported, kWakeOnWiFiNotSupported); 791 SLOG(this, 7) << __func__ << ": " << kWakeOnWiFiNotSupported; 792#endif // DISABLE_WAKE_ON_WIFI 793} 794 795void WakeOnWiFi::RemoveWakeOnPacketConnection(const string &ip_endpoint, 796 Error *error) { 797#if !defined(DISABLE_WAKE_ON_WIFI) 798 if (wake_on_wifi_triggers_supported_.find(kWakeTriggerPattern) == 799 wake_on_wifi_triggers_supported_.end()) { 800 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported, 801 kWakeOnIPAddressPatternsNotSupported); 802 return; 803 } 804 IPAddress ip_addr(ip_endpoint); 805 if (!ip_addr.IsValid()) { 806 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 807 "Invalid ip_address " + ip_endpoint); 808 return; 809 } 810 if (!wake_on_packet_connections_.Contains(ip_addr)) { 811 Error::PopulateAndLog(FROM_HERE, error, Error::kNotFound, 812 "No such IP address match registered to wake device"); 813 return; 814 } 815 wake_on_packet_connections_.Remove(ip_addr); 816#else 817 error->Populate(Error::kNotSupported, kWakeOnWiFiNotSupported); 818 SLOG(this, 7) << __func__ << ": " << kWakeOnWiFiNotSupported; 819#endif // DISABLE_WAKE_ON_WIFI 820} 821 822void WakeOnWiFi::RemoveAllWakeOnPacketConnections(Error *error) { 823#if !defined(DISABLE_WAKE_ON_WIFI) 824 if (wake_on_wifi_triggers_supported_.find(kWakeTriggerPattern) == 825 wake_on_wifi_triggers_supported_.end()) { 826 Error::PopulateAndLog(FROM_HERE, error, Error::kNotSupported, 827 kWakeOnIPAddressPatternsNotSupported); 828 return; 829 } 830 wake_on_packet_connections_.Clear(); 831#else 832 error->Populate(Error::kNotSupported, kWakeOnWiFiNotSupported); 833 SLOG(this, 7) << __func__ << ": " << kWakeOnWiFiNotSupported; 834#endif // DISABLE_WAKE_ON_WIFI 835} 836 837void WakeOnWiFi::OnWakeOnWiFiSettingsErrorResponse( 838 NetlinkManager::AuxilliaryMessageType type, 839 const NetlinkMessage *raw_message) { 840 Error error(Error::kOperationFailed); 841 switch (type) { 842 case NetlinkManager::kErrorFromKernel: 843 if (!raw_message) { 844 error.Populate(Error::kOperationFailed, "Unknown error from kernel"); 845 break; 846 } 847 if (raw_message->message_type() == ErrorAckMessage::GetMessageType()) { 848 const ErrorAckMessage *error_ack_message = 849 dynamic_cast<const ErrorAckMessage *>(raw_message); 850 if (error_ack_message->error() == EOPNOTSUPP) { 851 error.Populate(Error::kNotSupported); 852 } 853 } 854 break; 855 856 case NetlinkManager::kUnexpectedResponseType: 857 error.Populate(Error::kNotRegistered, 858 "Message not handled by regular message handler:"); 859 break; 860 861 case NetlinkManager::kTimeoutWaitingForResponse: 862 // CMD_SET_WOWLAN messages do not receive responses, so this error type 863 // is received when NetlinkManager times out the message handler. Return 864 // immediately rather than run the done callback since this event does 865 // not signify the completion of suspend actions. 866 return; 867 break; 868 869 default: 870 error.Populate( 871 Error::kOperationFailed, 872 "Unexpected auxilliary message type: " + std::to_string(type)); 873 break; 874 } 875 RunAndResetSuspendActionsDoneCallback(error); 876} 877 878// static 879void WakeOnWiFi::OnSetWakeOnPacketConnectionResponse( 880 const Nl80211Message &nl80211_message) { 881 // NOP because kernel does not send a response to NL80211_CMD_SET_WOWLAN 882 // requests. 883} 884 885void WakeOnWiFi::RequestWakeOnPacketSettings() { 886 SLOG(this, 3) << __func__; 887 Error e; 888 GetWakeOnPacketConnMessage get_wowlan_msg; 889 CHECK(wiphy_index_received_); 890 if (!ConfigureGetWakeOnWiFiSettingsMessage(&get_wowlan_msg, wiphy_index_, 891 &e)) { 892 LOG(ERROR) << e.message(); 893 return; 894 } 895 netlink_manager_->SendNl80211Message( 896 &get_wowlan_msg, Bind(&WakeOnWiFi::VerifyWakeOnWiFiSettings, 897 weak_ptr_factory_.GetWeakPtr()), 898 Bind(&NetlinkManager::OnAckDoNothing), 899 Bind(&NetlinkManager::OnNetlinkMessageError)); 900} 901 902void WakeOnWiFi::VerifyWakeOnWiFiSettings( 903 const Nl80211Message &nl80211_message) { 904 SLOG(this, 3) << __func__; 905 if (WakeOnWiFiSettingsMatch(nl80211_message, wake_on_wifi_triggers_, 906 wake_on_packet_connections_, 907 net_detect_scan_period_seconds_, 908 wake_on_ssid_whitelist_)) { 909 SLOG(this, 2) << __func__ << ": " 910 << "Wake on WiFi settings successfully verified"; 911 metrics_->NotifyVerifyWakeOnWiFiSettingsResult( 912 Metrics::kVerifyWakeOnWiFiSettingsResultSuccess); 913 RunAndResetSuspendActionsDoneCallback(Error(Error::kSuccess)); 914 } else { 915 LOG(ERROR) << __func__ << " failed: discrepancy between wake-on-packet " 916 "settings on NIC and those in local data " 917 "structure detected"; 918 metrics_->NotifyVerifyWakeOnWiFiSettingsResult( 919 Metrics::kVerifyWakeOnWiFiSettingsResultFailure); 920 RetrySetWakeOnPacketConnections(); 921 } 922} 923 924void WakeOnWiFi::ApplyWakeOnWiFiSettings() { 925 SLOG(this, 3) << __func__; 926 if (!wiphy_index_received_) { 927 LOG(ERROR) << "Interface index not yet received"; 928 return; 929 } 930 if (wake_on_wifi_triggers_.empty()) { 931 SLOG(this, 1) << "No triggers to be programmed, so disable wake on WiFi"; 932 DisableWakeOnWiFi(); 933 return; 934 } 935 936 Error error; 937 SetWakeOnPacketConnMessage set_wowlan_msg; 938 if (!ConfigureSetWakeOnWiFiSettingsMessage( 939 &set_wowlan_msg, wake_on_wifi_triggers_, wake_on_packet_connections_, 940 wiphy_index_, net_detect_scan_period_seconds_, 941 wake_on_ssid_whitelist_, &error)) { 942 LOG(ERROR) << error.message(); 943 RunAndResetSuspendActionsDoneCallback( 944 Error(Error::kOperationFailed, error.message())); 945 return; 946 } 947 if (!netlink_manager_->SendNl80211Message( 948 &set_wowlan_msg, 949 Bind(&WakeOnWiFi::OnSetWakeOnPacketConnectionResponse), 950 Bind(&NetlinkManager::OnAckDoNothing), 951 Bind(&WakeOnWiFi::OnWakeOnWiFiSettingsErrorResponse, 952 weak_ptr_factory_.GetWeakPtr()))) { 953 RunAndResetSuspendActionsDoneCallback( 954 Error(Error::kOperationFailed, "SendNl80211Message failed")); 955 return; 956 } 957 958 verify_wake_on_packet_settings_callback_.Reset( 959 Bind(&WakeOnWiFi::RequestWakeOnPacketSettings, 960 weak_ptr_factory_.GetWeakPtr())); 961 dispatcher_->PostDelayedTask( 962 verify_wake_on_packet_settings_callback_.callback(), 963 kVerifyWakeOnWiFiSettingsDelayMilliseconds); 964} 965 966void WakeOnWiFi::DisableWakeOnWiFi() { 967 SLOG(this, 3) << __func__; 968 Error error; 969 SetWakeOnPacketConnMessage disable_wowlan_msg; 970 CHECK(wiphy_index_received_); 971 if (!ConfigureDisableWakeOnWiFiMessage(&disable_wowlan_msg, wiphy_index_, 972 &error)) { 973 LOG(ERROR) << error.message(); 974 RunAndResetSuspendActionsDoneCallback( 975 Error(Error::kOperationFailed, error.message())); 976 return; 977 } 978 wake_on_wifi_triggers_.clear(); 979 if (!netlink_manager_->SendNl80211Message( 980 &disable_wowlan_msg, 981 Bind(&WakeOnWiFi::OnSetWakeOnPacketConnectionResponse), 982 Bind(&NetlinkManager::OnAckDoNothing), 983 Bind(&WakeOnWiFi::OnWakeOnWiFiSettingsErrorResponse, 984 weak_ptr_factory_.GetWeakPtr()))) { 985 RunAndResetSuspendActionsDoneCallback( 986 Error(Error::kOperationFailed, "SendNl80211Message failed")); 987 return; 988 } 989 990 verify_wake_on_packet_settings_callback_.Reset( 991 Bind(&WakeOnWiFi::RequestWakeOnPacketSettings, 992 weak_ptr_factory_.GetWeakPtr())); 993 dispatcher_->PostDelayedTask( 994 verify_wake_on_packet_settings_callback_.callback(), 995 kVerifyWakeOnWiFiSettingsDelayMilliseconds); 996} 997 998void WakeOnWiFi::RetrySetWakeOnPacketConnections() { 999 SLOG(this, 3) << __func__; 1000 if (num_set_wake_on_packet_retries_ < kMaxSetWakeOnPacketRetries) { 1001 ApplyWakeOnWiFiSettings(); 1002 ++num_set_wake_on_packet_retries_; 1003 } else { 1004 SLOG(this, 3) << __func__ << ": max retry attempts reached"; 1005 num_set_wake_on_packet_retries_ = 0; 1006 RunAndResetSuspendActionsDoneCallback(Error(Error::kOperationFailed)); 1007 } 1008} 1009 1010bool WakeOnWiFi::WakeOnPacketEnabledAndSupported() { 1011 if (wake_on_wifi_features_enabled_ == kWakeOnWiFiFeaturesEnabledNone || 1012 wake_on_wifi_features_enabled_ == 1013 kWakeOnWiFiFeaturesEnabledNotSupported || 1014 wake_on_wifi_features_enabled_ == kWakeOnWiFiFeaturesEnabledSSID) { 1015 return false; 1016 } 1017 if (wake_on_wifi_triggers_supported_.find(kWakeTriggerPattern) == 1018 wake_on_wifi_triggers_supported_.end()) { 1019 return false; 1020 } 1021 return true; 1022} 1023 1024bool WakeOnWiFi::WakeOnSSIDEnabledAndSupported() { 1025 if (wake_on_wifi_features_enabled_ == kWakeOnWiFiFeaturesEnabledNone || 1026 wake_on_wifi_features_enabled_ == 1027 kWakeOnWiFiFeaturesEnabledNotSupported || 1028 wake_on_wifi_features_enabled_ == kWakeOnWiFiFeaturesEnabledPacket) { 1029 return false; 1030 } 1031 if (wake_on_wifi_triggers_supported_.find(kWakeTriggerDisconnect) == 1032 wake_on_wifi_triggers_supported_.end() || 1033 wake_on_wifi_triggers_supported_.find(kWakeTriggerSSID) == 1034 wake_on_wifi_triggers_supported_.end()) { 1035 return false; 1036 } 1037 return true; 1038} 1039 1040void WakeOnWiFi::ReportMetrics() { 1041 Metrics::WakeOnWiFiFeaturesEnabledState reported_state; 1042 if (wake_on_wifi_features_enabled_ == kWakeOnWiFiFeaturesEnabledNone) { 1043 reported_state = Metrics::kWakeOnWiFiFeaturesEnabledStateNone; 1044 } else if (wake_on_wifi_features_enabled_ == 1045 kWakeOnWiFiFeaturesEnabledPacket) { 1046 reported_state = Metrics::kWakeOnWiFiFeaturesEnabledStatePacket; 1047 } else if (wake_on_wifi_features_enabled_ == kWakeOnWiFiFeaturesEnabledSSID) { 1048 reported_state = Metrics::kWakeOnWiFiFeaturesEnabledStateSSID; 1049 } else if (wake_on_wifi_features_enabled_ == 1050 kWakeOnWiFiFeaturesEnabledPacketSSID) { 1051 reported_state = Metrics::kWakeOnWiFiFeaturesEnabledStatePacketSSID; 1052 } else { 1053 LOG(ERROR) << __func__ << ": " 1054 << "Invalid wake on WiFi features state"; 1055 return; 1056 } 1057 metrics_->NotifyWakeOnWiFiFeaturesEnabledState(reported_state); 1058 StartMetricsTimer(); 1059} 1060 1061void WakeOnWiFi::ParseWakeOnWiFiCapabilities( 1062 const Nl80211Message &nl80211_message) { 1063 // Verify NL80211_CMD_NEW_WIPHY. 1064 if (nl80211_message.command() != NewWiphyMessage::kCommand) { 1065 LOG(ERROR) << "Received unexpected command:" << nl80211_message.command(); 1066 return; 1067 } 1068 AttributeListConstRefPtr triggers_supported; 1069 if (nl80211_message.const_attributes()->ConstGetNestedAttributeList( 1070 NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, &triggers_supported)) { 1071 bool disconnect_supported = false; 1072 if (triggers_supported->GetFlagAttributeValue( 1073 NL80211_WOWLAN_TRIG_DISCONNECT, &disconnect_supported)) { 1074 if (disconnect_supported) { 1075 wake_on_wifi_triggers_supported_.insert( 1076 WakeOnWiFi::kWakeTriggerDisconnect); 1077 SLOG(this, 7) << "Waking on disconnect supported by this WiFi device"; 1078 } 1079 } 1080 ByteString pattern_data; 1081 if (triggers_supported->GetRawAttributeValue( 1082 NL80211_WOWLAN_TRIG_PKT_PATTERN, &pattern_data)) { 1083 struct nl80211_pattern_support *patt_support = 1084 reinterpret_cast<struct nl80211_pattern_support *>( 1085 pattern_data.GetData()); 1086 // Determine the IPV4 and IPV6 pattern lengths we will use by 1087 // constructing dummy patterns and getting their lengths. 1088 ByteString dummy_pattern; 1089 ByteString dummy_mask; 1090 WakeOnWiFi::CreateIPV4PatternAndMask(IPAddress("192.168.0.20"), 1091 &dummy_pattern, &dummy_mask); 1092 size_t ipv4_pattern_len = dummy_pattern.GetLength(); 1093 WakeOnWiFi::CreateIPV6PatternAndMask( 1094 IPAddress("FEDC:BA98:7654:3210:FEDC:BA98:7654:3210"), &dummy_pattern, 1095 &dummy_mask); 1096 size_t ipv6_pattern_len = dummy_pattern.GetLength(); 1097 // Check if the pattern matching capabilities of this WiFi device will 1098 // allow IPV4 and IPV6 patterns to be used. 1099 if (patt_support->min_pattern_len <= 1100 std::min(ipv4_pattern_len, ipv6_pattern_len) && 1101 patt_support->max_pattern_len >= 1102 std::max(ipv4_pattern_len, ipv6_pattern_len)) { 1103 wake_on_wifi_triggers_supported_.insert( 1104 WakeOnWiFi::kWakeTriggerPattern); 1105 wake_on_wifi_max_patterns_ = patt_support->max_patterns; 1106 SLOG(this, 7) << "Waking on up to " << wake_on_wifi_max_patterns_ 1107 << " registered patterns of " 1108 << patt_support->min_pattern_len << "-" 1109 << patt_support->max_pattern_len 1110 << " bytes supported by this WiFi device"; 1111 } 1112 } 1113 if (triggers_supported->GetU32AttributeValue(NL80211_WOWLAN_TRIG_NET_DETECT, 1114 &wake_on_wifi_max_ssids_)) { 1115 wake_on_wifi_triggers_supported_.insert(WakeOnWiFi::kWakeTriggerSSID); 1116 SLOG(this, 7) << "Waking on up to " << wake_on_wifi_max_ssids_ 1117 << " whitelisted SSIDs supported by this WiFi device"; 1118 } 1119 } 1120} 1121 1122void WakeOnWiFi::OnWakeupReasonReceived(const NetlinkMessage &netlink_message) { 1123#if defined(DISABLE_WAKE_ON_WIFI) 1124 SLOG(this, 7) << __func__ << ": " 1125 << "Wake on WiFi not supported, so do nothing"; 1126#else 1127 metrics_->NotifyWakeupReasonReceived(); 1128 // We only handle wakeup reason messages in this handler, which is are 1129 // nl80211 messages with the NL80211_CMD_SET_WOWLAN command. 1130 if (netlink_message.message_type() != Nl80211Message::GetMessageType()) { 1131 SLOG(this, 7) << __func__ << ": " 1132 << "Not a NL80211 Message"; 1133 return; 1134 } 1135 const Nl80211Message &wakeup_reason_msg = 1136 *reinterpret_cast<const Nl80211Message *>(&netlink_message); 1137 if (wakeup_reason_msg.command() != SetWakeOnPacketConnMessage::kCommand) { 1138 SLOG(this, 7) << __func__ << ": " 1139 << "Not a NL80211_CMD_SET_WOWLAN message"; 1140 return; 1141 } 1142 uint32_t wiphy_index; 1143 if (!wakeup_reason_msg.const_attributes()->GetU32AttributeValue( 1144 NL80211_ATTR_WIPHY, &wiphy_index)) { 1145 LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY"; 1146 return; 1147 } 1148 if (!wiphy_index_received_) { 1149 SLOG(this, 7) << __func__ << ": " 1150 << "Interface index not yet received"; 1151 return; 1152 } 1153 if (wiphy_index != wiphy_index_) { 1154 SLOG(this, 7) << __func__ << ": " 1155 << "Wakeup reason not meant for this interface"; 1156 return; 1157 } 1158 SLOG(this, 3) << __func__ << ": " 1159 << "Parsing wakeup reason"; 1160 AttributeListConstRefPtr triggers; 1161 if (!wakeup_reason_msg.const_attributes()->ConstGetNestedAttributeList( 1162 NL80211_ATTR_WOWLAN_TRIGGERS, &triggers)) { 1163 SLOG(this, 3) << __func__ << ": " 1164 << "Wakeup reason: Not wake on WiFi related"; 1165 return; 1166 } 1167 bool wake_flag; 1168 if (triggers->GetFlagAttributeValue(NL80211_WOWLAN_TRIG_DISCONNECT, 1169 &wake_flag)) { 1170 SLOG(this, 3) << __func__ << ": " 1171 << "Wakeup reason: Disconnect"; 1172 last_wake_reason_ = kWakeTriggerDisconnect; 1173 return; 1174 } 1175 uint32_t wake_pattern_index; 1176 if (triggers->GetU32AttributeValue(NL80211_WOWLAN_TRIG_PKT_PATTERN, 1177 &wake_pattern_index)) { 1178 SLOG(this, 3) << __func__ << ": " 1179 << "Wakeup reason: Pattern " << wake_pattern_index; 1180 last_wake_reason_ = kWakeTriggerPattern; 1181 return; 1182 } 1183 AttributeListConstRefPtr results_list; 1184 if (triggers->ConstGetNestedAttributeList( 1185 NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS, &results_list)) { 1186 // It is possible that NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS is present 1187 // along with another wake trigger attribute. What this means is that the 1188 // firmware has detected a network, but the platform did not actually wake 1189 // on the detection of that network. In these cases, we will not parse the 1190 // net detect results; we return after parsing and reporting the actual 1191 // wakeup reason above. 1192 SLOG(this, 3) << __func__ << ": " 1193 << "Wakeup reason: SSID"; 1194 last_wake_reason_ = kWakeTriggerSSID; 1195 WakeOnSSIDResults results = ParseWakeOnWakeOnSSIDResults(results_list); 1196 int ssid_num = 0; 1197 for (const auto &result : results) { 1198 SLOG(this, 3) << "SSID " << ssid_num << ": " 1199 << std::string(result.first.begin(), result.first.end()); 1200 for (uint32_t freq : result.second) { 1201 SLOG(this, 7) << "Frequency: " << freq; 1202 } 1203 ++ssid_num; 1204 } 1205 return; 1206 } 1207 SLOG(this, 3) << __func__ << ": " 1208 << "Wakeup reason: Not supported"; 1209#endif // DISABLE_WAKE_ON_WIFI 1210} 1211 1212void WakeOnWiFi::OnBeforeSuspend( 1213 bool is_connected, 1214 const vector<ByteString> &ssid_whitelist, 1215 const ResultCallback &done_callback, 1216 const Closure &renew_dhcp_lease_callback, 1217 const Closure &remove_supplicant_networks_callback, bool have_dhcp_lease, 1218 uint32_t time_to_next_lease_renewal) { 1219 SLOG(this, 1) << __func__ << ": " 1220 << (is_connected ? "connected" : "not connected"); 1221#if defined(DISABLE_WAKE_ON_WIFI) 1222 // Wake on WiFi not supported, so immediately report success. 1223 done_callback.Run(Error(Error::kSuccess)); 1224#else 1225 suspend_actions_done_callback_ = done_callback; 1226 wake_on_ssid_whitelist_ = ssid_whitelist; 1227 dark_resume_history_.Clear(); 1228 if (have_dhcp_lease && is_connected && 1229 time_to_next_lease_renewal < kImmediateDHCPLeaseRenewalThresholdSeconds) { 1230 // Renew DHCP lease immediately if we have one that is expiring soon. 1231 renew_dhcp_lease_callback.Run(); 1232 dispatcher_->PostTask(Bind(&WakeOnWiFi::BeforeSuspendActions, 1233 weak_ptr_factory_.GetWeakPtr(), is_connected, 1234 false, time_to_next_lease_renewal, 1235 remove_supplicant_networks_callback)); 1236 } else { 1237 dispatcher_->PostTask(Bind(&WakeOnWiFi::BeforeSuspendActions, 1238 weak_ptr_factory_.GetWeakPtr(), is_connected, 1239 have_dhcp_lease, time_to_next_lease_renewal, 1240 remove_supplicant_networks_callback)); 1241 } 1242#endif // DISABLE_WAKE_ON_WIFI 1243} 1244 1245void WakeOnWiFi::OnAfterResume() { 1246 SLOG(this, 1) << __func__; 1247#if !defined(DISABLE_WAKE_ON_WIFI) 1248 wake_to_scan_timer_.Stop(); 1249 dhcp_lease_renewal_timer_.Stop(); 1250 if (WakeOnPacketEnabledAndSupported() || WakeOnSSIDEnabledAndSupported()) { 1251 // Unconditionally disable wake on WiFi on resume if these features 1252 // were enabled before the last suspend. 1253 DisableWakeOnWiFi(); 1254 metrics_->NotifySuspendWithWakeOnWiFiEnabledDone(); 1255 } 1256#endif // DISABLE_WAKE_ON_WIFI 1257} 1258 1259void WakeOnWiFi::OnDarkResume( 1260 bool is_connected, 1261 const vector<ByteString> &ssid_whitelist, 1262 const ResultCallback &done_callback, 1263 const Closure &renew_dhcp_lease_callback, 1264 const Closure &initiate_scan_callback, 1265 const Closure &remove_supplicant_networks_callback) { 1266 SLOG(this, 1) << __func__ << ": " 1267 << (is_connected ? "connected" : "not connected") 1268 << ", Wake reason " << last_wake_reason_; 1269#if defined(DISABLE_WAKE_ON_WIFI) 1270 done_callback.Run(Error(Error::kSuccess)); 1271#else 1272 metrics_->NotifyWakeOnWiFiOnDarkResume(last_wake_reason_); 1273 suspend_actions_done_callback_ = done_callback; 1274 wake_on_ssid_whitelist_ = ssid_whitelist; 1275 1276 if (!is_connected) { 1277 // Only record dark resume events where we wake up disconnected, since there 1278 // are valid scenarios where we would dark resume frequently in a connected 1279 // state (e.g. when wake on packet is enabled when there is a brief spike in 1280 // incoming network traffic). We check the connection status on dark resume 1281 // rather than the |last_wake_reason_| in case the WiFi driver does not 1282 // support wakeup reason reporting. 1283 dark_resume_history_.RecordEvent(); 1284 } 1285 if (dark_resume_history_.CountEventsWithinInterval( 1286 kDarkResumeFrequencySamplingPeriodShortMinutes * 60, 1287 EventHistory::kClockTypeBoottime) >= kMaxDarkResumesPerPeriodShort || 1288 dark_resume_history_.CountEventsWithinInterval( 1289 kDarkResumeFrequencySamplingPeriodLongMinutes * 60, 1290 EventHistory::kClockTypeBoottime) >= kMaxDarkResumesPerPeriodLong) { 1291 LOG(ERROR) << __func__ << ": " 1292 << "Too many dark resumes; disabling wake on WiFi"; 1293 // If too many dark resumes have triggered recently, we are probably 1294 // thrashing. Stop this by disabling wake on WiFi on the NIC and 1295 // stopping all RTC timers that might trigger another dark resume. 1296 dhcp_lease_renewal_timer_.Stop(); 1297 wake_to_scan_timer_.Stop(); 1298 DisableWakeOnWiFi(); 1299 dark_resume_history_.Clear(); 1300 metrics_->NotifyWakeOnWiFiThrottled(); 1301 return; 1302 } 1303 1304 switch (last_wake_reason_) { 1305 case kWakeTriggerPattern: { 1306 // Go back to suspend immediately since packet would have been delivered 1307 // to userspace upon waking in dark resume. Do not reset the lease renewal 1308 // timer since we are not getting a new lease. 1309 dispatcher_->PostTask(Bind( 1310 &WakeOnWiFi::BeforeSuspendActions, weak_ptr_factory_.GetWeakPtr(), 1311 is_connected, false, 0, remove_supplicant_networks_callback)); 1312 break; 1313 } 1314 case kWakeTriggerSSID: 1315 case kWakeTriggerDisconnect: { 1316 remove_supplicant_networks_callback.Run(); 1317 metrics_->NotifyDarkResumeInitiateScan(); 1318 initiate_scan_callback.Run(); 1319 break; 1320 } 1321 case kWakeTriggerUnsupported: 1322 default: { 1323 if (is_connected) { 1324 renew_dhcp_lease_callback.Run(); 1325 } else { 1326 remove_supplicant_networks_callback.Run(); 1327 metrics_->NotifyDarkResumeInitiateScan(); 1328 initiate_scan_callback.Run(); 1329 } 1330 } 1331 } 1332 1333 // Only set dark resume to true after checking if we need to disable wake on 1334 // WiFi since calling WakeOnWiFi::DisableWakeOnWiFi directly bypasses 1335 // WakeOnWiFi::BeforeSuspendActions where |in_dark_resume_| is set to false. 1336 in_dark_resume_ = true; 1337 // Assume that we are disconnected if we time out. Consequently, we do not 1338 // need to start a DHCP lease renewal timer. 1339 dark_resume_actions_timeout_callback_.Reset( 1340 Bind(&WakeOnWiFi::BeforeSuspendActions, weak_ptr_factory_.GetWeakPtr(), 1341 false, false, 0, remove_supplicant_networks_callback)); 1342 dispatcher_->PostDelayedTask(dark_resume_actions_timeout_callback_.callback(), 1343 DarkResumeActionsTimeoutMilliseconds); 1344#endif // DISABLE_WAKE_ON_WIFI 1345} 1346 1347void WakeOnWiFi::BeforeSuspendActions( 1348 bool is_connected, 1349 bool start_lease_renewal_timer, 1350 uint32_t time_to_next_lease_renewal, 1351 const Closure &remove_supplicant_networks_callback) { 1352 SLOG(this, 1) << __func__ << ": " 1353 << (is_connected ? "connected" : "not connected"); 1354 // Note: No conditional compilation because all entry points to this functions 1355 // are already conditionally compiled based on DISABLE_WAKE_ON_WIFI. 1356 1357 last_wake_reason_ = kWakeTriggerUnsupported; 1358 // Add relevant triggers to be programmed into the NIC. 1359 wake_on_wifi_triggers_.clear(); 1360 if (!wake_on_packet_connections_.Empty() && 1361 WakeOnPacketEnabledAndSupported() && is_connected) { 1362 SLOG(this, 3) << __func__ << ": " 1363 << "Enabling wake on pattern"; 1364 wake_on_wifi_triggers_.insert(kWakeTriggerPattern); 1365 } 1366 if (WakeOnSSIDEnabledAndSupported()) { 1367 if (is_connected) { 1368 SLOG(this, 3) << __func__ << ": " 1369 << "Enabling wake on disconnect"; 1370 wake_on_wifi_triggers_.insert(kWakeTriggerDisconnect); 1371 wake_on_wifi_triggers_.erase(kWakeTriggerSSID); 1372 wake_to_scan_timer_.Stop(); 1373 if (start_lease_renewal_timer) { 1374 // Timer callback is NO-OP since dark resume logic (the 1375 // kWakeTriggerUnsupported case) will initiate DHCP lease renewal. 1376 dhcp_lease_renewal_timer_.Start( 1377 FROM_HERE, base::TimeDelta::FromSeconds(time_to_next_lease_renewal), 1378 Bind(&WakeOnWiFi::OnTimerWakeDoNothing, base::Unretained(this))); 1379 } 1380 } else { 1381 // Force a disconnect in case supplicant is currently in the process of 1382 // connecting, and remove all networks so scans triggered in dark resume 1383 // are passive. 1384 remove_supplicant_networks_callback.Run(); 1385 dhcp_lease_renewal_timer_.Stop(); 1386 wake_on_wifi_triggers_.erase(kWakeTriggerDisconnect); 1387 if (!wake_on_ssid_whitelist_.empty()) { 1388 SLOG(this, 3) << __func__ << ": " 1389 << "Enabling wake on SSID"; 1390 wake_on_wifi_triggers_.insert(kWakeTriggerSSID); 1391 } 1392 int num_extra_ssids = 1393 wake_on_ssid_whitelist_.size() - wake_on_wifi_max_ssids_; 1394 if (num_extra_ssids > 0 || force_wake_to_scan_timer_) { 1395 SLOG(this, 3) << __func__ << ": " 1396 << "Starting wake to scan timer - " 1397 << (num_extra_ssids > 0 ? "extra SSIDs" : "forced"); 1398 if (num_extra_ssids > 0) { 1399 SLOG(this, 3) << __func__ << ": " << num_extra_ssids 1400 << " extra SSIDs."; 1401 } 1402 // Start wake to scan timer in case the only SSIDs available for 1403 // auto-connect during suspend are the ones that we do not program our 1404 // NIC to wake on. 1405 // Timer callback is NO-OP since dark resume logic (the 1406 // kWakeTriggerUnsupported case) will initiate a passive scan. 1407 wake_to_scan_timer_.Start( 1408 FROM_HERE, 1409 base::TimeDelta::FromSeconds(wake_to_scan_period_seconds_), 1410 Bind(&WakeOnWiFi::OnTimerWakeDoNothing, base::Unretained(this))); 1411 // Trim SSID list to the max size that the NIC supports. 1412 wake_on_ssid_whitelist_.resize(wake_on_wifi_max_ssids_); 1413 } 1414 } 1415 } 1416 1417 // Only call Cancel() here since it deallocates the underlying callback that 1418 // |remove_supplicant_networks_callback| references, which is invoked above. 1419 dark_resume_actions_timeout_callback_.Cancel(); 1420 1421 if (!in_dark_resume_ && wake_on_wifi_triggers_.empty()) { 1422 // No need program NIC on normal resume in this case since wake on WiFi 1423 // would already have been disabled on the last (non-dark) resume. 1424 SLOG(this, 1) << "No need to disable wake on WiFi on NIC in regular " 1425 "suspend"; 1426 RunAndResetSuspendActionsDoneCallback(Error(Error::kSuccess)); 1427 return; 1428 } 1429 1430 in_dark_resume_ = false; 1431 ApplyWakeOnWiFiSettings(); 1432} 1433 1434// static 1435WakeOnWiFi::WakeOnSSIDResults WakeOnWiFi::ParseWakeOnWakeOnSSIDResults( 1436 AttributeListConstRefPtr results_list) { 1437 WakeOnSSIDResults results; 1438 AttributeIdIterator results_iter(*results_list); 1439 if (results_iter.AtEnd()) { 1440 SLOG(WiFi, nullptr, 3) << __func__ << ": " 1441 << "Wake on SSID results not available"; 1442 return results; 1443 } 1444 AttributeListConstRefPtr result; 1445 for (; !results_iter.AtEnd(); results_iter.Advance()) { 1446 if (!results_list->ConstGetNestedAttributeList(results_iter.GetId(), 1447 &result)) { 1448 LOG(ERROR) << __func__ << ": " 1449 << "Could not get result #" << results_iter.GetId() 1450 << " in ssid_results"; 1451 return results; 1452 } 1453 ByteString ssid_bytestring; 1454 if (!result->GetRawAttributeValue(NL80211_ATTR_SSID, &ssid_bytestring)) { 1455 // We assume that the SSID attribute must be present in each result. 1456 LOG(ERROR) << __func__ << ": " 1457 << "No SSID available for result #" << results_iter.GetId(); 1458 continue; 1459 } 1460 vector<uint8_t> ssid( 1461 ssid_bytestring.GetConstData(), 1462 ssid_bytestring.GetConstData() + ssid_bytestring.GetLength()); 1463 vector<uint32_t> freq_list; 1464 AttributeListConstRefPtr frequencies; 1465 uint32_t freq_value; 1466 if (result->ConstGetNestedAttributeList(NL80211_ATTR_SCAN_FREQUENCIES, 1467 &frequencies)) { 1468 AttributeIdIterator freq_iter(*frequencies); 1469 for (; !freq_iter.AtEnd(); freq_iter.Advance()) { 1470 if (frequencies->GetU32AttributeValue(freq_iter.GetId(), &freq_value)) { 1471 freq_list.push_back(freq_value); 1472 } 1473 } 1474 } else { 1475 SLOG(WiFi, nullptr, 3) << __func__ << ": " 1476 << "No frequencies available for result #" 1477 << results_iter.GetId(); 1478 } 1479 results.push_back(SSIDFreqListPair(ssid, freq_list)); 1480 } 1481 return results; 1482} 1483 1484void WakeOnWiFi::OnDHCPLeaseObtained(bool start_lease_renewal_timer, 1485 uint32_t time_to_next_lease_renewal) { 1486 SLOG(this, 3) << __func__; 1487 if (in_dark_resume_) { 1488#if defined(DISABLE_WAKE_ON_WIFI) 1489 SLOG(this, 3) << "Wake on WiFi not supported, so do nothing"; 1490#else 1491 // If we obtain a DHCP lease, we are connected, so the callback to have 1492 // supplicant remove networks will not be invoked in 1493 // WakeOnWiFi::BeforeSuspendActions. 1494 BeforeSuspendActions(true, start_lease_renewal_timer, 1495 time_to_next_lease_renewal, base::Closure()); 1496#endif // DISABLE_WAKE_ON_WIFI 1497 } else { 1498 SLOG(this, 3) << "Not in dark resume, so do nothing"; 1499 } 1500} 1501 1502void WakeOnWiFi::ReportConnectedToServiceAfterWake(bool is_connected) { 1503#if defined(DISABLE_WAKE_ON_WIFI) 1504 metrics_->NotifyConnectedToServiceAfterWake( 1505 is_connected 1506 ? Metrics::kWiFiConnetionStatusAfterWakeOnWiFiDisabledWakeConnected 1507 : Metrics:: 1508 kWiFiConnetionStatusAfterWakeOnWiFiDisabledWakeNotConnected); 1509#else 1510 if (WakeOnSSIDEnabledAndSupported()) { 1511 // Only logged if wake on WiFi is supported and wake on SSID was enabled to 1512 // maintain connectivity while suspended. 1513 metrics_->NotifyConnectedToServiceAfterWake( 1514 is_connected 1515 ? Metrics::kWiFiConnetionStatusAfterWakeOnWiFiEnabledWakeConnected 1516 : Metrics:: 1517 kWiFiConnetionStatusAfterWakeOnWiFiEnabledWakeNotConnected); 1518 } else { 1519 metrics_->NotifyConnectedToServiceAfterWake( 1520 is_connected 1521 ? Metrics::kWiFiConnetionStatusAfterWakeOnWiFiDisabledWakeConnected 1522 : Metrics:: 1523 kWiFiConnetionStatusAfterWakeOnWiFiDisabledWakeNotConnected); 1524 } 1525#endif // DISABLE_WAKE_ON_WIFI 1526} 1527 1528void WakeOnWiFi::OnNoAutoConnectableServicesAfterScan( 1529 const vector<ByteString> &ssid_whitelist, 1530 const Closure &remove_supplicant_networks_callback) { 1531#if !defined(DISABLE_WAKE_ON_WIFI) 1532 SLOG(this, 3) << __func__ << ": " 1533 << (in_dark_resume_ ? "In dark resume" : "Not in dark resume"); 1534 if (in_dark_resume_) { 1535 wake_on_ssid_whitelist_ = ssid_whitelist; 1536 // Assume that if there are no services available for auto-connect, then we 1537 // cannot be connected. Therefore, no need for lease renewal parameters. 1538 BeforeSuspendActions(false, false, 0, remove_supplicant_networks_callback); 1539 } 1540#endif // DISABLE_WAKE_ON_WIFI 1541} 1542 1543void WakeOnWiFi::OnWiphyIndexReceived(uint32_t index) { 1544 wiphy_index_ = index; 1545 wiphy_index_received_ = true; 1546} 1547 1548void WakeOnWiFi::OnScanStarted(bool is_active_scan) { 1549 if (!in_dark_resume_) { 1550 return; 1551 } 1552 if (last_wake_reason_ == kWakeTriggerUnsupported || 1553 last_wake_reason_ == kWakeTriggerPattern) { 1554 // We don't expect active scans to be started when we wake on pattern or 1555 // RTC timers. 1556 if (is_active_scan) { 1557 LOG(ERROR) << "Unexpected active scan launched in dark resume"; 1558 } 1559 metrics_->NotifyScanStartedInDarkResume(is_active_scan); 1560 } 1561} 1562 1563} // namespace shill 1564