C++程序  |  596行  |  29.79 KB

//
// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#ifndef SHILL_WIFI_WAKE_ON_WIFI_H_
#define SHILL_WIFI_WAKE_ON_WIFI_H_

#include <linux/if_ether.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>

#include <set>
#include <string>
#include <utility>
#include <vector>

#include <base/cancelable_callback.h>
#include <gtest/gtest_prod.h>  // for FRIEND_TEST
#include <base/memory/ref_counted.h>
#include <base/memory/weak_ptr.h>
#include <components/timers/alarm_timer_chromeos.h>

#include "shill/callbacks.h"
#include "shill/ip_address_store.h"
#include "shill/net/event_history.h"
#include "shill/net/ip_address.h"
#include "shill/net/netlink_manager.h"
#include "shill/refptr_types.h"
#include "shill/wifi/wifi.h"

namespace shill {

class ByteString;
class Error;
class EventDispatcher;
class GetWakeOnPacketConnMessage;
class Metrics;
class Nl80211Message;
class PropertyStore;
class SetWakeOnPacketConnMessage;

// |WakeOnWiFi| performs all wake on WiFi related tasks and logic (e.g.
// suspend/dark resume/resume logic, NIC wowlan programming via nl80211), and
// stores the state necessary to perform these actions.
//
// Shill implements two wake on WiFi features:
//   1) Dark connect: this feature allows the CrOS device to maintain WiFi
//      connectivity while suspended, and to wake from suspend in a low-power
//      state (dark resume) to maintain or re-establish WiFi connectivity.
//   2) Packet: this feature allows the CrOS device to wake from suspend upon
//      receiving network packets from any whitelisted hosts.
// Either or both of these features can be enabled/disabled by assigning the
// appropriate value to |wake_on_wifi_features_enabled_|.
//
// Note that wake on WiFi features are different from wake on WiFi triggers. The
// former refers to shill's suspend/resume/dark resume handling logic, whereas
// the latter refers to the NIC's  ability to wake the CPU on certain network
// events (e.g. disconnects). In order for shill's wake on WiFi features to
// work, the platform must be compiled with wake on WiFi support (i.e.
// DISABLE_WAKE_ON_WIFI not set), and its NIC must support the triggers required
// for the features to work (see WakeOnWiFi::WakeOnWiFiPacketEnabledAndSupported
// and WakeOnWiFi::WakeOnWiFiDarkConnectEnabledAndSupported for more details).
//
// The logic shill uses before, during (i.e. during dark resume), and after
// suspend when both wake on WiFi features are enabled are described below:
//
// OnBeforeSuspend
// ================
// This function is run when Manager announces an upcoming system suspend.
//
//         +--------------+
//         |          Yes |   +----------------+
// +-------+--------+     +-->|Renew DHCP Lease|
// |  Connected &   |         +------+---------+
// |holding expiring|                |
// |  DHCP lease?   |                v
// +------+---------+         +--------------------+
//        |               +-> |BeforeSuspendActions|
//        |           No  |   +--------------------+
//        +---------------+
//
// OnDarkResume
// =============
// This function is run when Manager announces that the system has entered
// dark resume and that there is an upcoming system suspend.
//
// +-------------+      +------------+     Unsupported     +----------+
// |  Too many   +----->|Wake reason?+-------------------->|Connected?|
// |dark resumes?|  No  +-+----------+                     +-+-----+--+
// +------+------+        |       |                          |     |
//        | Yes           |       | Disconnect/           No |     | Yes
//        v               |       |    SSID                  |     |
// +-------------------+  |       v                          |     |
// |  Disable Wake on  |  |     +------------+               |     v
// |  WiFi, start wake |  |     |  Initiate  |<--------------+    +--------+
// |  to scan timer &  |  |     |passive scan|                    |Get DHCP|
// |  report readiness |  |     +-+----------+           +------->| Lease  |
// +-------------------+  |       | ScanDone         Yes |        +--+---+-+
//    +-------------------+       v                      |           |   |
//    | Pattern                 +-------------+      +---------+     |   |
//    |                    No   | Any services| Yes  |Connected|     |   |
//    |    +--------------------+available for+----->| to AP?  |     |   |
//    |    |                    | autoconnect?|      +---+-----+     |   |
//    |    |                    +-------------+          |           |   |
//    |    |                                             |No         |   |
//    v    v                                             |           |   |
// +--------------------+       +-------+                |           |   |
// |BeforeSuspendActions|<------+Timeout|<---------------+       No  |   |
// +--------------------+       +-------+<---------------------------+   |
//         ^                                                             |
//         |                   +-------------------+                     |
//         +-------------------+ OnIPConfigUpdated/|             Yes     |
//                             |OnIPv6ConfigUpdated|<--------------------+
//                             +-------------------+
//
// BeforeSuspendActions
// =====================
// This function is run immediately before the system reports suspend readiness
// to Manager. This is the common "exit path" taken by OnBeforeSuspend and
// OnDarkResume before suspending.
//
// +----------------------+
// |Packet feature enabled|   Yes   +------------------------+
// |    and supported?    +-------->|Set Wake on Pattern flag|
// +-----+----------------+         +------------+-----------+
//       |                                       |
//    No |        +------------------------------+
//       |        |
// +-----v--------v-------+        No
// | Dark connect feature +---------------------------------+
// |enabled and supported?|                                 |
// +--+-------------------+                                 |
//    |                                                     |
//    |Yes    Yes   +----------------------------+          |        +---------+
//    |     +-----> |Set Wake on Disconnect flag,+--+    +--v----+   |Report   |
//    |     |       |Start Lease Renewal Timer*  |  |    |Program|   |Suspend  |
//    |     |       +----------------------------+  +--> |  NIC  |   |Readiness|
// +--v-----+-+                                     |    +-+---+-+   +--+------+
// |Connected?|                                     |      |   ^        ^
// +--------+-+                                     |      |   |Failed  |
//          |                                       |      ^   |        |Success
//          |       +----------------------------+  |  +---+---+---+    |
//          +-----> |Set Wake on SSID flag,      +--+  |  Verify   +----+
//            No    |Start Wake To Scan Timer**  |     |Programming|
//                  +----------------------------+     +-----------+
//
// *  if necessary (as indicated by caller of BeforeSuspendActions).
// ** if we need to whitelist more SSIDs than our NIC supports.
//
// OnAfterResume
// ==============
// This is run after Manager announces that the system has fully resumed from
// suspend.
//
// Wake on WiFi is disabled on the NIC if it was enabled before suspend or
// dark resume, and both the wake to scan timer and DHCP lease renewal timers
// are stopped.

class WakeOnWiFi {
 public:
  typedef base::Callback<void(const WiFi::FreqSet&)> InitiateScanCallback;
  // Callback used to report the wake reason for the current dark resume to
  // powerd.
  typedef base::Callback<void(const std::string&)> RecordWakeReasonCallback;

  // Types of triggers that we can program the NIC to wake the WiFi device.
  enum WakeOnWiFiTrigger {
    kWakeTriggerUnsupported = 0,  // Used for reporting, not programming NIC.
    kWakeTriggerPattern = 1,
    kWakeTriggerDisconnect = 2,
    kWakeTriggerSSID = 3
  };

  WakeOnWiFi(NetlinkManager* netlink_manager, EventDispatcher* dispatcher,
             Metrics* metrics,
             RecordWakeReasonCallback record_wake_reason_callback);
  virtual ~WakeOnWiFi();

  // Registers |store| with properties related to wake on WiFi.
  void InitPropertyStore(PropertyStore* store);

  // Starts |metrics_timer_| so that wake on WiFi related metrics are
  // periodically collected.
  void StartMetricsTimer();

  // Enable the NIC to wake on packets received from |ip_endpoint|.
  // Note: The actual programming of the NIC only happens before the system
  // suspends, in |OnBeforeSuspend|.
  void AddWakeOnPacketConnection(const std::string& ip_endpoint, Error* error);
  // Remove rule to wake on packets received from |ip_endpoint| from the NIC.
  // Note: The actual programming of the NIC only happens before the system
  // suspends, in |OnBeforeSuspend|.
  void RemoveWakeOnPacketConnection(const std::string& ip_endpoint,
                                    Error* error);
  // Remove all rules to wake on incoming packets from the NIC.
  // Note: The actual programming of the NIC only happens before the system
  // suspends, in |OnBeforeSuspend|.
  void RemoveAllWakeOnPacketConnections(Error* error);
  // Given a NL80211_CMD_NEW_WIPHY message |nl80211_message|, parses the
  // wake on WiFi capabilities of the NIC and set relevant members of this
  // WakeOnWiFi object to reflect the supported capbilities.
  virtual void ParseWakeOnWiFiCapabilities(
      const Nl80211Message& nl80211_message);
  // Callback invoked when the system reports its wakeup reason.
  //
  // Arguments:
  //  - |netlink_message|: wakeup report message (note: must manually check
  //    this message to make sure it is a wakeup report message).
  //
  // Note: Assumes only one wakeup reason is received. If more than one is
  // received, the only first one parsed will be handled.
  virtual void OnWakeupReasonReceived(const NetlinkMessage& netlink_message);
  // Performs pre-suspend actions relevant to wake on WiFi functionality.
  //
  // Arguments:
  //  - |is_connected|: whether the WiFi device is connected.
  //  - |ssid_whitelist|: list of SSIDs that the NIC will be programmed to wake
  //    the system on if the NIC is programmed to wake on SSID.
  //  - |done_callback|: callback to invoke when suspend  actions have
  //    completed.
  //  - |renew_dhcp_lease_callback|: callback to invoke to initiate DHCP lease
  //    renewal.
  //  - |remove_supplicant_networks_callback|: callback to invoke
  //    to remove all networks from WPA supplicant.
  //  - |have_dhcp_lease|: whether or not there is a DHCP lease to renew.
  //  - |time_to_next_lease_renewal|: number of seconds until next DHCP lease
  //    renewal is due.
  virtual void OnBeforeSuspend(
      bool is_connected,
      const std::vector<ByteString>& ssid_whitelist,
      const ResultCallback& done_callback,
      const base::Closure& renew_dhcp_lease_callback,
      const base::Closure& remove_supplicant_networks_callback,
      bool have_dhcp_lease,
      uint32_t time_to_next_lease_renewal);
  // Performs post-resume actions relevant to wake on wireless functionality.
  virtual void OnAfterResume();
  // Performs and post actions to be performed in dark resume.
  //
  // Arguments:
  //  - |is_connected|: whether the WiFi device is connected.
  //  - |ssid_whitelist|: list of SSIDs that the NIC will be programmed to wake
  //    the system on if the NIC is programmed to wake on SSID.
  //  - |done_callback|: callback to invoke when dark resume actions have
  //    completed.
  //  - |renew_dhcp_lease_callback|: callback to invoke to initiate DHCP lease
  //    renewal.
  //  - |initate_scan_callback|: callback to invoke to initiate a scan.
  //  - |remove_supplicant_networks_callback|: callback to invoke
  //    to remove all networks from WPA supplicant.
  virtual void OnDarkResume(
      bool is_connected,
      const std::vector<ByteString>& ssid_whitelist,
      const ResultCallback& done_callback,
      const base::Closure& renew_dhcp_lease_callback,
      const InitiateScanCallback& initiate_scan_callback,
      const base::Closure& remove_supplicant_networks_callback);
  // Called when we the current service is connected, and we have IP
  // reachability. Calls WakeOnWiFi::BeforeSuspendActions if we are in dark
  // resume to end the current dark resume. Otherwise, does nothing.
  virtual void OnConnectedAndReachable(bool start_lease_renewal_timer,
                                       uint32_t time_to_next_lease_renewal);
  // Callback invoked to report whether this WiFi device is connected to
  // a service after waking from suspend.
  virtual void ReportConnectedToServiceAfterWake(bool is_connected);
  // Called in WiFi::ScanDoneTask when there are no WiFi services available
  // for auto-connect after a scan. |initiate_scan_callback| is used for dark
  // resume scan retries.
  virtual void OnNoAutoConnectableServicesAfterScan(
      const std::vector<ByteString>& ssid_whitelist,
      const base::Closure& remove_supplicant_networks_callback,
      const InitiateScanCallback& initiate_scan_callback);
  // Called by WiFi when it is notified by the kernel that a scan has started.
  // If |is_active_scan| is true, the scan is an active scan. Otherwise, the
  // scan is a passive scan.
  virtual void OnScanStarted(bool is_active_scan);

  bool in_dark_resume() { return in_dark_resume_; }

  virtual void OnWiphyIndexReceived(uint32_t index);

 private:
  friend class WakeOnWiFiTest;  // access to several members for tests
  friend class WiFiObjectTest;  // netlink_manager_
  // kWakeOnWiFiNotSupported.
  FRIEND_TEST(WakeOnWiFiTestWithMockDispatcher,
              WakeOnWiFiDisabled_SetWakeOnWiFiFeaturesEnabled);
  FRIEND_TEST(WakeOnWiFiTestWithMockDispatcher,
              WakeOnWiFiDisabled_AddWakeOnPacketConnection_ReturnsError);
  FRIEND_TEST(WakeOnWiFiTestWithMockDispatcher,
              WakeOnWiFiDisabled_RemoveWakeOnPacketConnection_ReturnsError);
  FRIEND_TEST(WakeOnWiFiTestWithMockDispatcher,
              WakeOnWiFiDisabled_RemoveAllWakeOnPacketConnections_ReturnsError);
  // kMaxSetWakeOnPacketRetries.
  FRIEND_TEST(WakeOnWiFiTestWithMockDispatcher,
              RetrySetWakeOnPacketConnections_LessThanMaxRetries);
  FRIEND_TEST(WakeOnWiFiTestWithMockDispatcher,
              RetrySetWakeOnPacketConnections_MaxAttemptsWithCallbackSet);
  FRIEND_TEST(WakeOnWiFiTestWithMockDispatcher,
              RetrySetWakeOnPacketConnections_MaxAttemptsCallbackUnset);
  // kDarkResumeActionsTimeoutMilliseconds
  FRIEND_TEST(WakeOnWiFiTestWithMockDispatcher,
              OnBeforeSuspend_DHCPLeaseRenewal);
  // Dark resume wake reason strings (e.g. kWakeReasonStringDisconnect)
  FRIEND_TEST(WakeOnWiFiTestWithMockDispatcher,
              OnWakeupReasonReceived_Disconnect);
  FRIEND_TEST(WakeOnWiFiTestWithMockDispatcher, OnWakeupReasonReceived_SSID);
  FRIEND_TEST(WakeOnWiFiTestWithMockDispatcher, OnWakeupReasonReceived_Pattern);
  // kMaxDarkResumesPerPeriodShort
  FRIEND_TEST(WakeOnWiFiTestWithDispatcher, OnBeforeSuspend_ClearsEventHistory);
  // kDarkResumeFrequencySamplingPeriodShortMinutes,
  // kMaxDarkResumesPerPeriodShort
  FRIEND_TEST(WakeOnWiFiTestWithDispatcher,
              OnDarkResume_NotConnected_MaxDarkResumes_ShortPeriod);
  // kDarkResumeFrequencySamplingPeriodLongMinutes,
  // kMaxDarkResumesPerPeriodLong,
  // kDarkResumeFrequencySamplingPeriodShortMinutes,
  // kMaxDarkResumesPerPeriodShort
  FRIEND_TEST(WakeOnWiFiTestWithDispatcher,
              OnDarkResume_NotConnected_MaxDarkResumes_LongPeriod);
  // kMaxFreqsForDarkResumeScanRetries, kMaxDarkResumeScanRetries
  FRIEND_TEST(WakeOnWiFiTestWithDispatcher, InitiateScanInDarkResume);

  static const char kWakeOnIPAddressPatternsNotSupported[];
  static const char kWakeOnWiFiNotSupported[];
  static const int kVerifyWakeOnWiFiSettingsDelayMilliseconds;
  static const int kMaxSetWakeOnPacketRetries;
  static const int kMetricsReportingFrequencySeconds;
  static const uint32_t kDefaultWakeToScanPeriodSeconds;
  static const uint32_t kDefaultNetDetectScanPeriodSeconds;
  static const uint32_t kImmediateDHCPLeaseRenewalThresholdSeconds;
  static const int kDarkResumeFrequencySamplingPeriodShortMinutes;
  static const int kDarkResumeFrequencySamplingPeriodLongMinutes;
  static const int kMaxDarkResumesPerPeriodShort;
  static const int kMaxDarkResumesPerPeriodLong;
  static int64_t DarkResumeActionsTimeoutMilliseconds;  // non-const for testing
  static const int kMaxFreqsForDarkResumeScanRetries;
  static const int kMaxDarkResumeScanRetries;
  // Dark resume wake reason names. These will be sent to powerd via
  // RecordDarkResumeWakeReason, to tell it the reason the system woke in the
  // current dark resume.
  static const char kWakeReasonStringPattern[];
  static const char kWakeReasonStringDisconnect[];
  static const char kWakeReasonStringSSID[];

  std::string GetWakeOnWiFiFeaturesEnabled(Error* error);
  bool SetWakeOnWiFiFeaturesEnabled(const std::string& enabled, Error* error);
  // Helper function to run and reset |suspend_actions_done_callback_|.
  void RunAndResetSuspendActionsDoneCallback(const Error& error);
  // Used for comparison of ByteString pairs in a set.
  static bool ByteStringPairIsLessThan(
      const std::pair<ByteString, ByteString>& lhs,
      const std::pair<ByteString, ByteString>& rhs);
  // Creates a mask which specifies which bytes in pattern of length
  // |pattern_len| to match against. Bits |offset| to |pattern_len| - 1 are set,
  // which bits 0 to bits 0 to |offset| - 1 are unset. This mask is saved in
  // |mask|.
  static void SetMask(ByteString* mask, uint32_t pattern_len, uint32_t offset);
  // Creates a pattern and mask for a NL80211 message that programs the NIC to
  // wake on packets originating from IP address |ip_addr|. The pattern and mask
  // are saved in |pattern| and |mask| respectively. Returns true iff the
  // pattern and mask are successfully created and written to |pattern| and
  // |mask| respectively.
  static bool CreateIPAddressPatternAndMask(const IPAddress& ip_addr,
                                            ByteString* pattern,
                                            ByteString* mask);
  static void CreateIPV4PatternAndMask(const IPAddress& ip_addr,
                                       ByteString* pattern, ByteString* mask);
  static void CreateIPV6PatternAndMask(const IPAddress& ip_addr,
                                       ByteString* pattern, ByteString* mask);
  // Creates and sets an attribute in a NL80211 message |msg| which indicates
  // the index of the wiphy interface to program. Returns true iff |msg| is
  // successfully configured.
  static bool ConfigureWiphyIndex(Nl80211Message* msg, int32_t index);
  // Creates and sets attributes in an SetWakeOnPacketConnMessage |msg| so that
  // the message will disable wake-on-packet functionality of the NIC with wiphy
  // index |wiphy_index|. Returns true iff |msg| is successfully configured.
  // NOTE: Assumes that |msg| has not been altered since construction.
  static bool ConfigureDisableWakeOnWiFiMessage(SetWakeOnPacketConnMessage* msg,
                                                uint32_t wiphy_index,
                                                Error* error);
  // Creates and sets attributes in a SetWakeOnPacketConnMessage |msg|
  // so that the message will program the NIC with wiphy index |wiphy_index|
  // with wake on wireless triggers in |trigs|. If |trigs| contains the
  // kWakeTriggerPattern trigger, the message is configured to program the NIC
  // to wake on packets from the IP addresses in |addrs|. If |trigs| contains
  // the kSSID trigger, the message is configured to program the NIC to wake on
  // the SSIDs in |ssid_whitelist|.
  // Returns true iff |msg| is successfully configured.
  // NOTE: Assumes that |msg| has not been altered since construction.
  static bool ConfigureSetWakeOnWiFiSettingsMessage(
      SetWakeOnPacketConnMessage* msg, const std::set<WakeOnWiFiTrigger>& trigs,
      const IPAddressStore& addrs, uint32_t wiphy_index,
      uint32_t net_detect_scan_period_seconds,
      const std::vector<ByteString>& ssid_whitelist,
      Error* error);
  // Helper function to ConfigureSetWakeOnWiFiSettingsMessage that creates a
  // single nested attribute inside the attribute list referenced by |patterns|
  // representing a wake-on-packet pattern matching rule with index |patnum|.
  // Returns true iff the attribute is successfully created and set.
  // NOTE: |patterns| is assumed to reference the nested attribute list
  // NL80211_WOWLAN_TRIG_PKT_PATTERN.
  // NOTE: |patnum| should be unique across multiple calls to this function to
  // prevent the formation of a erroneous nl80211 message or the overwriting of
  // pattern matching rules.
  static bool CreateSinglePattern(const IPAddress& ip_addr,
                                  AttributeListRefPtr patterns, uint8_t patnum,
                                  Error* error);
  // Creates and sets attributes in an GetWakeOnPacketConnMessage msg| so that
  // the message will request for wake-on-packet settings information from the
  // NIC with wiphy index |wiphy_index|. Returns true iff |msg| is successfully
  // configured.
  // NOTE: Assumes that |msg| has not been altered since construction.
  static bool ConfigureGetWakeOnWiFiSettingsMessage(
      GetWakeOnPacketConnMessage* msg, uint32_t wiphy_index, Error* error);
  // Given a NL80211_CMD_GET_WOWLAN response or NL80211_CMD_SET_WOWLAN request
  // |msg|, returns true iff the wake-on-wifi trigger settings in |msg| match
  // those in |trigs|. Performs the following checks for the following triggers:
  // - kWakeTriggerDisconnect: checks that the wake on disconnect flag is
  //   present and set.
  // - kIPAddress: checks that source IP addresses in |msg| match those reported
  //   in |addrs|.
  // - kSSID: checks that the SSIDs in |ssid_whitelist| and the scan interval
  //   |net_detect_scan_period_seconds| match those reported in |msg|.
  // Note: finding a trigger is in |msg| that is not expected based on the flags
  // in |trig| also counts as a mismatch.
  static bool WakeOnWiFiSettingsMatch(
      const Nl80211Message& msg, const std::set<WakeOnWiFiTrigger>& trigs,
      const IPAddressStore& addrs, uint32_t net_detect_scan_period_seconds,
      const std::vector<ByteString>& ssid_whitelist);
  // Handler for NL80211 message error responses from NIC wake on WiFi setting
  // programming attempts.
  void OnWakeOnWiFiSettingsErrorResponse(
      NetlinkManager::AuxilliaryMessageType type,
      const NetlinkMessage* raw_message);
  // Message handler for NL80211_CMD_SET_WOWLAN responses.
  static void OnSetWakeOnPacketConnectionResponse(
      const Nl80211Message& nl80211_message);
  // Request wake on WiFi settings for this WiFi device.
  void RequestWakeOnPacketSettings();
  // Verify that the wake on WiFi settings programmed into the NIC match
  // those recorded locally for this device in |wake_on_packet_connections_|,
  // |wake_on_wifi_triggers_|, and |wake_on_ssid_whitelist_|.
  void VerifyWakeOnWiFiSettings(const Nl80211Message& nl80211_message);
  // Sends an NL80211 message to program the NIC with wake on WiFi settings
  // configured in |wake_on_packet_connections_|, |wake_on_ssid_whitelist_|, and
  // |wake_on_wifi_triggers_|. If |wake_on_wifi_triggers_| is empty, calls
  // WakeOnWiFi::DisableWakeOnWiFi.
  void ApplyWakeOnWiFiSettings();
  // Helper function called by |ApplyWakeOnWiFiSettings| that sends an NL80211
  // message to program the NIC to disable wake on WiFi.
  void DisableWakeOnWiFi();
  // Calls |ApplyWakeOnWiFiSettings| and counts this call as
  // a retry. If |kMaxSetWakeOnPacketRetries| retries have already been
  // performed, resets counter and returns.
  void RetrySetWakeOnPacketConnections();
  // Utility functions to check which wake on WiFi features are currently
  // enabled based on the descriptor |wake_on_wifi_features_enabled_| and
  // are supported by the NIC.
  bool WakeOnWiFiPacketEnabledAndSupported();
  bool WakeOnWiFiDarkConnectEnabledAndSupported();
  // Called by metrics_timer_ to reports metrics.
  void ReportMetrics();
  // Actions executed before normal suspend and dark resume suspend.
  //
  // Arguments:
  //  - |is_connected|: whether the WiFi device is connected.
  //  - |start_lease_renewal_timer|: whether or not to start the DHCP lease
  //    renewal timer.
  //  - |time_to_next_lease_renewal|: number of seconds until next DHCP lease
  //    renewal is due.
  //  - |remove_supplicant_networks_callback|: callback to invoke
  //    to remove all networks from WPA supplicant.
  void BeforeSuspendActions(
      bool is_connected,
      bool start_lease_renewal_timer,
      uint32_t time_to_next_lease_renewal,
      const base::Closure& remove_supplicant_networks_callback);

  // Needed for |dhcp_lease_renewal_timer_| and |wake_to_scan_timer_| since
  // passing a empty base::Closure() causes a run-time DCHECK error when
  // SimpleAlarmTimer::Start or SimpleAlarmTimer::Reset are called.
  void OnTimerWakeDoNothing() {}

  // Parses an attribute list containing the SSID matches that caused the
  // system wake, along with the corresponding channels that these SSIDs were
  // detected in. Returns a set of unique frequencies that the reported
  // SSID matches occured in.
  //
  // Arguments:
  //  - |results_list|: Nested attribute list containing an array of nested
  //    attributes which contain the NL80211_ATTR_SSID or
  //    NL80211_ATTR_SCAN_FREQUENCIES attributes. This attribute list is assumed
  //    to have been extracted from a NL80211_CMD_SET_WOWLAN response message
  //    using the NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS id.
  static WiFi::FreqSet ParseWakeOnSSIDResults(
      AttributeListConstRefPtr results_list);

  // Sets the |dark_resume_scan_retries_left_| counter if necessary, then runs
  // |initiate_scan_callback| with |freqs|.
  void InitiateScanInDarkResume(
      const InitiateScanCallback& initiate_scan_callback,
      const WiFi::FreqSet& freqs);

  // Pointers to objects owned by the WiFi object that created this object.
  EventDispatcher* dispatcher_;
  NetlinkManager* netlink_manager_;
  Metrics* metrics_;
  // Executes after the NIC's wake-on-packet settings are configured via
  // NL80211 messages to verify that the new configuration has taken effect.
  // Calls RequestWakeOnPacketSettings.
  base::CancelableClosure verify_wake_on_packet_settings_callback_;
  // Callback to be invoked after all suspend actions finish executing both
  // before regular suspend and before suspend in dark resume.
  ResultCallback suspend_actions_done_callback_;
  // Callback to report wake on WiFi related metrics.
  base::CancelableClosure report_metrics_callback_;
  // Number of retry attempts to program the NIC's wake-on-packet settings.
  int num_set_wake_on_packet_retries_;
  // Keeps track of triggers that the NIC will be programmed to wake from
  // while suspended.
  std::set<WakeOnWiFi::WakeOnWiFiTrigger> wake_on_wifi_triggers_;
  // Keeps track of what wake on wifi triggers this WiFi device supports.
  std::set<WakeOnWiFi::WakeOnWiFiTrigger> wake_on_wifi_triggers_supported_;
  // Max number of patterns this WiFi device can be programmed to wake on at one
  // time.
  size_t wake_on_wifi_max_patterns_;
  // Max number of SSIDs this WiFi device can be programmed to wake on at one
  // time.
  uint32_t wake_on_wifi_max_ssids_;
  // Keeps track of IP addresses whose packets this device will wake upon
  // receiving while the device is suspended. Only used if the NIC is programmed
  // to wake on IP address patterns.
  IPAddressStore wake_on_packet_connections_;
  // Keeps track of SSIDs that this device will wake on the appearance of while
  // the device is suspended. Only used if the NIC is programmed to wake on
  // SSIDs.
  std::vector<ByteString> wake_on_ssid_whitelist_;
  uint32_t wiphy_index_;
  bool wiphy_index_received_;
  // Describes the wake on WiFi features that are currently enabled.
  std::string wake_on_wifi_features_enabled_;
  // Timer that wakes the system to renew DHCP leases.
  timers::SimpleAlarmTimer dhcp_lease_renewal_timer_;
  // Timer that wakes the system to scan for networks.
  timers::SimpleAlarmTimer wake_to_scan_timer_;
  // Executes when the dark resume actions timer expires. Calls
  // ScanTimerHandler.
  base::CancelableClosure dark_resume_actions_timeout_callback_;
  // Whether shill is currently in dark resume.
  bool in_dark_resume_;
  // Period (in seconds) between instances where the system wakes from suspend
  // to scan for networks in dark resume.
  uint32_t wake_to_scan_period_seconds_;
  // Period (in seconds) between instances where the NIC performs Net Detect
  // scans while the system is suspended.
  uint32_t net_detect_scan_period_seconds_;
  // Timestamps of dark resume wakes that took place during the current
  // or most recent suspend.
  EventHistory dark_resume_history_;
  // Last wake reason reported by the kernel.
  WakeOnWiFiTrigger last_wake_reason_;
  // Whether or not to always start |wake_to_scan_timer_| before suspend.
  bool force_wake_to_scan_timer_;
  // Frequencies that the last wake on SSID matches reported by the kernel
  // occurred in.
  WiFi::FreqSet last_ssid_match_freqs_;
  // How many more times to retry the last dark resume scan that shill launched
  // if no auto-connectable services were found.
  int dark_resume_scan_retries_left_;

  // Callback invoked to report the wake reason for the current dark resume to
  // powerd.
  RecordWakeReasonCallback record_wake_reason_callback_;

  base::WeakPtrFactory<WakeOnWiFi> weak_ptr_factory_;

  DISALLOW_COPY_AND_ASSIGN(WakeOnWiFi);
};

}  // namespace shill

#endif  // SHILL_WIFI_WAKE_ON_WIFI_H_