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