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