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