shill: add get wake-on-packet settings functionality
Add functionality to send nl80211 requests to the kernel for
the NIC's wake-on-packet settings and to parse response
messages from the kernel. Change add and remove wake-on-packet
function logic to make use of this new functionality to
asychronously verify the programming of the NIC.
BUG=chromium:399137
TEST='P2_TEST_FILTER="shill::*" FEATURES="test" emerge-squawks
platform2' succeeds; manual testing on squawks
CQ-DEPEND=CL:214100
Change-Id: I2133af7818f5655d62c371d928f0b62eca99e196
Reviewed-on: https://chromium-review.googlesource.com/214153
Tested-by: Samuel Tan <samueltan@chromium.org>
Reviewed-by: Paul Stewart <pstew@chromium.org>
Commit-Queue: Samuel Tan <samueltan@chromium.org>
diff --git a/device.h b/device.h
index 8ca41b4..ca7e9eb 100644
--- a/device.h
+++ b/device.h
@@ -279,7 +279,7 @@
virtual void RemoveAllWakeOnPacketConnections(Error *error);
// Get all registered wake-on-packet connections
- const IPAddressStore &GetAllWakeOnPacketConnections() const {
+ const IPAddressStore &GetWakeOnPacketConnections() const {
return wake_on_packet_connections_;
}
diff --git a/manager.cc b/manager.cc
index 0641065..2445ff9 100644
--- a/manager.cc
+++ b/manager.cc
@@ -2127,7 +2127,7 @@
return; // No transfer required
}
new_device->AddWakeOnPacketConnections(
- old_device->GetAllWakeOnPacketConnections());
+ old_device->GetWakeOnPacketConnections());
Error e;
old_device->RemoveAllWakeOnPacketConnections(&e);
if (e.IsFailure()) {
diff --git a/nl80211_message.cc b/nl80211_message.cc
index 077f666..b2d0fe0 100644
--- a/nl80211_message.cc
+++ b/nl80211_message.cc
@@ -488,6 +488,10 @@
const char SetWakeOnPacketConnMessage::kCommandString[] =
"NL80211_CMD_SET_WOWLAN";
+const uint8_t GetWakeOnPacketConnMessage::kCommand = NL80211_CMD_GET_WOWLAN;
+const char GetWakeOnPacketConnMessage::kCommandString[] =
+ "NL80211_CMD_GET_WOWLAN";
+
const uint8_t GetWiphyMessage::kCommand = NL80211_CMD_GET_WIPHY;
const char GetWiphyMessage::kCommandString[] = "NL80211_CMD_GET_WIPHY";
diff --git a/nl80211_message.h b/nl80211_message.h
index e5f952e..baf51c3 100644
--- a/nl80211_message.h
+++ b/nl80211_message.h
@@ -237,6 +237,17 @@
DISALLOW_COPY_AND_ASSIGN(SetWakeOnPacketConnMessage);
};
+class GetWakeOnPacketConnMessage : public Nl80211Message {
+ public:
+ static const uint8_t kCommand;
+ static const char kCommandString[];
+
+ GetWakeOnPacketConnMessage() : Nl80211Message(kCommand, kCommandString) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GetWakeOnPacketConnMessage);
+};
+
class GetWiphyMessage : public Nl80211Message {
public:
static const uint8_t kCommand;
diff --git a/wake_on_wifi.cc b/wake_on_wifi.cc
index ca20587..ec876ef 100644
--- a/wake_on_wifi.cc
+++ b/wake_on_wifi.cc
@@ -6,23 +6,30 @@
#include <stdio.h>
-#include <linux/if_ether.h>
-#include <netinet/ip.h>
-#include <netinet/ip6.h>
-
+#include <set>
+#include <utility>
#include <vector>
#include "shill/byte_string.h"
#include "shill/error.h"
#include "shill/ip_address.h"
+#include "shill/ip_address_store.h"
#include "shill/nl80211_message.h"
+using std::pair;
+using std::set;
using std::vector;
namespace shill {
namespace WakeOnWifi {
+bool ByteStringPairIsLessThan(const std::pair<ByteString, ByteString> &lhs,
+ const std::pair<ByteString, ByteString> &rhs) {
+ // Treat the first value of the pair as the key.
+ return ByteString::IsLessThan(lhs.first, rhs.first);
+}
+
void SetMask(ByteString *mask, uint32_t pattern_len, uint32_t offset) {
// Round up number of bytes required for the mask.
int result_mask_len = (pattern_len + 8 - 1) / 8;
@@ -58,7 +65,6 @@
struct ethhdr eth_hdr;
struct iphdr ipv4_hdr;
} __attribute__((__packed__)) pattern_bytes;
-
memset(&pattern_bytes, 0, sizeof(pattern_bytes));
CHECK_EQ(sizeof(pattern_bytes.ipv4_hdr.saddr), ip_addr.GetLength());
memcpy(&pattern_bytes.ipv4_hdr.saddr, ip_addr.GetConstData(),
@@ -79,7 +85,6 @@
struct ethhdr eth_hdr;
struct ip6_hdr ipv6_hdr;
} __attribute__((__packed__)) pattern_bytes;
-
memset(&pattern_bytes, 0, sizeof(pattern_bytes));
CHECK_EQ(sizeof(pattern_bytes.ipv6_hdr.ip6_src), ip_addr.GetLength());
memcpy(&pattern_bytes.ipv6_hdr.ip6_src, ip_addr.GetConstData(),
@@ -94,7 +99,7 @@
WakeOnWifi::SetMask(mask, pattern_len, src_ip_offset);
}
-bool ConfigureWiphyIndex(SetWakeOnPacketConnMessage *msg, int32_t index) {
+bool ConfigureWiphyIndex(Nl80211Message *msg, int32_t index) {
if (!msg->attributes()->CreateU32Attribute(NL80211_ATTR_WIPHY,
"WIPHY index")) {
return false;
@@ -108,7 +113,7 @@
bool ConfigureRemoveAllWakeOnPacketMsg(SetWakeOnPacketConnMessage *msg,
uint32_t wiphy_index, Error *error) {
if (!WakeOnWifi::ConfigureWiphyIndex(msg, wiphy_index)) {
- error->PopulateAndLog(error, Error::kOperationFailed,
+ Error::PopulateAndLog(error, Error::kOperationFailed,
"Failed to configure Wiphy index.");
return false;
}
@@ -116,27 +121,24 @@
}
bool ConfigureAddWakeOnPacketMsg(SetWakeOnPacketConnMessage *msg,
- const IPAddress &ip_addr, uint32_t wiphy_index,
- Error *error) {
- ByteString pattern;
- ByteString mask;
- WakeOnWifi::CreateIPAddressPatternAndMask(ip_addr, &pattern, &mask);
+ const IPAddressStore &addrs,
+ uint32_t wiphy_index, Error *error) {
if (!WakeOnWifi::ConfigureWiphyIndex(msg, wiphy_index)) {
- error->PopulateAndLog(error, Error::kOperationFailed,
+ Error::PopulateAndLog(error, Error::kOperationFailed,
"Failed to configure Wiphy index.");
return false;
}
- if (!(*msg).attributes()->CreateNestedAttribute(NL80211_ATTR_WOWLAN_TRIGGERS,
+ if (!msg->attributes()->CreateNestedAttribute(NL80211_ATTR_WOWLAN_TRIGGERS,
"WoWLAN Triggers")) {
- error->PopulateAndLog(error, Error::kOperationFailed,
+ Error::PopulateAndLog(error, Error::kOperationFailed,
"Could not create nested attribute "
"NL80211_ATTR_WOWLAN_TRIGGERS for "
"SetWakeOnPacketConnMessage.");
return false;
}
- if (!(*msg).attributes()->SetNestedAttributeHasAValue(
+ if (!msg->attributes()->SetNestedAttributeHasAValue(
NL80211_ATTR_WOWLAN_TRIGGERS)) {
- error->PopulateAndLog(error, Error::kOperationFailed,
+ Error::PopulateAndLog(error, Error::kOperationFailed,
"Could not set nested attribute "
"NL80211_ATTR_WOWLAN_TRIGGERS for "
"SetWakeOnPacketConnMessage.");
@@ -144,9 +146,9 @@
}
AttributeListRefPtr triggers;
- if (!(*msg).attributes()->GetNestedAttributeList(NL80211_ATTR_WOWLAN_TRIGGERS,
+ if (!msg->attributes()->GetNestedAttributeList(NL80211_ATTR_WOWLAN_TRIGGERS,
&triggers)) {
- error->PopulateAndLog(error, Error::kOperationFailed,
+ Error::PopulateAndLog(error, Error::kOperationFailed,
"Could not get nested attribute list "
"NL80211_ATTR_WOWLAN_TRIGGERS for "
"SetWakeOnPacketConnMessage.");
@@ -154,14 +156,14 @@
}
if (!triggers->CreateNestedAttribute(NL80211_WOWLAN_TRIG_PKT_PATTERN,
"Pattern trigger")) {
- error->PopulateAndLog(error, Error::kOperationFailed,
+ Error::PopulateAndLog(error, Error::kOperationFailed,
"Could not create nested attribute "
"NL80211_WOWLAN_TRIG_PKT_PATTERN for "
"SetWakeOnPacketConnMessage.");
return false;
}
if (!triggers->SetNestedAttributeHasAValue(NL80211_WOWLAN_TRIG_PKT_PATTERN)) {
- error->PopulateAndLog(error, Error::kOperationFailed,
+ Error::PopulateAndLog(error, Error::kOperationFailed,
"Could not set nested attribute "
"NL80211_WOWLAN_TRIG_PKT_PATTERN for "
"SetWakeOnPacketConnMessage.");
@@ -171,25 +173,36 @@
AttributeListRefPtr patterns;
if (!triggers->GetNestedAttributeList(NL80211_WOWLAN_TRIG_PKT_PATTERN,
&patterns)) {
- error->PopulateAndLog(error, Error::kOperationFailed,
+ Error::PopulateAndLog(error, Error::kOperationFailed,
"Could not get nested attribute list "
"NL80211_WOWLAN_TRIG_PKT_PATTERN for "
"SetWakeOnPacketConnMessage.");
return false;
}
- // This additional level of attribute nesting on an attribute indexed by
- // 1 is necessary to get the packet accepted. It is unclear what this
- // attribute is (wowlan.c in the iw source code references it as "patnum")
- // TODO(samueltan): identify this nested attribute
+
uint8_t patnum = 1;
+ for (const IPAddress &addr : addrs.GetIPAddresses()) {
+ if (!CreateSinglePattern(addr, patterns, patnum++, error)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool CreateSinglePattern(const IPAddress &ip_addr, AttributeListRefPtr patterns,
+ uint8_t patnum, Error *error) {
+ ByteString pattern;
+ ByteString mask;
+ WakeOnWifi::CreateIPAddressPatternAndMask(ip_addr, &pattern, &mask);
if (!patterns->CreateNestedAttribute(patnum, "Pattern info")) {
- error->PopulateAndLog(error, Error::kOperationFailed,
+ Error::PopulateAndLog(error, Error::kOperationFailed,
"Could not create nested attribute "
"patnum for SetWakeOnPacketConnMessage.");
return false;
}
if (!patterns->SetNestedAttributeHasAValue(patnum)) {
- error->PopulateAndLog(error, Error::kOperationFailed,
+ Error::PopulateAndLog(error, Error::kOperationFailed,
"Could not set nested attribute "
"patnum for SetWakeOnPacketConnMessage.");
return false;
@@ -197,48 +210,48 @@
AttributeListRefPtr pattern_info;
if (!patterns->GetNestedAttributeList(patnum, &pattern_info)) {
- error->PopulateAndLog(error, Error::kOperationFailed,
+ Error::PopulateAndLog(error, Error::kOperationFailed,
"Could not get nested attribute list "
"patnum for SetWakeOnPacketConnMessage.");
return false;
}
- // Add mask
+ // Add mask.
if (!pattern_info->CreateRawAttribute(NL80211_PKTPAT_MASK, "Mask")) {
- error->PopulateAndLog(error, Error::kOperationFailed,
+ Error::PopulateAndLog(error, Error::kOperationFailed,
"Could not add attribute NL80211_PKTPAT_MASK to "
"pattern_info.");
return false;
}
if (!pattern_info->SetRawAttributeValue(NL80211_PKTPAT_MASK, mask)) {
- error->PopulateAndLog(error, Error::kOperationFailed,
+ Error::PopulateAndLog(error, Error::kOperationFailed,
"Could not set attribute NL80211_PKTPAT_MASK in "
"pattern_info.");
return false;
}
- // Add pattern
+ // Add pattern.
if (!pattern_info->CreateRawAttribute(NL80211_PKTPAT_PATTERN, "Pattern")) {
- error->PopulateAndLog(error, Error::kOperationFailed,
+ Error::PopulateAndLog(error, Error::kOperationFailed,
"Could not add attribute NL80211_PKTPAT_PATTERN to "
"pattern_info.");
return false;
}
if (!pattern_info->SetRawAttributeValue(NL80211_PKTPAT_PATTERN, pattern)) {
- error->PopulateAndLog(error, Error::kOperationFailed,
+ Error::PopulateAndLog(error, Error::kOperationFailed,
"Could not set attribute NL80211_PKTPAT_PATTERN in "
"pattern_info.");
return false;
}
- // Add offset
+ // Add offset.
if (!pattern_info->CreateU32Attribute(NL80211_PKTPAT_OFFSET, "Offset")) {
- error->PopulateAndLog(error, Error::kOperationFailed,
+ Error::PopulateAndLog(error, Error::kOperationFailed,
"Could not add attribute NL80211_PKTPAT_OFFSET to "
"pattern_info.");
return false;
}
if (!pattern_info->SetU32AttributeValue(NL80211_PKTPAT_OFFSET, 0)) {
- error->PopulateAndLog(error, Error::kOperationFailed,
+ Error::PopulateAndLog(error, Error::kOperationFailed,
"Could not set attribute NL80211_PKTPAT_OFFSET in "
"pattern_info.");
return false;
@@ -246,6 +259,90 @@
return true;
}
+bool ConfigureGetWakeOnPacketMsg(GetWakeOnPacketConnMessage *msg,
+ uint32_t wiphy_index, Error *error) {
+ if (!WakeOnWifi::ConfigureWiphyIndex(msg, wiphy_index)) {
+ Error::PopulateAndLog(error, Error::kOperationFailed,
+ "Failed to configure Wiphy index.");
+ return false;
+ }
+ return true;
+}
+
+bool WakeOnPacketSettingsMatch(const Nl80211Message &msg,
+ const IPAddressStore &addrs) {
+ if (msg.command() != NL80211_CMD_GET_WOWLAN &&
+ msg.command() != NL80211_CMD_SET_WOWLAN) {
+ LOG(ERROR) << "Invalid message command";
+ return false;
+ }
+ set<pair<ByteString, ByteString>,
+ bool (*)(const pair<ByteString, ByteString> &,
+ const pair<ByteString, ByteString> &)>
+ expected_patt_mask_pairs(ByteStringPairIsLessThan);
+ ByteString temp_pattern;
+ ByteString temp_mask;
+ for (const IPAddress &addr : addrs.GetIPAddresses()) {
+ temp_pattern.Clear();
+ temp_mask.Clear();
+ WakeOnWifi::CreateIPAddressPatternAndMask(addr, &temp_pattern, &temp_mask);
+ expected_patt_mask_pairs.emplace(temp_pattern, temp_mask);
+ }
+ AttributeListConstRefPtr triggers;
+ if (!msg.const_attributes()->ConstGetNestedAttributeList(
+ NL80211_ATTR_WOWLAN_TRIGGERS, &triggers)) {
+ // No triggers in the returned message, which is valid iff the NIC has no
+ // wake-on-packet settings currently programmed into it.
+ return (expected_patt_mask_pairs.size() == 0);
+ }
+ AttributeListConstRefPtr patterns;
+ if (!triggers->ConstGetNestedAttributeList(NL80211_WOWLAN_TRIG_PKT_PATTERN,
+ &patterns)) {
+ LOG(ERROR) << "Could not get nested attribute list "
+ "NL80211_WOWLAN_TRIG_PKT_PATTERN.";
+ return false;
+ }
+ bool mismatch_found = false;
+ size_t num_mismatch = expected_patt_mask_pairs.size();
+ int pattern_index;
+ AttributeIdIterator pattern_iter(*patterns);
+ AttributeListConstRefPtr pattern_info;
+ ByteString returned_mask;
+ ByteString returned_pattern;
+ while (!pattern_iter.AtEnd()) {
+ returned_mask.Clear();
+ returned_pattern.Clear();
+ pattern_index = pattern_iter.GetId();
+ if (!patterns->ConstGetNestedAttributeList(pattern_index, &pattern_info)) {
+ LOG(ERROR) << "Could not get nested attribute list index "
+ << pattern_index << " in patterns.";
+ return false;
+ }
+ if (!pattern_info->GetRawAttributeValue(NL80211_PKTPAT_MASK,
+ &returned_mask)) {
+ LOG(ERROR) << "Could not get attribute NL80211_PKTPAT_MASK in "
+ "pattern_info.";
+ return false;
+ }
+ if (!pattern_info->GetRawAttributeValue(NL80211_PKTPAT_PATTERN,
+ &returned_pattern)) {
+ LOG(ERROR) << "Could not get attribute NL80211_PKTPAT_PATTERN in "
+ "pattern_info.";
+ return false;
+ }
+ if (expected_patt_mask_pairs.find(
+ pair<ByteString, ByteString>(returned_pattern, returned_mask)) ==
+ expected_patt_mask_pairs.end()) {
+ mismatch_found = true;
+ break;
+ } else {
+ --num_mismatch;
+ }
+ pattern_iter.Advance();
+ }
+ return (!mismatch_found && !num_mismatch);
+}
+
} // namespace WakeOnWifi
} // namespace shill
diff --git a/wake_on_wifi.h b/wake_on_wifi.h
index 6777e8a..d68cb36 100644
--- a/wake_on_wifi.h
+++ b/wake_on_wifi.h
@@ -5,22 +5,37 @@
#ifndef SHILL_WAKE_ON_WIFI_H_
#define SHILL_WAKE_ON_WIFI_H_
+#include <linux/if_ether.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+
+#include <utility>
+#include <vector>
+
#include <base/basictypes.h>
+#include "shill/refptr_types.h"
+
namespace shill {
class ByteString;
class Error;
class IPAddress;
+class IPAddressStore;
+class GetWakeOnPacketConnMessage;
+class Nl80211Message;
class SetWakeOnPacketConnMessage;
namespace WakeOnWifi {
+// Used for comparison of ByteString pairs in a set.
+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|.
void SetMask(ByteString *mask, uint32_t pattern_len, uint32_t offset);
-// Creates a pattern and mask for an NL80211 message that programs the NIC to
+// 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.
bool CreateIPAddressPatternAndMask(const IPAddress &ip_addr,
@@ -29,22 +44,43 @@
ByteString *mask);
void CreateIPV6PatternAndMask(const IPAddress &ip_addr, ByteString *pattern,
ByteString *mask);
-// Creates and sets an attribute in an NL80211 message |msg| which indicates the
+// Creates and sets an attribute in a NL80211 message |msg| which indicates the
// index of the wiphy device to program.
-bool ConfigureWiphyIndex(SetWakeOnPacketConnMessage *msg, int32_t index);
-// Creates and sets attributes in an NL80211 message |msg| so that the message
-// will deprogram all wake-on-packet rules from the NIC with wiphy index
-// |wiphy_index|.
+bool ConfigureWiphyIndex(Nl80211Message *msg, int32_t index);
+// Creates and sets attributes in an SetWakeOnPacketConnMessage |msg| so that
+// the message will deprogram all wake-on-packet rules from the NIC with wiphy
+// index |wiphy_index|.
// NOTE: Assumes that |msg| has not been altered since construction.
bool ConfigureRemoveAllWakeOnPacketMsg(SetWakeOnPacketConnMessage *msg,
uint32_t wiphy_index, Error *error);
-// Creates and sets attributes in an NL80211 message |msg| so that the message
-// will program the NIC with wiphy index |wiphy_index| to wake on packets
-// originating from IP address |ip_addr|.
+// Creates and sets attributes in a SetWakeOnPacketConnMessage |msg|
+// so that the message will program the NIC with wiphy index |wiphy_index| to
+// wake on packets originating from IP addresses in |addrs|.
// NOTE: Assumes that |msg| has not been altered since construction.
bool ConfigureAddWakeOnPacketMsg(SetWakeOnPacketConnMessage *msg,
- const IPAddress &ip_addr, uint32_t wiphy_index,
- Error *error);
+ const IPAddressStore &addrs,
+ uint32_t wiphy_index, Error *error);
+// Helper function to ConfigureAddWakeOnPacketMsg that creates a single nested
+// attribute inside the attribute list referenced by |patterns| representing
+// a single wake-on-packet pattern matching rule with index |patnum|.
+// 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.
+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|.
+// NOTE: Assumes that |msg| has not been altered since construction.
+bool ConfigureGetWakeOnPacketMsg(GetWakeOnPacketConnMessage *msg,
+ uint32_t wiphy_index, Error *error);
+// Given a NL80211_CMD_GET_WOWLAN response or NL80211_CMD_SET_WOWLAN request
+// |msg|, returns true if the source IP addresses in |msg| match those in
+// |addrs|. Returns false otherwise.
+bool WakeOnPacketSettingsMatch(const Nl80211Message &msg,
+ const IPAddressStore &addrs);
} // namespace WakeOnWifi
diff --git a/wake_on_wifi_unittest.cc b/wake_on_wifi_unittest.cc
index 2899c23..d1ed951 100644
--- a/wake_on_wifi_unittest.cc
+++ b/wake_on_wifi_unittest.cc
@@ -2,25 +2,32 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <set>
+#include <string>
+#include <utility>
+
#include <gtest/gtest.h>
#include "shill/byte_string.h"
#include "shill/error.h"
#include "shill/ip_address.h"
+#include "shill/ip_address_store.h"
#include "shill/nl80211_message.h"
#include "shill/testing.h"
#include "shill/wake_on_wifi.h"
+using std::string;
+
namespace shill {
namespace {
-// Zero-byte pattern prefixes to match the offsetting bytes in the ethernet
-// frame that lie before the source ip address field
-const uint8_t kIPV4PatternPrefix[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+// Zero-byte pattern prefixes to match the offsetting bytes in the Ethernet
+// frame that lie before the source IP address field.
+const uint8_t kIPV4PatternPrefix[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00};
const uint8_t kIPV6PatternPrefix[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
@@ -28,7 +35,7 @@
// These masks have bits set to 1 to match bytes in an IP address pattern that
// represent the source IP address of the frame. They are padded with zero
// bits in front to ignore the frame offset and at the end to byte-align the
-// mask itself
+// mask itself.
const uint8_t kIPV4MaskBytes[] = {0x00, 0x00, 0x00, 0x3c};
const uint8_t kIPV6MaskBytes[] = {0x00, 0x00, 0xc0, 0xff, 0x3f};
@@ -70,6 +77,71 @@
0x00, 0x00, 0x00, 0x00, 0xde, 0xde,
0xbe, 0x90, 0x34, 0x26};
+// These blobs represent NL80211 messages from the kernel reporting the NIC's
+// wake-on-packet settings, sent in response to NL80211_CMD_GET_WOWLAN requests.
+const uint8_t kResponseNoIPAddresses[] = {
+ 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x57, 0x40, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00};
+const uint8_t kResponseIPV40[] = {
+ 0x4C, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x57, 0x40, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, 0x38, 0x00,
+ 0x75, 0x00, 0x34, 0x00, 0x04, 0x00, 0x30, 0x00, 0x01, 0x00, 0x08,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x22, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8, 0x0A, 0x14, 0x00, 0x00};
+const uint8_t kResponseIPV401[] = {
+ 0x7C, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x57, 0x40, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, 0x68, 0x00, 0x75, 0x00,
+ 0x64, 0x00, 0x04, 0x00, 0x30, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x22, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
+ 0x03, 0x04, 0x00, 0x00, 0x30, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x22, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
+ 0x0A, 0x14, 0x00, 0x00};
+const uint8_t kResponseIPV401IPV60[] = {
+ 0xB8, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x57, 0x40, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, 0xA4, 0x00, 0x75, 0x00,
+ 0xA0, 0x00, 0x04, 0x00, 0x30, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x22, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
+ 0x03, 0x04, 0x00, 0x00, 0x30, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x22, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
+ 0x0A, 0x14, 0x00, 0x00, 0x3C, 0x00, 0x03, 0x00, 0x09, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0xC0, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xDC,
+ 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54,
+ 0x32, 0x10, 0x00, 0x00};
+const uint8_t kResponseIPV401IPV601[] = {
+ 0xF4, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x57, 0x40, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, 0xE0, 0x00, 0x75, 0x00,
+ 0xDC, 0x00, 0x04, 0x00, 0x30, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x22, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
+ 0x03, 0x04, 0x00, 0x00, 0x3C, 0x00, 0x02, 0x00, 0x09, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0xC0, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x20, 0x0C,
+ 0x41, 0x7A, 0x00, 0x00, 0x30, 0x00, 0x03, 0x00, 0x08, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x3C, 0x22, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8,
+ 0x0A, 0x14, 0x00, 0x00, 0x3C, 0x00, 0x04, 0x00, 0x09, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0xC0, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xDC,
+ 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54,
+ 0x32, 0x10, 0x00, 0x00};
+
} // namespace
ByteString CreatePattern(const unsigned char *prefix, size_t prefix_len,
@@ -79,7 +151,29 @@
return result;
}
-TEST(WifiUtilTest, CreateIPAddressPatternAndMask) {
+bool IPAddressesMatch(const IPAddressStore &addrs0,
+ const std::vector<IPAddress> &addrs1) {
+ if (addrs0.Count() != addrs1.size()) {
+ return false;
+ }
+ bool mismatch_found = false;
+ int num_mismatch = addrs0.Count();
+ for (const IPAddress &addr : addrs1) {
+ if (addrs0.Contains(addr)) {
+ --num_mismatch;
+ } else {
+ mismatch_found = true;
+ break;
+ }
+ }
+ if (mismatch_found || num_mismatch != 0) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+TEST(WakeOnWifiTest, CreateIPAddressPatternAndMask) {
ByteString pattern;
ByteString mask;
ByteString expected_pattern;
@@ -192,7 +286,7 @@
EXPECT_TRUE(mask.Equals(ByteString(kIPV6MaskBytes, sizeof(kIPV6MaskBytes))));
}
-TEST(WifiUtilTest, ConfigureWiphyIndex) {
+TEST(WakeOnWifiTest, ConfigureWiphyIndex) {
SetWakeOnPacketConnMessage msg;
uint32_t value;
EXPECT_FALSE(
@@ -204,7 +298,7 @@
EXPECT_EQ(value, 137);
}
-TEST(WifiUtilTest, ConfigureRemoveAllWakeOnPacketMsg) {
+TEST(WakeOnWifiTest, ConfigureRemoveAllWakeOnPacketMsg) {
SetWakeOnPacketConnMessage msg;
Error e;
uint32_t value;
@@ -218,190 +312,163 @@
EXPECT_EQ(value, 57);
}
-bool AddWakeOnPacketMsgAttributesSet(SetWakeOnPacketConnMessage *msg) {
- AttributeListRefPtr triggers;
- AttributeListRefPtr patterns;
- AttributeListRefPtr pattern_info;
- ByteString mask;
- ByteString pattern;
- uint32_t value;
- uint32_t offset;
- uint8_t patnum = 1;
- if (!msg->attributes()->GetU32AttributeValue(NL80211_ATTR_WIPHY, &value)) {
- return false;
- }
- if (!msg->attributes()->GetNestedAttributeList(NL80211_ATTR_WOWLAN_TRIGGERS,
- &triggers)) {
- return false;
- }
- if (!triggers->GetNestedAttributeList(NL80211_WOWLAN_TRIG_PKT_PATTERN,
- &patterns)) {
- return false;
- }
- if (!patterns->GetNestedAttributeList(patnum, &pattern_info)) {
- return false;
- }
+TEST(WakeOnWifiTest, WakeOnPacketSettingsMatch) {
+ IPAddressStore all_addresses;
+ scoped_ptr<uint8_t[]> message_memory_0(
+ new uint8_t[sizeof(kResponseNoIPAddresses)]);
+ memcpy(message_memory_0.get(), kResponseNoIPAddresses,
+ sizeof(kResponseNoIPAddresses));
+ nlmsghdr *hdr0 = reinterpret_cast<nlmsghdr *>(message_memory_0.get());
+ GetWakeOnPacketConnMessage msg0;
+ msg0.InitFromNlmsg(hdr0);
+ EXPECT_TRUE(WakeOnWifi::WakeOnPacketSettingsMatch(msg0, all_addresses));
- if (!pattern_info->GetRawAttributeValue(NL80211_PKTPAT_MASK, &mask)) {
- return false;
- }
- if (!pattern_info->GetRawAttributeValue(NL80211_PKTPAT_PATTERN, &pattern)) {
- return false;
- }
- if (!pattern_info->GetU32AttributeValue(NL80211_PKTPAT_OFFSET, &offset)) {
- return false;
- }
- if (offset != 0) {
- return false;
- }
- return true;
+ all_addresses.AddUnique(
+ IPAddress(string(kIPV4Address0, sizeof(kIPV4Address0))));
+ scoped_ptr<uint8_t[]> message_memory_1(new uint8_t[sizeof(kResponseIPV40)]);
+ memcpy(message_memory_1.get(), kResponseIPV40, sizeof(kResponseIPV40));
+ nlmsghdr *hdr1 = reinterpret_cast<nlmsghdr *>(message_memory_1.get());
+ GetWakeOnPacketConnMessage msg1;
+ msg1.InitFromNlmsg(hdr1);
+ EXPECT_TRUE(WakeOnWifi::WakeOnPacketSettingsMatch(msg1, all_addresses));
+ EXPECT_FALSE(WakeOnWifi::WakeOnPacketSettingsMatch(msg0, all_addresses));
+
+ all_addresses.AddUnique(
+ IPAddress(string(kIPV4Address1, sizeof(kIPV4Address1))));
+ scoped_ptr<uint8_t[]> message_memory_2(new uint8_t[sizeof(kResponseIPV401)]);
+ memcpy(message_memory_2.get(), kResponseIPV401, sizeof(kResponseIPV401));
+ nlmsghdr *hdr2 = reinterpret_cast<nlmsghdr *>(message_memory_2.get());
+ GetWakeOnPacketConnMessage msg2;
+ msg2.InitFromNlmsg(hdr2);
+ EXPECT_TRUE(WakeOnWifi::WakeOnPacketSettingsMatch(msg2, all_addresses));
+ EXPECT_FALSE(WakeOnWifi::WakeOnPacketSettingsMatch(msg1, all_addresses));
+ EXPECT_FALSE(WakeOnWifi::WakeOnPacketSettingsMatch(msg0, all_addresses));
+
+ all_addresses.AddUnique(
+ IPAddress(string(kIPV6Address0, sizeof(kIPV6Address0))));
+ scoped_ptr<uint8_t[]> message_memory_3(
+ new uint8_t[sizeof(kResponseIPV401IPV60)]);
+ memcpy(message_memory_3.get(), kResponseIPV401IPV60,
+ sizeof(kResponseIPV401IPV60));
+ nlmsghdr *hdr3 = reinterpret_cast<nlmsghdr *>(message_memory_3.get());
+ GetWakeOnPacketConnMessage msg3;
+ msg3.InitFromNlmsg(hdr3);
+ EXPECT_TRUE(WakeOnWifi::WakeOnPacketSettingsMatch(msg3, all_addresses));
+ EXPECT_FALSE(WakeOnWifi::WakeOnPacketSettingsMatch(msg2, all_addresses));
+ EXPECT_FALSE(WakeOnWifi::WakeOnPacketSettingsMatch(msg1, all_addresses));
+ EXPECT_FALSE(WakeOnWifi::WakeOnPacketSettingsMatch(msg0, all_addresses));
+
+ all_addresses.AddUnique(
+ IPAddress(string(kIPV6Address1, sizeof(kIPV6Address1))));
+ scoped_ptr<uint8_t[]> message_memory_4(
+ new uint8_t[sizeof(kResponseIPV401IPV601)]);
+ memcpy(message_memory_4.get(), kResponseIPV401IPV601,
+ sizeof(kResponseIPV401IPV601));
+ nlmsghdr *hdr4 = reinterpret_cast<nlmsghdr *>(message_memory_4.get());
+ GetWakeOnPacketConnMessage msg4;
+ msg4.InitFromNlmsg(hdr4);
+ EXPECT_TRUE(WakeOnWifi::WakeOnPacketSettingsMatch(msg4, all_addresses));
+ EXPECT_FALSE(WakeOnWifi::WakeOnPacketSettingsMatch(msg3, all_addresses));
+ EXPECT_FALSE(WakeOnWifi::WakeOnPacketSettingsMatch(msg2, all_addresses));
+ EXPECT_FALSE(WakeOnWifi::WakeOnPacketSettingsMatch(msg1, all_addresses));
+ EXPECT_FALSE(WakeOnWifi::WakeOnPacketSettingsMatch(msg0, all_addresses));
}
-bool AddWakeOnPacketMsgPatternAndMaskMatch(SetWakeOnPacketConnMessage *msg,
- ByteString expected_pattern,
- ByteString expected_mask) {
- AttributeListRefPtr triggers;
- AttributeListRefPtr patterns;
- AttributeListRefPtr pattern_info;
- ByteString msg_mask;
- ByteString msg_pattern;
-
- uint8_t patnum = 1;
- if (!msg->attributes()->GetNestedAttributeList(NL80211_ATTR_WOWLAN_TRIGGERS,
- &triggers)) {
- return false;
- }
- if (!triggers->GetNestedAttributeList(NL80211_WOWLAN_TRIG_PKT_PATTERN,
- &patterns)) {
- return false;
- }
- if (!patterns->GetNestedAttributeList(patnum, &pattern_info)) {
- return false;
- }
- if (!pattern_info->GetRawAttributeValue(NL80211_PKTPAT_PATTERN,
- &msg_pattern)) {
- return false;
- }
- if (!pattern_info->GetRawAttributeValue(NL80211_PKTPAT_MASK, &msg_mask)) {
- return false;
- }
- if (!expected_pattern.Equals(msg_pattern)) {
- LOG(INFO) << "Expected pattern: " << expected_pattern.HexEncode();
- LOG(INFO) << "Actual pattern: " << msg_pattern.HexEncode();
- return false;
- }
- if (!expected_mask.Equals(msg_mask)) {
- LOG(INFO) << "Expected mask: " << expected_mask.HexEncode();
- LOG(INFO) << "Actual mask: " << msg_mask.HexEncode();
- return false;
- }
- return true;
-}
-
-TEST(WifiUtilTest, ConfigureAddWakeOnPacketMsg) {
+TEST(WakeOnWifiTest, ConfigureAddWakeOnPacketMsg) {
+ IPAddressStore all_addresses;
+ int index = 1; // wiphy device number
SetWakeOnPacketConnMessage msg0;
- int index = 1;
Error e;
+ all_addresses.AddUnique(
+ IPAddress(string(kIPV4Address0, sizeof(kIPV4Address0))));
ByteString expected_mask = ByteString(kIPV4MaskBytes, sizeof(kIPV4MaskBytes));
ByteString expected_pattern =
CreatePattern(kIPV4PatternPrefix, sizeof(kIPV4PatternPrefix),
kIPV4Address0Bytes, sizeof(kIPV4Address0Bytes));
- WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg0, IPAddress(kIPV4Address0),
- index, &e);
- EXPECT_TRUE(AddWakeOnPacketMsgAttributesSet(&msg0));
- EXPECT_TRUE(AddWakeOnPacketMsgPatternAndMaskMatch(&msg0, expected_pattern,
- expected_mask));
+ WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg0, all_addresses, index, &e);
+ EXPECT_TRUE(WakeOnWifi::WakeOnPacketSettingsMatch(msg0, all_addresses));
SetWakeOnPacketConnMessage msg1;
+ all_addresses.AddUnique(
+ IPAddress(string(kIPV4Address1, sizeof(kIPV4Address1))));
expected_pattern =
CreatePattern(kIPV4PatternPrefix, sizeof(kIPV4PatternPrefix),
kIPV4Address1Bytes, sizeof(kIPV4Address1Bytes));
- WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg1, IPAddress(kIPV4Address1),
- index, &e);
- EXPECT_TRUE(AddWakeOnPacketMsgAttributesSet(&msg1));
- EXPECT_TRUE(AddWakeOnPacketMsgPatternAndMaskMatch(&msg1, expected_pattern,
- expected_mask));
+ WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg1, all_addresses, index, &e);
+ EXPECT_TRUE(WakeOnWifi::WakeOnPacketSettingsMatch(msg1, all_addresses));
SetWakeOnPacketConnMessage msg2;
+ all_addresses.AddUnique(
+ IPAddress(string(kIPV6Address0, sizeof(kIPV6Address0))));
expected_mask = ByteString(kIPV6MaskBytes, sizeof(kIPV6MaskBytes));
expected_pattern =
CreatePattern(kIPV6PatternPrefix, sizeof(kIPV6PatternPrefix),
kIPV6Address0Bytes, sizeof(kIPV6Address0Bytes));
- WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg2, IPAddress(kIPV6Address0),
- index, &e);
- EXPECT_TRUE(AddWakeOnPacketMsgAttributesSet(&msg2));
- EXPECT_TRUE(AddWakeOnPacketMsgPatternAndMaskMatch(&msg2, expected_pattern,
- expected_mask));
+ WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg2, all_addresses, index, &e);
+ EXPECT_TRUE(WakeOnWifi::WakeOnPacketSettingsMatch(msg2, all_addresses));
SetWakeOnPacketConnMessage msg3;
+ all_addresses.AddUnique(
+ IPAddress(string(kIPV6Address1, sizeof(kIPV6Address1))));
expected_pattern =
CreatePattern(kIPV6PatternPrefix, sizeof(kIPV6PatternPrefix),
kIPV6Address1Bytes, sizeof(kIPV6Address1Bytes));
- WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg3, IPAddress(kIPV6Address1),
- index, &e);
- EXPECT_TRUE(AddWakeOnPacketMsgAttributesSet(&msg3));
- EXPECT_TRUE(AddWakeOnPacketMsgPatternAndMaskMatch(&msg3, expected_pattern,
- expected_mask));
+ WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg3, all_addresses, index, &e);
+ EXPECT_TRUE(WakeOnWifi::WakeOnPacketSettingsMatch(msg3, all_addresses));
SetWakeOnPacketConnMessage msg4;
+ all_addresses.AddUnique(
+ IPAddress(string(kIPV6Address2, sizeof(kIPV6Address2))));
expected_pattern =
CreatePattern(kIPV6PatternPrefix, sizeof(kIPV6PatternPrefix),
kIPV6Address2Bytes, sizeof(kIPV6Address2Bytes));
- WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg4, IPAddress(kIPV6Address2),
- index, &e);
- EXPECT_TRUE(AddWakeOnPacketMsgAttributesSet(&msg4));
- EXPECT_TRUE(AddWakeOnPacketMsgPatternAndMaskMatch(&msg4, expected_pattern,
- expected_mask));
+ WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg4, all_addresses, index, &e);
+ EXPECT_TRUE(WakeOnWifi::WakeOnPacketSettingsMatch(msg4, all_addresses));
SetWakeOnPacketConnMessage msg5;
+ all_addresses.AddUnique(
+ IPAddress(string(kIPV6Address3, sizeof(kIPV6Address3))));
expected_pattern =
CreatePattern(kIPV6PatternPrefix, sizeof(kIPV6PatternPrefix),
kIPV6Address3Bytes, sizeof(kIPV6Address3Bytes));
- WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg5, IPAddress(kIPV6Address3),
- index, &e);
- EXPECT_TRUE(AddWakeOnPacketMsgAttributesSet(&msg5));
- EXPECT_TRUE(AddWakeOnPacketMsgPatternAndMaskMatch(&msg5, expected_pattern,
- expected_mask));
+ WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg5, all_addresses, index, &e);
+ EXPECT_TRUE(WakeOnWifi::WakeOnPacketSettingsMatch(msg5, all_addresses));
SetWakeOnPacketConnMessage msg6;
+ all_addresses.AddUnique(
+ IPAddress(string(kIPV6Address4, sizeof(kIPV6Address4))));
expected_pattern =
CreatePattern(kIPV6PatternPrefix, sizeof(kIPV6PatternPrefix),
kIPV6Address4Bytes, sizeof(kIPV6Address4Bytes));
- WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg6, IPAddress(kIPV6Address4),
- index, &e);
- EXPECT_TRUE(AddWakeOnPacketMsgAttributesSet(&msg6));
- EXPECT_TRUE(AddWakeOnPacketMsgPatternAndMaskMatch(&msg6, expected_pattern,
- expected_mask));
+ WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg6, all_addresses, index, &e);
+ EXPECT_TRUE(WakeOnWifi::WakeOnPacketSettingsMatch(msg6, all_addresses));
SetWakeOnPacketConnMessage msg7;
+ all_addresses.AddUnique(
+ IPAddress(string(kIPV6Address5, sizeof(kIPV6Address5))));
expected_pattern =
CreatePattern(kIPV6PatternPrefix, sizeof(kIPV6PatternPrefix),
kIPV6Address5Bytes, sizeof(kIPV6Address5Bytes));
- WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg7, IPAddress(kIPV6Address5),
- index, &e);
- EXPECT_TRUE(AddWakeOnPacketMsgAttributesSet(&msg7));
- EXPECT_TRUE(AddWakeOnPacketMsgPatternAndMaskMatch(&msg7, expected_pattern,
- expected_mask));
+ WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg7, all_addresses, index, &e);
+ EXPECT_TRUE(WakeOnWifi::WakeOnPacketSettingsMatch(msg7, all_addresses));
SetWakeOnPacketConnMessage msg8;
+ all_addresses.AddUnique(
+ IPAddress(string(kIPV6Address6, sizeof(kIPV6Address6))));
expected_pattern =
CreatePattern(kIPV6PatternPrefix, sizeof(kIPV6PatternPrefix),
kIPV6Address6Bytes, sizeof(kIPV6Address6Bytes));
- WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg8, IPAddress(kIPV6Address6),
- index, &e);
- EXPECT_TRUE(AddWakeOnPacketMsgAttributesSet(&msg8));
- EXPECT_TRUE(AddWakeOnPacketMsgPatternAndMaskMatch(&msg8, expected_pattern,
- expected_mask));
+ WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg8, all_addresses, index, &e);
+ EXPECT_TRUE(WakeOnWifi::WakeOnPacketSettingsMatch(msg8, all_addresses));
SetWakeOnPacketConnMessage msg9;
+ all_addresses.AddUnique(
+ IPAddress(string(kIPV6Address7, sizeof(kIPV6Address7))));
expected_pattern =
CreatePattern(kIPV6PatternPrefix, sizeof(kIPV6PatternPrefix),
kIPV6Address7Bytes, sizeof(kIPV6Address7Bytes));
- WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg9, IPAddress(kIPV6Address7),
- index, &e);
- EXPECT_TRUE(AddWakeOnPacketMsgAttributesSet(&msg9));
- EXPECT_TRUE(AddWakeOnPacketMsgPatternAndMaskMatch(&msg9, expected_pattern,
- expected_mask));
+ WakeOnWifi::ConfigureAddWakeOnPacketMsg(&msg9, all_addresses, index, &e);
+ EXPECT_TRUE(WakeOnWifi::WakeOnPacketSettingsMatch(msg9, all_addresses));
}
} // namespace shill
diff --git a/wifi.cc b/wifi.cc
index cd234a9..cf9553e 100644
--- a/wifi.cc
+++ b/wifi.cc
@@ -95,6 +95,8 @@
const char WiFi::kProgressiveScanFieldTrialFlagFile[] =
"/home/chronos/.progressive_scan_variation";
const size_t WiFi::kStuckQueueLengthThreshold = 40; // ~1 full-channel scan
+const int WiFi::kVerifyWakeOnPacketSettingsDelaySeconds = 1;
+const int WiFi::kMaxSetWakeOnPacketRetries = 2;
WiFi::WiFi(ControlInterface *control_interface,
EventDispatcher *dispatcher,
@@ -146,7 +148,8 @@
fraction_per_scan_(kDefaultFractionPerScan),
scan_state_(kScanIdle),
scan_method_(kScanMethodNone),
- receive_byte_count_at_connect_(0) {
+ receive_byte_count_at_connect_(0),
+ num_set_wake_on_packet_retries_(0) {
PropertyStore *store = this->mutable_store();
store->RegisterDerivedString(
kBgscanMethodProperty,
@@ -1767,47 +1770,24 @@
void WiFi::AddWakeOnPacketConnection(const IPAddress &ip_endpoint,
Error *error) {
- SetWakeOnPacketConnMessage add_wowlan_msg;
- if (!WakeOnWifi::ConfigureAddWakeOnPacketMsg(&add_wowlan_msg, ip_endpoint,
- wiphy_index_, error)) {
- LOG(ERROR) << "Failed to configure nl80211 message.";
- return;
- }
- add_wowlan_msg.AddAckFlag();
- netlink_manager_->SendNl80211Message(
- &add_wowlan_msg, Bind(&WiFi::OnSetWakeOnPacketConnectionResponse,
- weak_ptr_factory_.GetWeakPtr()),
- Bind(&WiFi::OnAddWakeOnPacketConnectionAck,
- weak_ptr_factory_.GetWeakPtr(), ip_endpoint),
- Bind(&NetlinkManager::OnNetlinkMessageError));
+ wake_on_packet_connections_.AddUnique(ip_endpoint);
+ SendSetWakeOnPacketMessage(error);
}
void WiFi::RemoveWakeOnPacketConnection(const IPAddress &ip_endpoint,
Error *error) {
if (!wake_on_packet_connections_.Contains(ip_endpoint)) {
Error::PopulateAndLog(error, Error::kNotFound,
- "No such wake-on-packet connection registered");
+ "No such wake-on-packet connection registered");
return;
}
wake_on_packet_connections_.Remove(ip_endpoint);
- RemoveAllWakeOnPacketConnections(error);
- for (const IPAddress &addr : wake_on_packet_connections_.GetIPAddresses()) {
- AddWakeOnPacketConnection(addr, error);
- if (error->IsFailure()) {
- Error::PopulateAndLog(error, Error::kOperationFailed,
- "Call to AddWakeOnPacketConnection failed; "
- "removing all wake-on-packet rules");
- RemoveAllWakeOnPacketConnections(error);
- return;
- }
- }
- // TODO(samueltan): Add a PostDelayedTask with callback that checks NIC state
- // against wake_on_packet_connections_ once such a function has been
- // implemented.
+ SendSetWakeOnPacketMessage(error);
}
void WiFi::RemoveAllWakeOnPacketConnections(Error *error) {
- // Send an empty NL80211_CMD_SET_WOWLAN message.
+ // Send an empty NL80211_CMD_SET_WOWLAN message to disable wowlan.
+ wake_on_packet_connections_.Clear();
SetWakeOnPacketConnMessage disable_wowlan_msg;
if (!WakeOnWifi::ConfigureRemoveAllWakeOnPacketMsg(&disable_wowlan_msg,
wiphy_index_, error)) {
@@ -1815,13 +1795,17 @@
"Failed to configure nl80211 message");
return;
}
- disable_wowlan_msg.AddAckFlag();
netlink_manager_->SendNl80211Message(
&disable_wowlan_msg, Bind(&WiFi::OnSetWakeOnPacketConnectionResponse,
weak_ptr_factory_.GetWeakPtr()),
- Bind(&WiFi::OnRemoveAllWakeOnPacketConnectionAck,
- weak_ptr_factory_.GetWeakPtr()),
+ Bind(&NetlinkManager::OnAckDoNothing),
Bind(&NetlinkManager::OnNetlinkMessageError));
+
+ verify_wake_on_packet_settings_callback_.Reset(Bind(
+ &WiFi::RequestWakeOnPacketSettings, weak_ptr_factory_.GetWeakPtr()));
+ dispatcher()->PostDelayedTask(
+ verify_wake_on_packet_settings_callback_.callback(),
+ kVerifyWakeOnPacketSettingsDelaySeconds * 1000);
}
void WiFi::OnSetWakeOnPacketConnectionResponse(
@@ -1830,19 +1814,70 @@
// requests.
}
-void WiFi::OnAddWakeOnPacketConnectionAck(IPAddress ip_endpoint,
- bool *remove_callbacks) {
- wake_on_packet_connections_.AddUnique(ip_endpoint);
- // No other responses expected for original message, so remove callbacks.
- *remove_callbacks = true;
+void WiFi::RequestWakeOnPacketSettings() {
+ Error e;
+ GetWakeOnPacketConnMessage get_wowlan_msg;
+ if (!WakeOnWifi::ConfigureGetWakeOnPacketMsg(&get_wowlan_msg, wiphy_index_,
+ &e)) {
+ LOG(ERROR) << e.message();
+ return;
+ }
+ netlink_manager_->SendNl80211Message(
+ &get_wowlan_msg, Bind(&WiFi::VerifyWakeOnPacketConnections,
+ weak_ptr_factory_.GetWeakPtr()),
+ Bind(&NetlinkManager::OnAckDoNothing),
+ Bind(&NetlinkManager::OnNetlinkMessageError));
}
-void WiFi::OnRemoveAllWakeOnPacketConnectionAck(bool *remove_callbacks) {
- wake_on_packet_connections_.Clear();
- // No other responses expected for original message, so remove callbacks.
- *remove_callbacks = true;
+void WiFi::VerifyWakeOnPacketConnections(
+ const Nl80211Message &nl80211_message) {
+ if (WakeOnWifi::WakeOnPacketSettingsMatch(nl80211_message,
+ wake_on_packet_connections_)) {
+ SLOG(WiFi, 2) << __func__ << ": "
+ << "Wake-on-packet settings successfully verified";
+ } else {
+ LOG(ERROR) << __func__ << " failed: discrepancy between wake-on-packet "
+ "settings on NIC and those in local data "
+ "structure detected";
+ RetrySetWakeOnPacketConnections();
+ }
}
+void WiFi::SendSetWakeOnPacketMessage(Error *error) {
+ if (wake_on_packet_connections_.Empty()) {
+ RemoveAllWakeOnPacketConnections(error);
+ return;
+ }
+ SetWakeOnPacketConnMessage set_wowlan_msg;
+ if (!WakeOnWifi::ConfigureAddWakeOnPacketMsg(
+ &set_wowlan_msg, wake_on_packet_connections_, wiphy_index_, error)) {
+ LOG(ERROR) << "Failed to configure nl80211 message.";
+ return;
+ }
+ netlink_manager_->SendNl80211Message(
+ &set_wowlan_msg, Bind(&WiFi::OnSetWakeOnPacketConnectionResponse,
+ weak_ptr_factory_.GetWeakPtr()),
+ Bind(&NetlinkManager::OnAckDoNothing),
+ Bind(&NetlinkManager::OnNetlinkMessageError));
+
+ verify_wake_on_packet_settings_callback_.Reset(
+ Bind(&WiFi::RequestWakeOnPacketSettings, weak_ptr_factory_.GetWeakPtr()));
+ dispatcher()->PostDelayedTask(
+ verify_wake_on_packet_settings_callback_.callback(),
+ kVerifyWakeOnPacketSettingsDelaySeconds * 1000);
+}
+
+void WiFi::RetrySetWakeOnPacketConnections() {
+ if (num_set_wake_on_packet_retries_ < kMaxSetWakeOnPacketRetries) {
+ Error e;
+ SLOG(WiFi, 2) << __func__;
+ SendSetWakeOnPacketMessage(&e);
+ ++num_set_wake_on_packet_retries_;
+ } else {
+ SLOG(WiFi, 2) << __func__ << ": max retry attempts reached";
+ num_set_wake_on_packet_retries_ = 0;
+ }
+}
void WiFi::RestartFastScanAttempts() {
fast_scans_remaining_ = kNumFastScanAttempts;
diff --git a/wifi.h b/wifi.h
index 907346c..e9b5e8b 100644
--- a/wifi.h
+++ b/wifi.h
@@ -141,17 +141,29 @@
// Callback for when a service fails to configure with an IP.
void OnIPConfigFailure() override;
- // Implementation of Wake-on-WLAN interface that programs the NIC.
+ // Program the NIC to wake on packets received from |ip_endpoint|.
void AddWakeOnPacketConnection(const IPAddress &ip_endpoint,
Error *error) override;
+ // Remove rule to wake on packets received from |ip_endpoint| from the NIC.
void RemoveWakeOnPacketConnection(const IPAddress &ip_endpoint,
Error *error) override;
+ // Remove all rules to wake on incoming packets from the NIC.
void RemoveAllWakeOnPacketConnections(Error *error) override;
+ // Message handler for NL80211_CMD_SET_WOWLAN responses.
void OnSetWakeOnPacketConnectionResponse(
const Nl80211Message &nl80211_message);
- void OnAddWakeOnPacketConnectionAck(IPAddress ip_endpoint,
- bool *remove_callbacks);
- void OnRemoveAllWakeOnPacketConnectionAck(bool *remove_callbacks);
+ // Request wake-on-packet settings for this wifi device.
+ void RequestWakeOnPacketSettings();
+ // Verify that the wake-on-packet connections programmed into the NIC match
+ // those recorded locally for this device.
+ void VerifyWakeOnPacketConnections(const Nl80211Message &nl80211_message);
+ // Sends an NL80211 message to program the NIC to wake on packets from
+ // the IP addresses stored locally in wake_on_packet_connections_.
+ void SendSetWakeOnPacketMessage(Error *error);
+ // Calls |SendSetWakeOnPacketMessage| and tracks this call as a retry. If
+ // |kMaxSetWakeOnPacketRetries| retries have already been performed, resets
+ // counter and returns.
+ void RetrySetWakeOnPacketConnections();
// Implementation of SupplicantEventDelegateInterface. These methods
// are called by SupplicantInterfaceProxy, in response to events from
@@ -317,6 +329,8 @@
// TODO(wdg): Remove after progressive scan field trial is over.
static const char kProgressiveScanFieldTrialFlagFile[];
static const size_t kStuckQueueLengthThreshold;
+ static const int kVerifyWakeOnPacketSettingsDelaySeconds;
+ static const int kMaxSetWakeOnPacketRetries;
// TODO(wdg): Remove after progressive scan field trial is over.
void ParseFieldTrialFile(const base::FilePath &field_trial_file_path);
@@ -552,6 +566,10 @@
// Executes periodically while a service is connected, to update the
// signal strength from the currently connected AP.
base::CancelableClosure request_station_info_callback_;
+ // 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_;
// Number of remaining fast scans to be done during startup and disconnect.
int fast_scans_remaining_;
// Indicates that the current BSS has reached the completed state according
@@ -601,6 +619,9 @@
// Used to report the current state of our wireless link.
KeyValueStore link_statistics_;
+ // Number of retries to program the NIC's wake-on-packet settings.
+ int num_set_wake_on_packet_retries_;
+
DISALLOW_COPY_AND_ASSIGN(WiFi);
};