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