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