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