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