// // 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. // #include "shill/wifi/wake_on_wifi.h" #include <linux/nl80211.h> #include <set> #include <string> #include <utility> #include <base/message_loop/message_loop.h> #if defined(__ANDROID__) #include <dbus/service_constants.h> #else #include <chromeos/dbus/service_constants.h> #endif // __ANDROID__ #include <gmock/gmock.h> #include <gtest/gtest.h> #include "shill/error.h" #include "shill/event_dispatcher.h" #include "shill/ip_address_store.h" #include "shill/logging.h" #include "shill/mock_event_dispatcher.h" #include "shill/mock_log.h" #include "shill/mock_metrics.h" #include "shill/net/byte_string.h" #include "shill/net/ip_address.h" #include "shill/net/mock_netlink_manager.h" #include "shill/net/mock_time.h" #include "shill/net/netlink_message_matchers.h" #include "shill/net/netlink_packet.h" #include "shill/net/nl80211_message.h" #include "shill/net/shill_time.h" #include "shill/nice_mock_control.h" #include "shill/test_event_dispatcher.h" #include "shill/testing.h" using base::Bind; using base::Closure; using base::Unretained; using std::set; using std::string; using std::vector; using testing::_; using ::testing::AnyNumber; using ::testing::HasSubstr; using ::testing::Return; namespace shill { namespace { const uint16_t kNl80211FamilyId = 0x13; const uint8_t kSSIDBytes1[] = {0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x47, 0x75, 0x65, 0x73, 0x74}; // Bytes representing a NL80211_CMD_SET_WOWLAN reporting that the system woke // up because of an SSID match. The net detect results report a single SSID // match represented by kSSIDBytes1, occurring in the frequencies in // kSSID1FreqMatches. const uint8_t kWakeReasonSSIDNlMsg[] = { 0x90, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x60, 0x00, 0x75, 0x00, 0x5c, 0x00, 0x13, 0x00, 0x58, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x34, 0x00, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x47, 0x75, 0x65, 0x73, 0x74, 0x00, 0x44, 0x00, 0x2c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6c, 0x09, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x85, 0x09, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x9e, 0x09, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, 0x3c, 0x14, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x78, 0x14, 0x00, 0x00, 0x08, 0x00, 0x05, 0x00, 0x71, 0x16, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0xad, 0x16, 0x00, 0x00, 0x08, 0x00, 0x07, 0x00, 0xc1, 0x16, 0x00, 0x00}; const uint32_t kTimeToNextLeaseRenewalShort = 1; const uint32_t kTimeToNextLeaseRenewalLong = 1000; const uint32_t kNetDetectScanIntervalSeconds = 120; // 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, 0x13, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x57, 0x40, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00}; const uint8_t kResponseIPV40[] = { 0x4C, 0x00, 0x00, 0x00, 0x13, 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 kResponseIPV40WakeOnDisconnect[] = { 0x50, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x57, 0x40, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, 0x3C, 0x00, 0x75, 0x00, 0x04, 0x00, 0x02, 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, 0x13, 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, 0x13, 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, 0x13, 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}; // This blob represents an NL80211 messages from the kernel reporting that the // NIC is programmed to wake on the SSIDs represented by kSSIDBytes1 and // kSSIDBytes2, and scans for these SSIDs at interval // kNetDetectScanIntervalSeconds. const uint8_t kResponseWakeOnSSID[] = { 0x60, 0x01, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x9a, 0x01, 0x00, 0x00, 0xfa, 0x02, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, 0x4c, 0x01, 0x75, 0x00, 0x48, 0x01, 0x12, 0x00, 0x08, 0x00, 0x77, 0x00, 0xc0, 0xd4, 0x01, 0x00, 0x0c, 0x01, 0x2c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6c, 0x09, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x71, 0x09, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x76, 0x09, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7b, 0x09, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x80, 0x09, 0x00, 0x00, 0x08, 0x00, 0x05, 0x00, 0x85, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x8a, 0x09, 0x00, 0x00, 0x08, 0x00, 0x07, 0x00, 0x8f, 0x09, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x94, 0x09, 0x00, 0x00, 0x08, 0x00, 0x09, 0x00, 0x99, 0x09, 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x9e, 0x09, 0x00, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x3c, 0x14, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x50, 0x14, 0x00, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x64, 0x14, 0x00, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x78, 0x14, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x8c, 0x14, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0xa0, 0x14, 0x00, 0x00, 0x08, 0x00, 0x11, 0x00, 0xb4, 0x14, 0x00, 0x00, 0x08, 0x00, 0x12, 0x00, 0xc8, 0x14, 0x00, 0x00, 0x08, 0x00, 0x13, 0x00, 0x7c, 0x15, 0x00, 0x00, 0x08, 0x00, 0x14, 0x00, 0x90, 0x15, 0x00, 0x00, 0x08, 0x00, 0x15, 0x00, 0xa4, 0x15, 0x00, 0x00, 0x08, 0x00, 0x16, 0x00, 0xb8, 0x15, 0x00, 0x00, 0x08, 0x00, 0x17, 0x00, 0xcc, 0x15, 0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0x1c, 0x16, 0x00, 0x00, 0x08, 0x00, 0x19, 0x00, 0x30, 0x16, 0x00, 0x00, 0x08, 0x00, 0x1a, 0x00, 0x44, 0x16, 0x00, 0x00, 0x08, 0x00, 0x1b, 0x00, 0x58, 0x16, 0x00, 0x00, 0x08, 0x00, 0x1c, 0x00, 0x71, 0x16, 0x00, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x85, 0x16, 0x00, 0x00, 0x08, 0x00, 0x1e, 0x00, 0x99, 0x16, 0x00, 0x00, 0x08, 0x00, 0x1f, 0x00, 0xad, 0x16, 0x00, 0x00, 0x08, 0x00, 0x20, 0x00, 0xc1, 0x16, 0x00, 0x00, 0x30, 0x00, 0x84, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x47, 0x75, 0x65, 0x73, 0x74, 0x00, 0x18, 0x00, 0x01, 0x00, 0x12, 0x00, 0x01, 0x00, 0x54, 0x50, 0x2d, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x38, 0x37, 0x36, 0x44, 0x33, 0x35, 0x00, 0x00}; const uint8_t kSSIDBytes2[] = {0x54, 0x50, 0x2d, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x38, 0x37, 0x36, 0x44, 0x33, 0x35}; // Bytes representing a NL80211_CMD_NEW_WIPHY message reporting the WiFi // capabilities of a NIC. This message reports that the NIC supports wake on // pattern (on up to |kNewWiphyNlMsg_MaxPatterns| registered patterns), supports // wake on SSID (on up to |kNewWiphyNlMsg_MaxSSIDs| SSIDs), and supports wake on // disconnect. const uint8_t kNewWiphyNlMsg[] = { 0xb8, 0x0d, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xd9, 0x53, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x00, 0x02, 0x00, 0x70, 0x68, 0x79, 0x30, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x2e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x3d, 0x00, 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x3e, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x3f, 0x00, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x40, 0x00, 0xff, 0xff, 0xff, 0xff, 0x05, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x7b, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x38, 0x00, 0xa9, 0x01, 0x00, 0x00, 0x06, 0x00, 0x7c, 0x00, 0xe6, 0x01, 0x00, 0x00, 0x05, 0x00, 0x85, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x68, 0x00, 0x04, 0x00, 0x82, 0x00, 0x1c, 0x00, 0x39, 0x00, 0x04, 0xac, 0x0f, 0x00, 0x02, 0xac, 0x0f, 0x00, 0x01, 0xac, 0x0f, 0x00, 0x05, 0xac, 0x0f, 0x00, 0x06, 0xac, 0x0f, 0x00, 0x01, 0x72, 0x14, 0x00, 0x05, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x66, 0x00, 0x08, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x20, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x09, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x94, 0x05, 0x16, 0x00, 0xe8, 0x01, 0x00, 0x00, 0x14, 0x00, 0x03, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x01, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, 0xe2, 0x11, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x18, 0x01, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x6c, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x71, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x76, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x14, 0x00, 0x03, 0x00, 0x08, 0x00, 0x01, 0x00, 0x7b, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x14, 0x00, 0x04, 0x00, 0x08, 0x00, 0x01, 0x00, 0x80, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x14, 0x00, 0x05, 0x00, 0x08, 0x00, 0x01, 0x00, 0x85, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x01, 0x00, 0x8a, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x14, 0x00, 0x07, 0x00, 0x08, 0x00, 0x01, 0x00, 0x8f, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x14, 0x00, 0x08, 0x00, 0x08, 0x00, 0x01, 0x00, 0x94, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x14, 0x00, 0x09, 0x00, 0x08, 0x00, 0x01, 0x00, 0x99, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x01, 0x00, 0x9e, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x1c, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x01, 0x00, 0xa3, 0x09, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x1c, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x01, 0x00, 0xa8, 0x09, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0xa0, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x10, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x37, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x10, 0x00, 0x03, 0x00, 0x08, 0x00, 0x01, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x08, 0x00, 0x01, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x05, 0x00, 0x08, 0x00, 0x01, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x08, 0x00, 0x01, 0x00, 0x78, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x01, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x08, 0x00, 0x01, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x08, 0x00, 0x01, 0x00, 0x68, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x01, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x01, 0x00, 0x1c, 0x02, 0x00, 0x00, 0xa8, 0x03, 0x01, 0x00, 0x14, 0x00, 0x03, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x01, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, 0xe2, 0x11, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, 0xfa, 0xff, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0xa0, 0x71, 0x80, 0x03, 0x00, 0x03, 0x01, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x3c, 0x14, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x50, 0x14, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x64, 0x14, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x1c, 0x00, 0x03, 0x00, 0x08, 0x00, 0x01, 0x00, 0x78, 0x14, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x01, 0x00, 0x8c, 0x14, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x20, 0x00, 0x05, 0x00, 0x08, 0x00, 0x01, 0x00, 0xa0, 0x14, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x20, 0x00, 0x06, 0x00, 0x08, 0x00, 0x01, 0x00, 0xb4, 0x14, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x20, 0x00, 0x07, 0x00, 0x08, 0x00, 0x01, 0x00, 0xc8, 0x14, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x08, 0x00, 0x01, 0x00, 0x7c, 0x15, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x20, 0x00, 0x09, 0x00, 0x08, 0x00, 0x01, 0x00, 0x90, 0x15, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x20, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x01, 0x00, 0xa4, 0x15, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x20, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x01, 0x00, 0xb8, 0x15, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x20, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x01, 0x00, 0xcc, 0x15, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x20, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x01, 0x00, 0xe0, 0x15, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x20, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x01, 0x00, 0xf4, 0x15, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x20, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x01, 0x00, 0x08, 0x16, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, 0x01, 0x00, 0x1c, 0x16, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x20, 0x00, 0x11, 0x00, 0x08, 0x00, 0x01, 0x00, 0x30, 0x16, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x20, 0x00, 0x12, 0x00, 0x08, 0x00, 0x01, 0x00, 0x44, 0x16, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x20, 0x00, 0x13, 0x00, 0x08, 0x00, 0x01, 0x00, 0x58, 0x16, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x08, 0x00, 0x01, 0x00, 0x71, 0x16, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x1c, 0x00, 0x15, 0x00, 0x08, 0x00, 0x01, 0x00, 0x85, 0x16, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x1c, 0x00, 0x16, 0x00, 0x08, 0x00, 0x01, 0x00, 0x99, 0x16, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x1c, 0x00, 0x17, 0x00, 0x08, 0x00, 0x01, 0x00, 0xad, 0x16, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x08, 0x00, 0x01, 0x00, 0xc1, 0x16, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x03, 0x00, 0x08, 0x00, 0x06, 0x00, 0x98, 0x08, 0x00, 0x00, 0x64, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x78, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x08, 0x00, 0x01, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x08, 0x00, 0x01, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x05, 0x00, 0x08, 0x00, 0x01, 0x00, 0x68, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x08, 0x00, 0x01, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x01, 0x00, 0x1c, 0x02, 0x00, 0x00, 0xdc, 0x00, 0x32, 0x00, 0x08, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x05, 0x00, 0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x19, 0x00, 0x00, 0x00, 0x08, 0x00, 0x07, 0x00, 0x25, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x26, 0x00, 0x00, 0x00, 0x08, 0x00, 0x09, 0x00, 0x27, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x28, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0b, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x37, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x39, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x43, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x31, 0x00, 0x00, 0x00, 0x08, 0x00, 0x11, 0x00, 0x41, 0x00, 0x00, 0x00, 0x08, 0x00, 0x12, 0x00, 0x42, 0x00, 0x00, 0x00, 0x08, 0x00, 0x13, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x08, 0x00, 0x14, 0x00, 0x54, 0x00, 0x00, 0x00, 0x08, 0x00, 0x15, 0x00, 0x57, 0x00, 0x00, 0x00, 0x08, 0x00, 0x16, 0x00, 0x55, 0x00, 0x00, 0x00, 0x08, 0x00, 0x17, 0x00, 0x59, 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x19, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1a, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1b, 0x00, 0x30, 0x00, 0x00, 0x00, 0x08, 0x00, 0x6f, 0x00, 0x10, 0x27, 0x00, 0x00, 0x04, 0x00, 0x6c, 0x00, 0x30, 0x04, 0x63, 0x00, 0x04, 0x00, 0x00, 0x00, 0x84, 0x00, 0x01, 0x00, 0x06, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x40, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x50, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x60, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x70, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x02, 0x00, 0x06, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x40, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x50, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x60, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x70, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x03, 0x00, 0x06, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x40, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x50, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x60, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x70, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x04, 0x00, 0x06, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x40, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x50, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x60, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x70, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x06, 0x00, 0x84, 0x00, 0x07, 0x00, 0x06, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x40, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x50, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x60, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x70, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x08, 0x00, 0x06, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x40, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x50, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x60, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x70, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x09, 0x00, 0x06, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x40, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x50, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x60, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x70, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x40, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x50, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x60, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x70, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x40, 0x01, 0x64, 0x00, 0x04, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x00, 0x06, 0x00, 0x65, 0x00, 0x40, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x06, 0x00, 0x65, 0x00, 0x40, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x03, 0x00, 0x06, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x40, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x04, 0x00, 0x06, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x40, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x06, 0x00, 0x1c, 0x00, 0x07, 0x00, 0x06, 0x00, 0x65, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x14, 0x00, 0x08, 0x00, 0x06, 0x00, 0x65, 0x00, 0x40, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x09, 0x00, 0x06, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0x40, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x65, 0x00, 0x40, 0x00, 0x00, 0x00, 0x06, 0x00, 0x65, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x76, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x07, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x09, 0x00, 0x14, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x12, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x79, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x06, 0x00, 0x60, 0x00, 0x78, 0x00, 0x5c, 0x00, 0x01, 0x00, 0x48, 0x00, 0x01, 0x00, 0x14, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x1c, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x08, 0x00, 0x04, 0x00, 0x09, 0x00, 0x14, 0x00, 0x03, 0x00, 0x08, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x8f, 0x00, 0xe3, 0x1a, 0x00, 0x07, 0x1e, 0x00, 0x94, 0x00, 0x63, 0x48, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xa9, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x0c, 0x00, 0xaa, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40}; const char kIPV4Address0[] = "192.168.10.20"; const char kIPV4Address1[] = "1.2.3.4"; const char kIPV6Address0[] = "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210"; const char kIPV6Address1[] = "1080:0:0:0:8:800:200C:417A"; #if !defined(DISABLE_WAKE_ON_WIFI) // 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}; // 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. const uint8_t kIPV4MaskBytes[] = {0x00, 0x00, 0x00, 0x3c}; const uint8_t kIPV6MaskBytes[] = {0x00, 0x00, 0xc0, 0xff, 0x3f}; const uint8_t kIPV4Address0Bytes[] = {0xc0, 0xa8, 0x0a, 0x14}; const uint8_t kIPV4Address1Bytes[] = {0x01, 0x02, 0x03, 0x04}; const uint8_t kIPV6Address0Bytes[] = {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}; const uint8_t kIPV6Address1Bytes[] = {0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x20, 0x0c, 0x41, 0x7a}; const char kIPV6Address2[] = "1080::8:800:200C:417A"; const uint8_t kIPV6Address2Bytes[] = {0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x20, 0x0c, 0x41, 0x7a}; const char kIPV6Address3[] = "FF01::101"; const uint8_t kIPV6Address3Bytes[] = {0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01}; const char kIPV6Address4[] = "::1"; const uint8_t kIPV6Address4Bytes[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; const char kIPV6Address5[] = "::"; const uint8_t kIPV6Address5Bytes[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const char kIPV6Address6[] = "0:0:0:0:0:FFFF:129.144.52.38"; const uint8_t kIPV6Address6Bytes[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x81, 0x90, 0x34, 0x26}; const char kIPV6Address7[] = "::DEDE:190.144.52.38"; const uint8_t kIPV6Address7Bytes[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xde, 0xbe, 0x90, 0x34, 0x26}; const uint32_t kNewWiphyNlMsg_MaxPatterns = 20; const uint32_t kNewWiphyNlMsg_MaxSSIDs = 11; const int kNewWiphyNlMsg_PattSupportOffset = 3300; const int kNewWiphyNlMsg_WowlanTrigNetDetectAttributeOffset = 3316; const int kNewWiphyNlMsg_WowlanTrigDisconnectAttributeOffset = 3268; const uint32_t kSSID1FreqMatches[] = {2412, 2437, 2462, 5180, 5240, 5745, 5805, 5825}; const uint32_t kWakeReasonNlMsg_WiphyIndex = 0; // NL80211_CMD_GET_WOWLAN message with nlmsg_type 0x16, which is different from // kNl80211FamilyId (0x13). const uint8_t kWrongMessageTypeNlMsg[] = { 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x57, 0x40, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00}; // Bytes representing a NL80211_CMD_SET_WOWLAN reporting that the system woke // up because of a reason other than wake on WiFi. const uint8_t kWakeReasonUnsupportedNlMsg[] = { 0x30, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00}; // Bytes representing a NL80211_CMD_SET_WOWLAN reporting that the system woke // up because of a disconnect. const uint8_t kWakeReasonDisconnectNlMsg[] = { 0x38, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x75, 0x00, 0x04, 0x00, 0x02, 0x00}; // Bytes representing a NL80211_CMD_SET_WOWLAN reporting that the system woke // up because of a a match with packet pattern index // kWakeReasonPatternNlMsg_PattIndex. const uint8_t kWakeReasonPatternNlMsg[] = { 0xac, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x75, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x62, 0x00, 0x00, 0x00, 0x66, 0x00, 0x0c, 0x00, 0x6c, 0x29, 0x95, 0x16, 0x54, 0x68, 0x6c, 0x71, 0xd9, 0x8b, 0x3c, 0x6c, 0x08, 0x00, 0x45, 0x00, 0x00, 0x54, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0xb7, 0xdd, 0xc0, 0xa8, 0x00, 0xfe, 0xc0, 0xa8, 0x00, 0x7d, 0x08, 0x00, 0x3f, 0x51, 0x28, 0x64, 0x00, 0x01, 0xb1, 0x0b, 0xd0, 0x54, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x16, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x00, 0x00}; const uint32_t kWakeReasonPatternNlMsg_PattIndex = 0; #endif // DISABLE_WAKE_ON_WIFI } // namespace class WakeOnWiFiTest : public ::testing::Test { public: WakeOnWiFiTest() : metrics_(nullptr) {} virtual ~WakeOnWiFiTest() {} virtual void SetUp() { Nl80211Message::SetMessageType(kNl80211FamilyId); // Assume our NIC has reported its wiphy index, and that it supports wake // all wake triggers. wake_on_wifi_->wiphy_index_received_ = true; wake_on_wifi_->wake_on_wifi_triggers_supported_.insert( WakeOnWiFi::kWakeTriggerPattern); wake_on_wifi_->wake_on_wifi_triggers_supported_.insert( WakeOnWiFi::kWakeTriggerDisconnect); wake_on_wifi_->wake_on_wifi_triggers_supported_.insert( WakeOnWiFi::kWakeTriggerSSID); // By default our tests assume that the NIC supports more SSIDs than // whitelisted SSIDs. wake_on_wifi_->wake_on_wifi_max_ssids_ = 999; wake_on_wifi_->dark_resume_history_.time_ = &time_; ON_CALL(netlink_manager_, SendNl80211Message(_, _, _, _)) .WillByDefault(Return(true)); } void SetWakeOnWiFiMaxSSIDs(uint32_t max_ssids) { wake_on_wifi_->wake_on_wifi_max_ssids_ = max_ssids; } void EnableWakeOnWiFiFeaturesPacket() { wake_on_wifi_->wake_on_wifi_features_enabled_ = kWakeOnWiFiFeaturesEnabledPacket; } void EnableWakeOnWiFiFeaturesDarkConnect() { wake_on_wifi_->wake_on_wifi_features_enabled_ = kWakeOnWiFiFeaturesEnabledDarkConnect; } void EnableWakeOnWiFiFeaturesPacketDarkConnect() { wake_on_wifi_->wake_on_wifi_features_enabled_ = kWakeOnWiFiFeaturesEnabledPacketDarkConnect; } void SetWakeOnWiFiFeaturesNotSupported() { wake_on_wifi_->wake_on_wifi_features_enabled_ = kWakeOnWiFiFeaturesEnabledNotSupported; } void DisableWakeOnWiFiFeatures() { wake_on_wifi_->wake_on_wifi_features_enabled_ = kWakeOnWiFiFeaturesEnabledNone; } void AddWakeOnPacketConnection(const string& ip_endpoint, Error* error) { wake_on_wifi_->AddWakeOnPacketConnection(ip_endpoint, error); } void RemoveWakeOnPacketConnection(const string& ip_endpoint, Error* error) { wake_on_wifi_->RemoveWakeOnPacketConnection(ip_endpoint, error); } void RemoveAllWakeOnPacketConnections(Error* error) { wake_on_wifi_->RemoveAllWakeOnPacketConnections(error); } bool CreateIPAddressPatternAndMask(const IPAddress& ip_addr, ByteString* pattern, ByteString* mask) { return WakeOnWiFi::CreateIPAddressPatternAndMask(ip_addr, pattern, mask); } bool ConfigureWiphyIndex(Nl80211Message* msg, int32_t index) { return WakeOnWiFi::ConfigureWiphyIndex(msg, index); } bool ConfigureDisableWakeOnWiFiMessage(SetWakeOnPacketConnMessage* msg, uint32_t wiphy_index, Error* error) { return WakeOnWiFi::ConfigureDisableWakeOnWiFiMessage(msg, wiphy_index, error); } bool WakeOnWiFiSettingsMatch(const Nl80211Message& msg, const set<WakeOnWiFi::WakeOnWiFiTrigger>& trigs, const IPAddressStore& addrs, uint32_t net_detect_scan_period_seconds, const vector<ByteString>& ssid_whitelist) { return WakeOnWiFi::WakeOnWiFiSettingsMatch( msg, trigs, addrs, net_detect_scan_period_seconds, ssid_whitelist); } bool ConfigureSetWakeOnWiFiSettingsMessage( SetWakeOnPacketConnMessage* msg, const set<WakeOnWiFi::WakeOnWiFiTrigger>& trigs, const IPAddressStore& addrs, uint32_t wiphy_index, uint32_t net_detect_scan_period_seconds, const vector<ByteString>& ssid_whitelist, Error* error) { return WakeOnWiFi::ConfigureSetWakeOnWiFiSettingsMessage( msg, trigs, addrs, wiphy_index, net_detect_scan_period_seconds, ssid_whitelist, error); } void RequestWakeOnPacketSettings() { wake_on_wifi_->RequestWakeOnPacketSettings(); } void VerifyWakeOnWiFiSettings(const Nl80211Message& nl80211_message) { wake_on_wifi_->VerifyWakeOnWiFiSettings(nl80211_message); } size_t GetWakeOnWiFiMaxPatterns() { return wake_on_wifi_->wake_on_wifi_max_patterns_; } uint32_t GetWakeOnWiFiMaxSSIDs() { return wake_on_wifi_->wake_on_wifi_max_ssids_; } void SetWakeOnWiFiMaxPatterns(size_t max_patterns) { wake_on_wifi_->wake_on_wifi_max_patterns_ = max_patterns; } void ApplyWakeOnWiFiSettings() { wake_on_wifi_->ApplyWakeOnWiFiSettings(); } void DisableWakeOnWiFi() { wake_on_wifi_->DisableWakeOnWiFi(); } set<WakeOnWiFi::WakeOnWiFiTrigger>* GetWakeOnWiFiTriggers() { return &wake_on_wifi_->wake_on_wifi_triggers_; } set<WakeOnWiFi::WakeOnWiFiTrigger>* GetWakeOnWiFiTriggersSupported() { return &wake_on_wifi_->wake_on_wifi_triggers_supported_; } void ClearWakeOnWiFiTriggersSupported() { wake_on_wifi_->wake_on_wifi_triggers_supported_.clear(); } IPAddressStore* GetWakeOnPacketConnections() { return &wake_on_wifi_->wake_on_packet_connections_; } void RetrySetWakeOnPacketConnections() { wake_on_wifi_->RetrySetWakeOnPacketConnections(); } void SetSuspendActionsDoneCallback() { wake_on_wifi_->suspend_actions_done_callback_ = Bind(&WakeOnWiFiTest::DoneCallback, Unretained(this)); } void ResetSuspendActionsDoneCallback() { wake_on_wifi_->suspend_actions_done_callback_.Reset(); } bool SuspendActionsCallbackIsNull() { return wake_on_wifi_->suspend_actions_done_callback_.is_null(); } void RunSuspendActionsCallback(const Error& error) { wake_on_wifi_->suspend_actions_done_callback_.Run(error); } int GetNumSetWakeOnPacketRetries() { return wake_on_wifi_->num_set_wake_on_packet_retries_; } void SetNumSetWakeOnPacketRetries(int retries) { wake_on_wifi_->num_set_wake_on_packet_retries_ = retries; } void OnBeforeSuspend(bool is_connected, const vector<ByteString>& ssid_whitelist, bool have_dhcp_lease, uint32_t time_to_next_lease_renewal) { ResultCallback done_callback( Bind(&WakeOnWiFiTest::DoneCallback, Unretained(this))); Closure renew_dhcp_lease_callback( Bind(&WakeOnWiFiTest::RenewDHCPLeaseCallback, Unretained(this))); Closure remove_supplicant_networks_callback(Bind( &WakeOnWiFiTest::RemoveSupplicantNetworksCallback, Unretained(this))); wake_on_wifi_->OnBeforeSuspend(is_connected, ssid_whitelist, done_callback, renew_dhcp_lease_callback, remove_supplicant_networks_callback, have_dhcp_lease, time_to_next_lease_renewal); } void OnDarkResume(bool is_connected, const vector<ByteString>& ssid_whitelist) { ResultCallback done_callback( Bind(&WakeOnWiFiTest::DoneCallback, Unretained(this))); Closure renew_dhcp_lease_callback( Bind(&WakeOnWiFiTest::RenewDHCPLeaseCallback, Unretained(this))); WakeOnWiFi::InitiateScanCallback initiate_scan_callback( Bind(&WakeOnWiFiTest::InitiateScanCallback, Unretained(this))); Closure remove_supplicant_networks_callback(Bind( &WakeOnWiFiTest::RemoveSupplicantNetworksCallback, Unretained(this))); wake_on_wifi_->OnDarkResume( is_connected, ssid_whitelist, done_callback, renew_dhcp_lease_callback, initiate_scan_callback, remove_supplicant_networks_callback); } void OnAfterResume() { wake_on_wifi_->OnAfterResume(); } void BeforeSuspendActions(bool is_connected, bool start_lease_renewal_timer, uint32_t time_to_next_lease_renewal) { SetDarkResumeActionsTimeOutCallback(); EXPECT_FALSE(DarkResumeActionsTimeOutCallbackIsCancelled()); EXPECT_CALL(metrics_, NotifyBeforeSuspendActions(is_connected, GetInDarkResume())); Closure remove_supplicant_networks_callback(Bind( &WakeOnWiFiTest::RemoveSupplicantNetworksCallback, Unretained(this))); wake_on_wifi_->BeforeSuspendActions(is_connected, start_lease_renewal_timer, time_to_next_lease_renewal, remove_supplicant_networks_callback); EXPECT_TRUE(DarkResumeActionsTimeOutCallbackIsCancelled()); } void OnConnectedAndReachable(bool start_lease_renewal_timer, uint32_t time_to_next_lease_renewal) { wake_on_wifi_->OnConnectedAndReachable(start_lease_renewal_timer, time_to_next_lease_renewal); } void SetInDarkResume(bool val) { wake_on_wifi_->in_dark_resume_ = val; } bool GetInDarkResume() { return wake_on_wifi_->in_dark_resume_; } void SetWiphyIndexReceivedToFalse() { wake_on_wifi_->wiphy_index_received_ = false; } void SetWiphyIndex(uint32_t wiphy_index) { wake_on_wifi_->wiphy_index_ = wiphy_index; } void ParseWakeOnWiFiCapabilities(const Nl80211Message& nl80211_message) { wake_on_wifi_->ParseWakeOnWiFiCapabilities(nl80211_message); } bool SetWakeOnWiFiFeaturesEnabled(const std::string& enabled, Error* error) { return wake_on_wifi_->SetWakeOnWiFiFeaturesEnabled(enabled, error); } const string& GetWakeOnWiFiFeaturesEnabled() { return wake_on_wifi_->wake_on_wifi_features_enabled_; } void SetDarkResumeActionsTimeOutCallback() { wake_on_wifi_->dark_resume_actions_timeout_callback_.Reset(Bind( &WakeOnWiFiTest::DarkResumeActionsTimeoutCallback, Unretained(this))); } bool DarkResumeActionsTimeOutCallbackIsCancelled() { return wake_on_wifi_->dark_resume_actions_timeout_callback_.IsCancelled(); } void StartDHCPLeaseRenewalTimer() { wake_on_wifi_->dhcp_lease_renewal_timer_.Start( FROM_HERE, base::TimeDelta::FromSeconds(kTimeToNextLeaseRenewalLong), Bind(&WakeOnWiFiTest::OnTimerWakeDoNothing, Unretained(this))); } void StartWakeToScanTimer() { wake_on_wifi_->wake_to_scan_timer_.Start( FROM_HERE, base::TimeDelta::FromSeconds(kTimeToNextLeaseRenewalLong), Bind(&WakeOnWiFiTest::OnTimerWakeDoNothing, Unretained(this))); } void StopDHCPLeaseRenewalTimer() { wake_on_wifi_->dhcp_lease_renewal_timer_.Stop(); } void StopWakeToScanTimer() { wake_on_wifi_->wake_to_scan_timer_.Stop(); } bool DHCPLeaseRenewalTimerIsRunning() { return wake_on_wifi_->dhcp_lease_renewal_timer_.IsRunning(); } bool WakeToScanTimerIsRunning() { return wake_on_wifi_->wake_to_scan_timer_.IsRunning(); } void SetDarkResumeActionsTimeoutMilliseconds(int64_t timeout) { wake_on_wifi_->DarkResumeActionsTimeoutMilliseconds = timeout; } void InitStateForDarkResume() { SetInDarkResume(true); GetWakeOnPacketConnections()->AddUnique(IPAddress("1.1.1.1")); EnableWakeOnWiFiFeaturesPacketDarkConnect(); SetDarkResumeActionsTimeoutMilliseconds(0); } void SetExpectationsDisconnectedBeforeSuspend() { EXPECT_TRUE(GetWakeOnWiFiTriggers()->empty()); EXPECT_CALL(*this, DoneCallback(_)).Times(0); EXPECT_CALL(*this, RemoveSupplicantNetworksCallback()).Times(1); EXPECT_CALL(netlink_manager_, SendNl80211Message( IsNl80211Command(kNl80211FamilyId, SetWakeOnPacketConnMessage::kCommand), _, _, _)); } void SetExpectationsConnectedBeforeSuspend() { EXPECT_TRUE(GetWakeOnWiFiTriggers()->empty()); EXPECT_CALL(*this, DoneCallback(_)).Times(0); EXPECT_CALL(netlink_manager_, SendNl80211Message( IsNl80211Command(kNl80211FamilyId, SetWakeOnPacketConnMessage::kCommand), _, _, _)); } void VerifyStateConnectedBeforeSuspend() { EXPECT_TRUE(DarkResumeActionsTimeOutCallbackIsCancelled()); EXPECT_FALSE(GetInDarkResume()); EXPECT_EQ(GetWakeOnWiFiTriggers()->size(), 2); EXPECT_TRUE( GetWakeOnWiFiTriggers()->find(WakeOnWiFi::kWakeTriggerPattern) != GetWakeOnWiFiTriggers()->end()); EXPECT_TRUE( GetWakeOnWiFiTriggers()->find(WakeOnWiFi::kWakeTriggerDisconnect) != GetWakeOnWiFiTriggers()->end()); } void VerifyStateDisconnectedBeforeSuspend() { EXPECT_TRUE(DarkResumeActionsTimeOutCallbackIsCancelled()); EXPECT_FALSE(GetInDarkResume()); EXPECT_EQ(GetWakeOnWiFiTriggers()->size(), 1); EXPECT_FALSE( GetWakeOnWiFiTriggers()->find(WakeOnWiFi::kWakeTriggerPattern) != GetWakeOnWiFiTriggers()->end()); EXPECT_TRUE(GetWakeOnWiFiTriggers()->find(WakeOnWiFi::kWakeTriggerSSID) != GetWakeOnWiFiTriggers()->end()); } void ReportConnectedToServiceAfterWake(bool is_connected) { wake_on_wifi_->ReportConnectedToServiceAfterWake(is_connected); } void OnNoAutoConnectableServicesAfterScan( const vector<ByteString>& ssid_whitelist) { Closure remove_supplicant_networks_callback(Bind( &WakeOnWiFiTest::RemoveSupplicantNetworksCallback, Unretained(this))); WakeOnWiFi::InitiateScanCallback initiate_scan_callback( Bind(&WakeOnWiFiTest::InitiateScanCallback, Unretained(this))); wake_on_wifi_->OnNoAutoConnectableServicesAfterScan( ssid_whitelist, remove_supplicant_networks_callback, initiate_scan_callback); } EventHistory* GetDarkResumeHistory() { return &wake_on_wifi_->dark_resume_history_; } void SetNetDetectScanPeriodSeconds(uint32_t period) { wake_on_wifi_->net_detect_scan_period_seconds_ = period; } void AddSSIDToWhitelist(const uint8_t* ssid, int num_bytes, vector<ByteString>* whitelist) { vector<uint8_t> ssid_vector(ssid, ssid + num_bytes); whitelist->push_back(ByteString(ssid_vector)); } vector<ByteString>* GetWakeOnSSIDWhitelist() { return &wake_on_wifi_->wake_on_ssid_whitelist_; } void OnWakeupReasonReceived(const NetlinkMessage& netlink_message) { wake_on_wifi_->OnWakeupReasonReceived(netlink_message); } WiFi::FreqSet ParseWakeOnSSIDResults(AttributeListConstRefPtr results_list) { return wake_on_wifi_->ParseWakeOnSSIDResults(results_list); } NetlinkMessage::MessageContext GetWakeupReportMsgContext() { NetlinkMessage::MessageContext context; context.nl80211_cmd = NL80211_CMD_SET_WOWLAN; context.is_broadcast = true; return context; } void SetLastWakeReason(WakeOnWiFi::WakeOnWiFiTrigger reason) { wake_on_wifi_->last_wake_reason_ = reason; } WakeOnWiFi::WakeOnWiFiTrigger GetLastWakeReason() { return wake_on_wifi_->last_wake_reason_; } void OnScanStarted(bool is_active_scan) { wake_on_wifi_->OnScanStarted(is_active_scan); } const WiFi::FreqSet& GetLastSSIDMatchFreqs() { return wake_on_wifi_->last_ssid_match_freqs_; } void AddResultToLastSSIDResults() { wake_on_wifi_->last_ssid_match_freqs_.insert(1); } void InitiateScanInDarkResume(const WiFi::FreqSet& freqs) { wake_on_wifi_->InitiateScanInDarkResume( Bind(&WakeOnWiFiTest::InitiateScanCallback, Unretained(this)), freqs); } int GetDarkResumeScanRetriesLeft() { return wake_on_wifi_->dark_resume_scan_retries_left_; } void SetDarkResumeScanRetriesLeft(int retries) { wake_on_wifi_->dark_resume_scan_retries_left_ = retries; } Timestamp GetTimestampBootTime(int boottime_seconds) { struct timeval monotonic = {.tv_sec = 0, .tv_usec = 0}; struct timeval boottime = {.tv_sec = boottime_seconds, .tv_usec = 0}; return Timestamp(monotonic, boottime, ""); } MOCK_METHOD1(DoneCallback, void(const Error &)); MOCK_METHOD0(RenewDHCPLeaseCallback, void(void)); MOCK_METHOD1(InitiateScanCallback, void(const WiFi::FreqSet&)); MOCK_METHOD0(RemoveSupplicantNetworksCallback, void(void)); MOCK_METHOD0(DarkResumeActionsTimeoutCallback, void(void)); MOCK_METHOD0(OnTimerWakeDoNothing, void(void)); MOCK_METHOD1(RecordDarkResumeWakeReasonCallback, void(const string& wake_reason)); protected: NiceMockControl control_interface_; MockMetrics metrics_; MockNetlinkManager netlink_manager_; MockTime time_; std::unique_ptr<WakeOnWiFi> wake_on_wifi_; }; class WakeOnWiFiTestWithDispatcher : public WakeOnWiFiTest { public: WakeOnWiFiTestWithDispatcher() : WakeOnWiFiTest() { wake_on_wifi_.reset( new WakeOnWiFi(&netlink_manager_, &dispatcher_, &metrics_, Bind(&WakeOnWiFiTest::RecordDarkResumeWakeReasonCallback, Unretained(this)))); } virtual ~WakeOnWiFiTestWithDispatcher() {} protected: EventDispatcherForTest dispatcher_; }; class WakeOnWiFiTestWithMockDispatcher : public WakeOnWiFiTest { public: WakeOnWiFiTestWithMockDispatcher() : WakeOnWiFiTest() { wake_on_wifi_.reset( new WakeOnWiFi(&netlink_manager_, &mock_dispatcher_, &metrics_, Bind(&WakeOnWiFiTest::RecordDarkResumeWakeReasonCallback, Unretained(this)))); } virtual ~WakeOnWiFiTestWithMockDispatcher() {} protected: // TODO(zqiu): message loop is needed by AlarmTimer, should restructure the // code so that it can be mocked out. base::MessageLoopForIO message_loop_; MockEventDispatcher mock_dispatcher_; }; ByteString CreatePattern(const unsigned char* prefix, size_t prefix_len, const unsigned char* addr, size_t addr_len) { ByteString result(prefix, prefix_len); result.Append(ByteString(addr, addr_len)); return result; } #if !defined(DISABLE_WAKE_ON_WIFI) TEST_F(WakeOnWiFiTestWithMockDispatcher, CreateIPAddressPatternAndMask) { ByteString pattern; ByteString mask; ByteString expected_pattern; CreateIPAddressPatternAndMask(IPAddress(kIPV4Address0), &pattern, &mask); expected_pattern = CreatePattern(kIPV4PatternPrefix, sizeof(kIPV4PatternPrefix), kIPV4Address0Bytes, sizeof(kIPV4Address0Bytes)); EXPECT_TRUE(pattern.Equals(expected_pattern)); EXPECT_TRUE(mask.Equals(ByteString(kIPV4MaskBytes, sizeof(kIPV4MaskBytes)))); pattern.Clear(); expected_pattern.Clear(); mask.Clear(); CreateIPAddressPatternAndMask(IPAddress(kIPV4Address1), &pattern, &mask); expected_pattern = CreatePattern(kIPV4PatternPrefix, sizeof(kIPV4PatternPrefix), kIPV4Address1Bytes, sizeof(kIPV4Address1Bytes)); EXPECT_TRUE(pattern.Equals(expected_pattern)); EXPECT_TRUE(mask.Equals(ByteString(kIPV4MaskBytes, sizeof(kIPV4MaskBytes)))); pattern.Clear(); expected_pattern.Clear(); mask.Clear(); CreateIPAddressPatternAndMask(IPAddress(kIPV6Address0), &pattern, &mask); expected_pattern = CreatePattern(kIPV6PatternPrefix, sizeof(kIPV6PatternPrefix), kIPV6Address0Bytes, sizeof(kIPV6Address0Bytes)); EXPECT_TRUE(pattern.Equals(expected_pattern)); EXPECT_TRUE(mask.Equals(ByteString(kIPV6MaskBytes, sizeof(kIPV6MaskBytes)))); pattern.Clear(); expected_pattern.Clear(); mask.Clear(); CreateIPAddressPatternAndMask(IPAddress(kIPV6Address1), &pattern, &mask); expected_pattern = CreatePattern(kIPV6PatternPrefix, sizeof(kIPV6PatternPrefix), kIPV6Address1Bytes, sizeof(kIPV6Address1Bytes)); EXPECT_TRUE(pattern.Equals(expected_pattern)); EXPECT_TRUE(mask.Equals(ByteString(kIPV6MaskBytes, sizeof(kIPV6MaskBytes)))); pattern.Clear(); expected_pattern.Clear(); mask.Clear(); CreateIPAddressPatternAndMask(IPAddress(kIPV6Address2), &pattern, &mask); expected_pattern = CreatePattern(kIPV6PatternPrefix, sizeof(kIPV6PatternPrefix), kIPV6Address2Bytes, sizeof(kIPV6Address2Bytes)); EXPECT_TRUE(pattern.Equals(expected_pattern)); EXPECT_TRUE(mask.Equals(ByteString(kIPV6MaskBytes, sizeof(kIPV6MaskBytes)))); pattern.Clear(); expected_pattern.Clear(); mask.Clear(); CreateIPAddressPatternAndMask(IPAddress(kIPV6Address3), &pattern, &mask); expected_pattern = CreatePattern(kIPV6PatternPrefix, sizeof(kIPV6PatternPrefix), kIPV6Address3Bytes, sizeof(kIPV6Address3Bytes)); EXPECT_TRUE(pattern.Equals(expected_pattern)); EXPECT_TRUE(mask.Equals(ByteString(kIPV6MaskBytes, sizeof(kIPV6MaskBytes)))); pattern.Clear(); expected_pattern.Clear(); mask.Clear(); CreateIPAddressPatternAndMask(IPAddress(kIPV6Address4), &pattern, &mask); expected_pattern = CreatePattern(kIPV6PatternPrefix, sizeof(kIPV6PatternPrefix), kIPV6Address4Bytes, sizeof(kIPV6Address4Bytes)); EXPECT_TRUE(pattern.Equals(expected_pattern)); EXPECT_TRUE(mask.Equals(ByteString(kIPV6MaskBytes, sizeof(kIPV6MaskBytes)))); pattern.Clear(); expected_pattern.Clear(); mask.Clear(); CreateIPAddressPatternAndMask(IPAddress(kIPV6Address5), &pattern, &mask); expected_pattern = CreatePattern(kIPV6PatternPrefix, sizeof(kIPV6PatternPrefix), kIPV6Address5Bytes, sizeof(kIPV6Address5Bytes)); EXPECT_TRUE(pattern.Equals(expected_pattern)); EXPECT_TRUE(mask.Equals(ByteString(kIPV6MaskBytes, sizeof(kIPV6MaskBytes)))); pattern.Clear(); expected_pattern.Clear(); mask.Clear(); CreateIPAddressPatternAndMask(IPAddress(kIPV6Address6), &pattern, &mask); expected_pattern = CreatePattern(kIPV6PatternPrefix, sizeof(kIPV6PatternPrefix), kIPV6Address6Bytes, sizeof(kIPV6Address6Bytes)); EXPECT_TRUE(pattern.Equals(expected_pattern)); EXPECT_TRUE(mask.Equals(ByteString(kIPV6MaskBytes, sizeof(kIPV6MaskBytes)))); pattern.Clear(); expected_pattern.Clear(); mask.Clear(); CreateIPAddressPatternAndMask(IPAddress(kIPV6Address7), &pattern, &mask); expected_pattern = CreatePattern(kIPV6PatternPrefix, sizeof(kIPV6PatternPrefix), kIPV6Address7Bytes, sizeof(kIPV6Address7Bytes)); EXPECT_TRUE(pattern.Equals(expected_pattern)); EXPECT_TRUE(mask.Equals(ByteString(kIPV6MaskBytes, sizeof(kIPV6MaskBytes)))); } TEST_F(WakeOnWiFiTestWithMockDispatcher, ConfigureWiphyIndex) { SetWakeOnPacketConnMessage msg; uint32_t value; EXPECT_FALSE( msg.attributes()->GetU32AttributeValue(NL80211_ATTR_WIPHY, &value)); ConfigureWiphyIndex(&msg, 137); EXPECT_TRUE( msg.attributes()->GetU32AttributeValue(NL80211_ATTR_WIPHY, &value)); EXPECT_EQ(value, 137); } TEST_F(WakeOnWiFiTestWithMockDispatcher, ConfigureDisableWakeOnWiFiMessage) { SetWakeOnPacketConnMessage msg; Error e; uint32_t value; EXPECT_FALSE( msg.attributes()->GetU32AttributeValue(NL80211_ATTR_WIPHY, &value)); ConfigureDisableWakeOnWiFiMessage(&msg, 57, &e); EXPECT_EQ(e.type(), Error::Type::kSuccess); EXPECT_TRUE( msg.attributes()->GetU32AttributeValue(NL80211_ATTR_WIPHY, &value)); EXPECT_EQ(value, 57); } TEST_F(WakeOnWiFiTestWithMockDispatcher, WakeOnWiFiSettingsMatch) { IPAddressStore all_addresses; set<WakeOnWiFi::WakeOnWiFiTrigger> trigs; vector<ByteString> whitelist; const uint32_t interval = kNetDetectScanIntervalSeconds; GetWakeOnPacketConnMessage msg0; NetlinkPacket packet0(kResponseNoIPAddresses, sizeof(kResponseNoIPAddresses)); msg0.InitFromPacket(&packet0, NetlinkMessage::MessageContext()); EXPECT_TRUE( WakeOnWiFiSettingsMatch(msg0, trigs, all_addresses, interval, whitelist)); trigs.insert(WakeOnWiFi::kWakeTriggerPattern); all_addresses.AddUnique( IPAddress(string(kIPV4Address0, sizeof(kIPV4Address0)))); GetWakeOnPacketConnMessage msg1; NetlinkPacket packet1(kResponseIPV40, sizeof(kResponseIPV40)); msg1.InitFromPacket(&packet1, NetlinkMessage::MessageContext()); EXPECT_TRUE( WakeOnWiFiSettingsMatch(msg1, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg0, trigs, all_addresses, interval, whitelist)); // Test matching of wake on disconnect trigger. trigs.insert(WakeOnWiFi::kWakeTriggerDisconnect); GetWakeOnPacketConnMessage msg2; NetlinkPacket packet2( kResponseIPV40WakeOnDisconnect, sizeof(kResponseIPV40WakeOnDisconnect)); msg2.InitFromPacket(&packet2, NetlinkMessage::MessageContext()); EXPECT_TRUE( WakeOnWiFiSettingsMatch(msg2, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg1, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg0, trigs, all_addresses, interval, whitelist)); trigs.erase(WakeOnWiFi::kWakeTriggerDisconnect); all_addresses.AddUnique( IPAddress(string(kIPV4Address1, sizeof(kIPV4Address1)))); GetWakeOnPacketConnMessage msg3; NetlinkPacket packet3(kResponseIPV401, sizeof(kResponseIPV401)); msg3.InitFromPacket(&packet3, NetlinkMessage::MessageContext()); EXPECT_TRUE( WakeOnWiFiSettingsMatch(msg3, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg2, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg1, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg0, trigs, all_addresses, interval, whitelist)); all_addresses.AddUnique( IPAddress(string(kIPV6Address0, sizeof(kIPV6Address0)))); GetWakeOnPacketConnMessage msg4; NetlinkPacket packet4(kResponseIPV401IPV60, sizeof(kResponseIPV401IPV60)); msg4.InitFromPacket(&packet4, NetlinkMessage::MessageContext()); EXPECT_TRUE( WakeOnWiFiSettingsMatch(msg4, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg3, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg2, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg1, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg0, trigs, all_addresses, interval, whitelist)); all_addresses.AddUnique( IPAddress(string(kIPV6Address1, sizeof(kIPV6Address1)))); GetWakeOnPacketConnMessage msg5; NetlinkPacket packet5(kResponseIPV401IPV601, sizeof(kResponseIPV401IPV601)); msg5.InitFromPacket(&packet5, NetlinkMessage::MessageContext()); EXPECT_TRUE( WakeOnWiFiSettingsMatch(msg5, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg4, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg3, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg2, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg1, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg0, trigs, all_addresses, interval, whitelist)); // Test matching of wake on SSID trigger. all_addresses.Clear(); trigs.clear(); trigs.insert(WakeOnWiFi::kWakeTriggerSSID); AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); AddSSIDToWhitelist(kSSIDBytes2, sizeof(kSSIDBytes2), &whitelist); GetWakeOnPacketConnMessage msg6; NetlinkPacket packet6(kResponseWakeOnSSID, sizeof(kResponseWakeOnSSID)); msg6.InitFromPacket(&packet6, NetlinkMessage::MessageContext()); EXPECT_TRUE( WakeOnWiFiSettingsMatch(msg6, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg5, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg4, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg3, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg2, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg1, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg0, trigs, all_addresses, interval, whitelist)); // Test that we get a mismatch if triggers are present in the message that we // don't expect. trigs.clear(); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg6, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg5, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg4, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg3, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg2, trigs, all_addresses, interval, whitelist)); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg1, trigs, all_addresses, interval, whitelist)); } TEST_F(WakeOnWiFiTestWithMockDispatcher, ConfigureSetWakeOnWiFiSettingsMessage) { IPAddressStore all_addresses; set<WakeOnWiFi::WakeOnWiFiTrigger> trigs; const int index = 1; // wiphy device number vector<ByteString> whitelist; const uint32_t interval = kNetDetectScanIntervalSeconds; SetWakeOnPacketConnMessage msg0; Error e; trigs.insert(WakeOnWiFi::kWakeTriggerPattern); all_addresses.AddUnique( IPAddress(string(kIPV4Address0, sizeof(kIPV4Address0)))); EXPECT_TRUE(ConfigureSetWakeOnWiFiSettingsMessage( &msg0, trigs, all_addresses, index, interval, whitelist, &e)); EXPECT_TRUE( WakeOnWiFiSettingsMatch(msg0, trigs, all_addresses, interval, whitelist)); SetWakeOnPacketConnMessage msg1; all_addresses.AddUnique( IPAddress(string(kIPV4Address1, sizeof(kIPV4Address1)))); EXPECT_TRUE(ConfigureSetWakeOnWiFiSettingsMessage( &msg1, trigs, all_addresses, index, interval, whitelist, &e)); EXPECT_TRUE( WakeOnWiFiSettingsMatch(msg1, trigs, all_addresses, interval, whitelist)); SetWakeOnPacketConnMessage msg2; all_addresses.AddUnique( IPAddress(string(kIPV6Address0, sizeof(kIPV6Address0)))); EXPECT_TRUE(ConfigureSetWakeOnWiFiSettingsMessage( &msg2, trigs, all_addresses, index, interval, whitelist, &e)); EXPECT_TRUE( WakeOnWiFiSettingsMatch(msg2, trigs, all_addresses, interval, whitelist)); SetWakeOnPacketConnMessage msg3; all_addresses.AddUnique( IPAddress(string(kIPV6Address1, sizeof(kIPV6Address1)))); EXPECT_TRUE(ConfigureSetWakeOnWiFiSettingsMessage( &msg3, trigs, all_addresses, index, interval, whitelist, &e)); EXPECT_TRUE( WakeOnWiFiSettingsMatch(msg3, trigs, all_addresses, interval, whitelist)); SetWakeOnPacketConnMessage msg4; all_addresses.AddUnique( IPAddress(string(kIPV6Address2, sizeof(kIPV6Address2)))); EXPECT_TRUE(ConfigureSetWakeOnWiFiSettingsMessage( &msg4, trigs, all_addresses, index, interval, whitelist, &e)); EXPECT_TRUE( WakeOnWiFiSettingsMatch(msg4, trigs, all_addresses, interval, whitelist)); SetWakeOnPacketConnMessage msg5; all_addresses.AddUnique( IPAddress(string(kIPV6Address3, sizeof(kIPV6Address3)))); EXPECT_TRUE(ConfigureSetWakeOnWiFiSettingsMessage( &msg5, trigs, all_addresses, index, interval, whitelist, &e)); EXPECT_TRUE( WakeOnWiFiSettingsMatch(msg5, trigs, all_addresses, interval, whitelist)); SetWakeOnPacketConnMessage msg6; all_addresses.AddUnique( IPAddress(string(kIPV6Address4, sizeof(kIPV6Address4)))); EXPECT_TRUE(ConfigureSetWakeOnWiFiSettingsMessage( &msg6, trigs, all_addresses, index, interval, whitelist, &e)); EXPECT_TRUE( WakeOnWiFiSettingsMatch(msg6, trigs, all_addresses, interval, whitelist)); SetWakeOnPacketConnMessage msg7; all_addresses.AddUnique( IPAddress(string(kIPV6Address5, sizeof(kIPV6Address5)))); EXPECT_TRUE(ConfigureSetWakeOnWiFiSettingsMessage( &msg7, trigs, all_addresses, index, interval, whitelist, &e)); EXPECT_TRUE( WakeOnWiFiSettingsMatch(msg7, trigs, all_addresses, interval, whitelist)); SetWakeOnPacketConnMessage msg8; all_addresses.AddUnique( IPAddress(string(kIPV6Address6, sizeof(kIPV6Address6)))); EXPECT_TRUE(ConfigureSetWakeOnWiFiSettingsMessage( &msg8, trigs, all_addresses, index, interval, whitelist, &e)); EXPECT_TRUE( WakeOnWiFiSettingsMatch(msg8, trigs, all_addresses, interval, whitelist)); SetWakeOnPacketConnMessage msg9; all_addresses.AddUnique( IPAddress(string(kIPV6Address7, sizeof(kIPV6Address7)))); EXPECT_TRUE(ConfigureSetWakeOnWiFiSettingsMessage( &msg9, trigs, all_addresses, index, interval, whitelist, &e)); EXPECT_TRUE( WakeOnWiFiSettingsMatch(msg9, trigs, all_addresses, interval, whitelist)); SetWakeOnPacketConnMessage msg10; all_addresses.Clear(); trigs.clear(); trigs.insert(WakeOnWiFi::kWakeTriggerSSID); AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); AddSSIDToWhitelist(kSSIDBytes2, sizeof(kSSIDBytes2), &whitelist); EXPECT_TRUE(ConfigureSetWakeOnWiFiSettingsMessage( &msg10, trigs, all_addresses, index, interval, whitelist, &e)); EXPECT_TRUE(WakeOnWiFiSettingsMatch(msg10, trigs, all_addresses, interval, whitelist)); } TEST_F(WakeOnWiFiTestWithMockDispatcher, RequestWakeOnPacketSettings) { EXPECT_CALL( netlink_manager_, SendNl80211Message(IsNl80211Command(kNl80211FamilyId, GetWakeOnPacketConnMessage::kCommand), _, _, _)).Times(1); RequestWakeOnPacketSettings(); } TEST_F(WakeOnWiFiTestWithMockDispatcher, VerifyWakeOnWiFiSettings_NoWakeOnPacketRules) { ScopedMockLog log; // Create an Nl80211 response to a NL80211_CMD_GET_WOWLAN request // indicating that there are no wake-on-packet rules programmed into the NIC. GetWakeOnPacketConnMessage msg; NetlinkPacket packet(kResponseNoIPAddresses, sizeof(kResponseNoIPAddresses)); msg.InitFromPacket(&packet, NetlinkMessage::MessageContext()); // Successful verification and consequent invocation of callback. SetSuspendActionsDoneCallback(); ScopeLogger::GetInstance()->EnableScopesByName("wifi"); ScopeLogger::GetInstance()->set_verbose_level(2); EXPECT_TRUE(GetWakeOnPacketConnections()->Empty()); EXPECT_FALSE(SuspendActionsCallbackIsNull()); EXPECT_CALL(*this, DoneCallback(ErrorTypeIs(Error::kSuccess))).Times(1); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); EXPECT_CALL( log, Log(_, _, HasSubstr("Wake on WiFi settings successfully verified"))); EXPECT_CALL(metrics_, NotifyVerifyWakeOnWiFiSettingsResult( Metrics::kVerifyWakeOnWiFiSettingsResultSuccess)); VerifyWakeOnWiFiSettings(msg); // Suspend action callback cleared after being invoked. EXPECT_TRUE(SuspendActionsCallbackIsNull()); ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); ScopeLogger::GetInstance()->set_verbose_level(0); // Unsuccessful verification if locally stored settings do not match. GetWakeOnPacketConnections()->AddUnique(IPAddress("1.1.1.1")); GetWakeOnWiFiTriggers()->insert(WakeOnWiFi::kWakeTriggerPattern); EXPECT_CALL(log, Log(logging::LOG_ERROR, _, HasSubstr( " failed: discrepancy between wake-on-packet settings on " "NIC and those in local data structure detected"))); EXPECT_CALL(metrics_, NotifyVerifyWakeOnWiFiSettingsResult( Metrics::kVerifyWakeOnWiFiSettingsResultFailure)); VerifyWakeOnWiFiSettings(msg); } TEST_F(WakeOnWiFiTestWithMockDispatcher, VerifyWakeOnWiFiSettings_WakeOnPatternAndDisconnectRules) { ScopedMockLog log; // Create a non-trivial Nl80211 response to a NL80211_CMD_GET_WOWLAN request // indicating that that the NIC wakes on packets from 192.168.10.20 and on // disconnects. GetWakeOnPacketConnMessage msg; NetlinkPacket packet( kResponseIPV40WakeOnDisconnect, sizeof(kResponseIPV40WakeOnDisconnect)); msg.InitFromPacket(&packet, NetlinkMessage::MessageContext()); // Successful verification and consequent invocation of callback. SetSuspendActionsDoneCallback(); EXPECT_FALSE(SuspendActionsCallbackIsNull()); GetWakeOnPacketConnections()->AddUnique(IPAddress("192.168.10.20")); GetWakeOnWiFiTriggers()->insert(WakeOnWiFi::kWakeTriggerPattern); GetWakeOnWiFiTriggers()->insert(WakeOnWiFi::kWakeTriggerDisconnect); ScopeLogger::GetInstance()->EnableScopesByName("wifi"); ScopeLogger::GetInstance()->set_verbose_level(2); EXPECT_CALL(*this, DoneCallback(ErrorTypeIs(Error::kSuccess))).Times(1); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); EXPECT_CALL( log, Log(_, _, HasSubstr("Wake on WiFi settings successfully verified"))); EXPECT_CALL(metrics_, NotifyVerifyWakeOnWiFiSettingsResult( Metrics::kVerifyWakeOnWiFiSettingsResultSuccess)); VerifyWakeOnWiFiSettings(msg); // Suspend action callback cleared after being invoked. EXPECT_TRUE(SuspendActionsCallbackIsNull()); ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); ScopeLogger::GetInstance()->set_verbose_level(0); // Unsuccessful verification if locally stored settings do not match. GetWakeOnWiFiTriggers()->erase(WakeOnWiFi::kWakeTriggerDisconnect); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); EXPECT_CALL(log, Log(logging::LOG_ERROR, _, HasSubstr( " failed: discrepancy between wake-on-packet settings on " "NIC and those in local data structure detected"))); EXPECT_CALL(metrics_, NotifyVerifyWakeOnWiFiSettingsResult( Metrics::kVerifyWakeOnWiFiSettingsResultFailure)); VerifyWakeOnWiFiSettings(msg); } TEST_F(WakeOnWiFiTestWithMockDispatcher, VerifyWakeOnWiFiSettings_WakeOnSSIDRules) { ScopedMockLog log; // Create a non-trivial Nl80211 response to a NL80211_CMD_GET_WOWLAN request // indicating that that the NIC wakes on two SSIDs represented by kSSIDBytes1 // and kSSIDBytes2 and scans for them at interval // kNetDetectScanIntervalSeconds. GetWakeOnPacketConnMessage msg; NetlinkPacket packet(kResponseWakeOnSSID, sizeof(kResponseWakeOnSSID)); msg.InitFromPacket(&packet, NetlinkMessage::MessageContext()); // Successful verification and consequent invocation of callback. SetSuspendActionsDoneCallback(); EXPECT_FALSE(SuspendActionsCallbackIsNull()); GetWakeOnWiFiTriggers()->insert(WakeOnWiFi::kWakeTriggerSSID); AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), GetWakeOnSSIDWhitelist()); AddSSIDToWhitelist(kSSIDBytes2, sizeof(kSSIDBytes2), GetWakeOnSSIDWhitelist()); SetNetDetectScanPeriodSeconds(kNetDetectScanIntervalSeconds); ScopeLogger::GetInstance()->EnableScopesByName("wifi"); ScopeLogger::GetInstance()->set_verbose_level(2); EXPECT_CALL(*this, DoneCallback(ErrorTypeIs(Error::kSuccess))).Times(1); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); EXPECT_CALL( log, Log(_, _, HasSubstr("Wake on WiFi settings successfully verified"))); EXPECT_CALL(metrics_, NotifyVerifyWakeOnWiFiSettingsResult( Metrics::kVerifyWakeOnWiFiSettingsResultSuccess)); VerifyWakeOnWiFiSettings(msg); // Suspend action callback cleared after being invoked. EXPECT_TRUE(SuspendActionsCallbackIsNull()); ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); ScopeLogger::GetInstance()->set_verbose_level(0); } TEST_F(WakeOnWiFiTestWithMockDispatcher, VerifyWakeOnWiFiSettingsSuccess_NoDoneCallback) { ScopedMockLog log; // Create an Nl80211 response to a NL80211_CMD_GET_WOWLAN request // indicating that there are no wake-on-packet rules programmed into the NIC. GetWakeOnPacketConnMessage msg; NetlinkPacket packet(kResponseNoIPAddresses, sizeof(kResponseNoIPAddresses)); msg.InitFromPacket(&packet, NetlinkMessage::MessageContext()); // Successful verification, but since there is no suspend action callback // set, no callback is invoked. EXPECT_TRUE(SuspendActionsCallbackIsNull()); EXPECT_TRUE(GetWakeOnPacketConnections()->Empty()); ScopeLogger::GetInstance()->EnableScopesByName("wifi"); ScopeLogger::GetInstance()->set_verbose_level(2); EXPECT_CALL(*this, DoneCallback(_)).Times(0); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); EXPECT_CALL( log, Log(_, _, HasSubstr("Wake on WiFi settings successfully verified"))); EXPECT_CALL(metrics_, NotifyVerifyWakeOnWiFiSettingsResult( Metrics::kVerifyWakeOnWiFiSettingsResultSuccess)); VerifyWakeOnWiFiSettings(msg); ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); ScopeLogger::GetInstance()->set_verbose_level(0); } TEST_F(WakeOnWiFiTestWithMockDispatcher, RetrySetWakeOnPacketConnections_LessThanMaxRetries) { ScopedMockLog log; // Max retries not reached yet, so send Nl80211 message to program NIC again. GetWakeOnWiFiTriggers()->insert(WakeOnWiFi::kWakeTriggerDisconnect); SetNumSetWakeOnPacketRetries(WakeOnWiFi::kMaxSetWakeOnPacketRetries - 1); EXPECT_CALL( netlink_manager_, SendNl80211Message(IsNl80211Command(kNl80211FamilyId, SetWakeOnPacketConnMessage::kCommand), _, _, _)).Times(1); RetrySetWakeOnPacketConnections(); EXPECT_EQ(GetNumSetWakeOnPacketRetries(), WakeOnWiFi::kMaxSetWakeOnPacketRetries); } TEST_F(WakeOnWiFiTestWithMockDispatcher, RetrySetWakeOnPacketConnections_MaxAttemptsWithCallbackSet) { ScopedMockLog log; // Max retry attempts reached. Suspend actions done callback is set, so it // is invoked. SetNumSetWakeOnPacketRetries(WakeOnWiFi::kMaxSetWakeOnPacketRetries); SetSuspendActionsDoneCallback(); ScopeLogger::GetInstance()->EnableScopesByName("wifi"); ScopeLogger::GetInstance()->set_verbose_level(3); EXPECT_FALSE(SuspendActionsCallbackIsNull()); EXPECT_CALL(*this, DoneCallback(ErrorTypeIs(Error::kOperationFailed))) .Times(1); EXPECT_CALL(netlink_manager_, SendNl80211Message(_, _, _, _)).Times(0); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); EXPECT_CALL(log, Log(_, _, HasSubstr("max retry attempts reached"))); RetrySetWakeOnPacketConnections(); EXPECT_TRUE(SuspendActionsCallbackIsNull()); EXPECT_EQ(GetNumSetWakeOnPacketRetries(), 0); ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); ScopeLogger::GetInstance()->set_verbose_level(0); } TEST_F(WakeOnWiFiTestWithMockDispatcher, RetrySetWakeOnPacketConnections_MaxAttemptsCallbackUnset) { ScopedMockLog log; // If there is no suspend action callback set, no suspend callback should be // invoked. SetNumSetWakeOnPacketRetries(WakeOnWiFi::kMaxSetWakeOnPacketRetries); ScopeLogger::GetInstance()->EnableScopesByName("wifi"); ScopeLogger::GetInstance()->set_verbose_level(3); EXPECT_TRUE(SuspendActionsCallbackIsNull()); EXPECT_CALL(*this, DoneCallback(_)).Times(0); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); EXPECT_CALL(log, Log(_, _, HasSubstr("max retry attempts reached"))); RetrySetWakeOnPacketConnections(); ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); ScopeLogger::GetInstance()->set_verbose_level(0); } TEST_F(WakeOnWiFiTestWithMockDispatcher, ParseWakeOnWiFiCapabilities_DisconnectPatternSSIDSupported) { ClearWakeOnWiFiTriggersSupported(); NewWiphyMessage msg; NetlinkPacket packet(kNewWiphyNlMsg, sizeof(kNewWiphyNlMsg)); msg.InitFromPacket(&packet, NetlinkMessage::MessageContext()); ParseWakeOnWiFiCapabilities(msg); EXPECT_TRUE(GetWakeOnWiFiTriggersSupported()->find( WakeOnWiFi::kWakeTriggerDisconnect) != GetWakeOnWiFiTriggersSupported()->end()); EXPECT_TRUE( GetWakeOnWiFiTriggersSupported()->find(WakeOnWiFi::kWakeTriggerPattern) != GetWakeOnWiFiTriggersSupported()->end()); EXPECT_TRUE( GetWakeOnWiFiTriggersSupported()->find(WakeOnWiFi::kWakeTriggerSSID) != GetWakeOnWiFiTriggersSupported()->end()); EXPECT_EQ(GetWakeOnWiFiMaxPatterns(), kNewWiphyNlMsg_MaxPatterns); EXPECT_EQ(GetWakeOnWiFiMaxSSIDs(), kNewWiphyNlMsg_MaxSSIDs); } TEST_F(WakeOnWiFiTestWithMockDispatcher, ParseWakeOnWiFiCapabilities_UnsupportedPatternLen) { ClearWakeOnWiFiTriggersSupported(); NewWiphyMessage msg; // Modify the range of support pattern lengths to [0-1] bytes, which is less // than what we need to use our IPV4 (30 bytes) or IPV6 (38 bytes) patterns. MutableNetlinkPacket packet(kNewWiphyNlMsg, sizeof(kNewWiphyNlMsg)); struct nl80211_pattern_support* patt_support = reinterpret_cast<struct nl80211_pattern_support*>( &packet.GetMutablePayload()->GetData()[ kNewWiphyNlMsg_PattSupportOffset]); patt_support->min_pattern_len = 0; patt_support->max_pattern_len = 1; msg.InitFromPacket(&packet, NetlinkMessage::MessageContext()); ParseWakeOnWiFiCapabilities(msg); EXPECT_TRUE(GetWakeOnWiFiTriggersSupported()->find( WakeOnWiFi::kWakeTriggerDisconnect) != GetWakeOnWiFiTriggersSupported()->end()); EXPECT_TRUE( GetWakeOnWiFiTriggersSupported()->find(WakeOnWiFi::kWakeTriggerSSID) != GetWakeOnWiFiTriggersSupported()->end()); // Ensure that ParseWakeOnWiFiCapabilities realizes that our IP address // patterns cannot be used given the support pattern length range reported. EXPECT_FALSE( GetWakeOnWiFiTriggersSupported()->find(WakeOnWiFi::kWakeTriggerPattern) != GetWakeOnWiFiTriggersSupported()->end()); } TEST_F(WakeOnWiFiTestWithMockDispatcher, ParseWakeOnWiFiCapabilities_DisconnectNotSupported) { ClearWakeOnWiFiTriggersSupported(); NewWiphyMessage msg; // Change the NL80211_WOWLAN_TRIG_DISCONNECT flag attribute into the // NL80211_WOWLAN_TRIG_MAGIC_PKT flag attribute, so that this message // no longer reports wake on disconnect as a supported capability. MutableNetlinkPacket packet(kNewWiphyNlMsg, sizeof(kNewWiphyNlMsg)); struct nlattr* wowlan_trig_disconnect_attr = reinterpret_cast<struct nlattr*>( &packet.GetMutablePayload()->GetData()[ kNewWiphyNlMsg_WowlanTrigDisconnectAttributeOffset]); wowlan_trig_disconnect_attr->nla_type = NL80211_WOWLAN_TRIG_MAGIC_PKT; msg.InitFromPacket(&packet, NetlinkMessage::MessageContext()); ParseWakeOnWiFiCapabilities(msg); EXPECT_TRUE( GetWakeOnWiFiTriggersSupported()->find(WakeOnWiFi::kWakeTriggerPattern) != GetWakeOnWiFiTriggersSupported()->end()); EXPECT_TRUE( GetWakeOnWiFiTriggersSupported()->find(WakeOnWiFi::kWakeTriggerSSID) != GetWakeOnWiFiTriggersSupported()->end()); // Ensure that ParseWakeOnWiFiCapabilities realizes that wake on disconnect // is not supported. EXPECT_FALSE(GetWakeOnWiFiTriggersSupported()->find( WakeOnWiFi::kWakeTriggerDisconnect) != GetWakeOnWiFiTriggersSupported()->end()); } TEST_F(WakeOnWiFiTestWithMockDispatcher, ParseWakeOnWiFiCapabilities_SSIDNotSupported) { ClearWakeOnWiFiTriggersSupported(); NewWiphyMessage msg; // Change the NL80211_WOWLAN_TRIG_NET_DETECT flag attribute type to an invalid // attribute type (0), so that this message no longer reports wake on SSID // as a supported capability. MutableNetlinkPacket packet(kNewWiphyNlMsg, sizeof(kNewWiphyNlMsg)); struct nlattr* wowlan_trig_net_detect_attr = reinterpret_cast<struct nlattr*>( &packet.GetMutablePayload()->GetData()[ kNewWiphyNlMsg_WowlanTrigNetDetectAttributeOffset]); wowlan_trig_net_detect_attr->nla_type = 0; msg.InitFromPacket(&packet, NetlinkMessage::MessageContext()); ParseWakeOnWiFiCapabilities(msg); EXPECT_TRUE( GetWakeOnWiFiTriggersSupported()->find(WakeOnWiFi::kWakeTriggerPattern) != GetWakeOnWiFiTriggersSupported()->end()); EXPECT_TRUE(GetWakeOnWiFiTriggersSupported()->find( WakeOnWiFi::kWakeTriggerDisconnect) != GetWakeOnWiFiTriggersSupported()->end()); // Ensure that ParseWakeOnWiFiCapabilities realizes that wake on SSID is not // supported. EXPECT_FALSE( GetWakeOnWiFiTriggersSupported()->find(WakeOnWiFi::kWakeTriggerSSID) != GetWakeOnWiFiTriggersSupported()->end()); } TEST_F(WakeOnWiFiTestWithMockDispatcher, ApplyWakeOnWiFiSettings_WiphyIndexNotReceived) { ScopedMockLog log; // ApplyWakeOnWiFiSettings should return immediately if the wifi interface // index has not been received when the function is called. SetWiphyIndexReceivedToFalse(); EXPECT_CALL(netlink_manager_, SendNl80211Message(IsDisableWakeOnWiFiMsg(), _, _, _)).Times(0); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); EXPECT_CALL(log, Log(logging::LOG_ERROR, _, HasSubstr("Interface index not yet received"))); ApplyWakeOnWiFiSettings(); } TEST_F(WakeOnWiFiTestWithMockDispatcher, ApplyWakeOnWiFiSettings_WiphyIndexReceived) { // Disable wake on WiFi if there are no wake on WiFi triggers registered. EXPECT_CALL( netlink_manager_, SendNl80211Message(IsNl80211Command(kNl80211FamilyId, SetWakeOnPacketConnMessage::kCommand), _, _, _)).Times(0); EXPECT_CALL(netlink_manager_, SendNl80211Message(IsDisableWakeOnWiFiMsg(), _, _, _)).Times(1); ApplyWakeOnWiFiSettings(); // Otherwise, program the NIC. IPAddress ip_addr("1.1.1.1"); GetWakeOnPacketConnections()->AddUnique(ip_addr); GetWakeOnWiFiTriggers()->insert(WakeOnWiFi::kWakeTriggerPattern); EXPECT_FALSE(GetWakeOnPacketConnections()->Empty()); EXPECT_CALL( netlink_manager_, SendNl80211Message(IsNl80211Command(kNl80211FamilyId, SetWakeOnPacketConnMessage::kCommand), _, _, _)).Times(1); EXPECT_CALL(netlink_manager_, SendNl80211Message(IsDisableWakeOnWiFiMsg(), _, _, _)).Times(0); ApplyWakeOnWiFiSettings(); } TEST_F(WakeOnWiFiTestWithMockDispatcher, BeforeSuspendActions_ReportDoneImmediately) { ScopedMockLog log; const bool is_connected = true; const bool start_lease_renewal_timer = true; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), GetWakeOnSSIDWhitelist()); // If no triggers are supported, no triggers will be programmed into the NIC. ClearWakeOnWiFiTriggersSupported(); SetSuspendActionsDoneCallback(); SetInDarkResume(true); SetLastWakeReason(WakeOnWiFi::kWakeTriggerPattern); AddResultToLastSSIDResults(); // Do not report done immediately in dark resume, since we need to program it // to disable wake on WiFi. EXPECT_CALL(*this, DoneCallback(_)).Times(0); BeforeSuspendActions(is_connected, start_lease_renewal_timer, kTimeToNextLeaseRenewalLong); EXPECT_FALSE(GetInDarkResume()); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); EXPECT_TRUE(GetLastSSIDMatchFreqs().empty()); SetInDarkResume(false); SetLastWakeReason(WakeOnWiFi::kWakeTriggerPattern); AddResultToLastSSIDResults(); // Report done immediately on normal suspend, since wake on WiFi should // already have been disabled on the NIC on a previous resume. EXPECT_CALL(*this, DoneCallback(_)).Times(1); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); ScopeLogger::GetInstance()->EnableScopesByName("wifi"); ScopeLogger::GetInstance()->set_verbose_level(1); EXPECT_CALL( log, Log(_, _, HasSubstr( "No need to disable wake on WiFi on NIC in regular suspend"))); BeforeSuspendActions(is_connected, start_lease_renewal_timer, kTimeToNextLeaseRenewalLong); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); EXPECT_TRUE(GetLastSSIDMatchFreqs().empty()); ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); ScopeLogger::GetInstance()->set_verbose_level(0); } TEST_F(WakeOnWiFiTestWithMockDispatcher, BeforeSuspendActions_FeaturesDisabledOrTriggersUnsupported) { const bool is_connected = true; const bool start_lease_renewal_timer = true; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), GetWakeOnSSIDWhitelist()); SetInDarkResume(false); SetSuspendActionsDoneCallback(); // No features enabled, so no triggers programmed. DisableWakeOnWiFiFeatures(); SetLastWakeReason(WakeOnWiFi::kWakeTriggerPattern); AddResultToLastSSIDResults(); EXPECT_TRUE(GetWakeOnWiFiTriggers()->empty()); EXPECT_CALL(*this, DoneCallback(_)); BeforeSuspendActions(is_connected, start_lease_renewal_timer, kTimeToNextLeaseRenewalLong); EXPECT_TRUE(GetWakeOnWiFiTriggers()->empty()); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); EXPECT_TRUE(GetLastSSIDMatchFreqs().empty()); // No triggers supported, so no triggers programmed. SetSuspendActionsDoneCallback(); EnableWakeOnWiFiFeaturesPacketDarkConnect(); GetWakeOnWiFiTriggersSupported()->clear(); SetLastWakeReason(WakeOnWiFi::kWakeTriggerPattern); AddResultToLastSSIDResults(); EXPECT_TRUE(GetWakeOnWiFiTriggers()->empty()); EXPECT_CALL(*this, DoneCallback(_)); BeforeSuspendActions(is_connected, start_lease_renewal_timer, kTimeToNextLeaseRenewalLong); EXPECT_TRUE(GetWakeOnWiFiTriggers()->empty()); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); EXPECT_TRUE(GetLastSSIDMatchFreqs().empty()); // Only wake on packet feature enabled and supported. EnableWakeOnWiFiFeaturesPacket(); GetWakeOnWiFiTriggersSupported()->insert(WakeOnWiFi::kWakeTriggerPattern); GetWakeOnPacketConnections()->AddUnique(IPAddress("1.1.1.1")); SetLastWakeReason(WakeOnWiFi::kWakeTriggerPattern); AddResultToLastSSIDResults(); EXPECT_TRUE(GetWakeOnWiFiTriggers()->empty()); BeforeSuspendActions(is_connected, start_lease_renewal_timer, kTimeToNextLeaseRenewalLong); EXPECT_EQ(GetWakeOnWiFiTriggers()->size(), 1); EXPECT_TRUE(GetWakeOnWiFiTriggers()->find(WakeOnWiFi::kWakeTriggerPattern) != GetWakeOnWiFiTriggers()->end()); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); EXPECT_TRUE(GetLastSSIDMatchFreqs().empty()); // Only wake on SSID feature supported. EnableWakeOnWiFiFeaturesDarkConnect(); GetWakeOnPacketConnections()->Clear(); GetWakeOnWiFiTriggersSupported()->clear(); GetWakeOnWiFiTriggersSupported()->insert(WakeOnWiFi::kWakeTriggerDisconnect); GetWakeOnWiFiTriggersSupported()->insert(WakeOnWiFi::kWakeTriggerSSID); GetWakeOnWiFiTriggers()->clear(); SetLastWakeReason(WakeOnWiFi::kWakeTriggerPattern); AddResultToLastSSIDResults(); EXPECT_TRUE(GetWakeOnWiFiTriggers()->empty()); BeforeSuspendActions(is_connected, start_lease_renewal_timer, kTimeToNextLeaseRenewalLong); EXPECT_EQ(GetWakeOnWiFiTriggers()->size(), 1); EXPECT_TRUE( GetWakeOnWiFiTriggers()->find(WakeOnWiFi::kWakeTriggerDisconnect) != GetWakeOnWiFiTriggers()->end()); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); EXPECT_TRUE(GetLastSSIDMatchFreqs().empty()); } TEST_F(WakeOnWiFiTestWithMockDispatcher, BeforeSuspendActions_ConnectedBeforeSuspend) { const bool is_connected = true; const bool start_lease_renewal_timer = true; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), GetWakeOnSSIDWhitelist()); SetSuspendActionsDoneCallback(); EnableWakeOnWiFiFeaturesPacketDarkConnect(); GetWakeOnPacketConnections()->AddUnique(IPAddress("1.1.1.1")); SetInDarkResume(true); GetWakeOnWiFiTriggers()->clear(); EXPECT_TRUE(GetWakeOnWiFiTriggers()->empty()); StartWakeToScanTimer(); StopDHCPLeaseRenewalTimer(); SetLastWakeReason(WakeOnWiFi::kWakeTriggerPattern); AddResultToLastSSIDResults(); EXPECT_TRUE(WakeToScanTimerIsRunning()); EXPECT_FALSE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_CALL(*this, DoneCallback(_)).Times(0); BeforeSuspendActions(is_connected, start_lease_renewal_timer, kTimeToNextLeaseRenewalLong); EXPECT_FALSE(GetInDarkResume()); EXPECT_EQ(GetWakeOnWiFiTriggers()->size(), 2); EXPECT_TRUE( GetWakeOnWiFiTriggers()->find(WakeOnWiFi::kWakeTriggerDisconnect) != GetWakeOnWiFiTriggers()->end()); EXPECT_TRUE(GetWakeOnWiFiTriggers()->find(WakeOnWiFi::kWakeTriggerPattern) != GetWakeOnWiFiTriggers()->end()); EXPECT_TRUE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_FALSE(WakeToScanTimerIsRunning()); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); EXPECT_TRUE(GetLastSSIDMatchFreqs().empty()); } TEST_F(WakeOnWiFiTestWithMockDispatcher, BeforeSuspendActions_DisconnectedBeforeSuspend) { const bool is_connected = false; const bool start_lease_renewal_timer = true; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), GetWakeOnSSIDWhitelist()); AddSSIDToWhitelist(kSSIDBytes2, sizeof(kSSIDBytes2), GetWakeOnSSIDWhitelist()); SetSuspendActionsDoneCallback(); EnableWakeOnWiFiFeaturesPacketDarkConnect(); // Do not start wake to scan timer if there are less whitelisted SSIDs (2) // than net detect SSIDs we support (10). SetInDarkResume(true); GetWakeOnWiFiTriggers()->clear(); StopWakeToScanTimer(); StartDHCPLeaseRenewalTimer(); SetWakeOnWiFiMaxSSIDs(10); SetLastWakeReason(WakeOnWiFi::kWakeTriggerPattern); AddResultToLastSSIDResults(); EXPECT_EQ(2, GetWakeOnSSIDWhitelist()->size()); EXPECT_FALSE(WakeToScanTimerIsRunning()); EXPECT_TRUE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_CALL(*this, DoneCallback(_)).Times(0); BeforeSuspendActions(is_connected, start_lease_renewal_timer, kTimeToNextLeaseRenewalLong); EXPECT_EQ(2, GetWakeOnSSIDWhitelist()->size()); EXPECT_FALSE(GetInDarkResume()); EXPECT_EQ(GetWakeOnWiFiTriggers()->size(), 1); EXPECT_TRUE(GetWakeOnWiFiTriggers()->find(WakeOnWiFi::kWakeTriggerSSID) != GetWakeOnWiFiTriggers()->end()); EXPECT_FALSE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_FALSE(WakeToScanTimerIsRunning()); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); EXPECT_TRUE(GetLastSSIDMatchFreqs().empty()); // Start wake to scan timer if there are more whitelisted SSIDs (2) than // net detect SSIDs we support (1). Also, truncate the wake on SSID whitelist // so that it only contains as many SSIDs as we support (1). SetInDarkResume(true); GetWakeOnWiFiTriggers()->clear(); StopWakeToScanTimer(); StartDHCPLeaseRenewalTimer(); SetWakeOnWiFiMaxSSIDs(1); SetLastWakeReason(WakeOnWiFi::kWakeTriggerPattern); AddResultToLastSSIDResults(); EXPECT_EQ(2, GetWakeOnSSIDWhitelist()->size()); EXPECT_FALSE(WakeToScanTimerIsRunning()); EXPECT_TRUE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_CALL(*this, DoneCallback(_)).Times(0); BeforeSuspendActions(is_connected, start_lease_renewal_timer, kTimeToNextLeaseRenewalLong); EXPECT_EQ(1, GetWakeOnSSIDWhitelist()->size()); EXPECT_FALSE(GetInDarkResume()); EXPECT_EQ(GetWakeOnWiFiTriggers()->size(), 1); EXPECT_TRUE(GetWakeOnWiFiTriggers()->find(WakeOnWiFi::kWakeTriggerSSID) != GetWakeOnWiFiTriggers()->end()); EXPECT_FALSE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_TRUE(WakeToScanTimerIsRunning()); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); EXPECT_TRUE(GetLastSSIDMatchFreqs().empty()); // Neither add the wake on SSID trigger nor start the wake to scan timer if // there are no whitelisted SSIDs. SetInDarkResume(true); GetWakeOnSSIDWhitelist()->clear(); StopWakeToScanTimer(); StartDHCPLeaseRenewalTimer(); SetWakeOnWiFiMaxSSIDs(10); SetLastWakeReason(WakeOnWiFi::kWakeTriggerPattern); AddResultToLastSSIDResults(); EXPECT_TRUE(GetWakeOnSSIDWhitelist()->empty()); EXPECT_FALSE(WakeToScanTimerIsRunning()); EXPECT_TRUE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_CALL(*this, DoneCallback(_)).Times(0); BeforeSuspendActions(is_connected, start_lease_renewal_timer, kTimeToNextLeaseRenewalLong); EXPECT_TRUE(GetWakeOnSSIDWhitelist()->empty()); EXPECT_FALSE(GetInDarkResume()); EXPECT_TRUE(GetWakeOnWiFiTriggers()->empty()); EXPECT_FALSE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_FALSE(WakeToScanTimerIsRunning()); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); EXPECT_TRUE(GetLastSSIDMatchFreqs().empty()); } TEST_F(WakeOnWiFiTestWithMockDispatcher, DisableWakeOnWiFi_ClearsTriggers) { GetWakeOnWiFiTriggers()->insert(WakeOnWiFi::kWakeTriggerPattern); EXPECT_FALSE(GetWakeOnWiFiTriggers()->empty()); DisableWakeOnWiFi(); EXPECT_TRUE(GetWakeOnWiFiTriggers()->empty()); } TEST_F(WakeOnWiFiTestWithMockDispatcher, ParseWakeOnSSIDResults) { SetWakeOnPacketConnMessage msg; NetlinkPacket packet(kWakeReasonSSIDNlMsg, sizeof(kWakeReasonSSIDNlMsg)); msg.InitFromPacket(&packet, GetWakeupReportMsgContext()); AttributeListConstRefPtr triggers; ASSERT_TRUE(msg.const_attributes()->ConstGetNestedAttributeList( NL80211_ATTR_WOWLAN_TRIGGERS, &triggers)); AttributeListConstRefPtr results_list; ASSERT_TRUE(triggers->ConstGetNestedAttributeList( NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS, &results_list)); WiFi::FreqSet freqs = ParseWakeOnSSIDResults(results_list); EXPECT_EQ(arraysize(kSSID1FreqMatches), freqs.size()); for (uint32_t freq : kSSID1FreqMatches) { EXPECT_TRUE(freqs.find(freq) != freqs.end()); } } TEST_F(WakeOnWiFiTestWithMockDispatcher, OnScanStarted_NotInDarkResume) { SetInDarkResume(false); EXPECT_CALL(metrics_, NotifyScanStartedInDarkResume(_)).Times(0); OnScanStarted(false); } TEST_F(WakeOnWiFiTestWithMockDispatcher, OnScanStarted_IgnoredWakeReasons) { // Do not log metrics if we entered dark resume because of wake on SSID or // wake on disconnect. SetInDarkResume(true); SetLastWakeReason(WakeOnWiFi::kWakeTriggerSSID); EXPECT_CALL(metrics_, NotifyScanStartedInDarkResume(_)).Times(0); OnScanStarted(false); SetLastWakeReason(WakeOnWiFi::kWakeTriggerDisconnect); EXPECT_CALL(metrics_, NotifyScanStartedInDarkResume(_)).Times(0); OnScanStarted(false); } TEST_F(WakeOnWiFiTestWithMockDispatcher, OnScanStarted_LogMetrics) { // Log metrics if we entered dark resume because of wake on pattern or an // unsupported wake reason. SetInDarkResume(true); SetLastWakeReason(WakeOnWiFi::kWakeTriggerUnsupported); EXPECT_CALL(metrics_, NotifyScanStartedInDarkResume(_)); OnScanStarted(false); SetLastWakeReason(WakeOnWiFi::kWakeTriggerPattern); EXPECT_CALL(metrics_, NotifyScanStartedInDarkResume(_)); OnScanStarted(false); // Log error if an active scan is launched. ScopedMockLog log; EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); EXPECT_CALL(log, Log(logging::LOG_ERROR, _, HasSubstr("Unexpected active scan launched in dark resume"))); EXPECT_CALL(metrics_, NotifyScanStartedInDarkResume(_)); OnScanStarted(true); } TEST_F(WakeOnWiFiTestWithDispatcher, InitiateScanInDarkResume) { WiFi::FreqSet freqs; // If we are not scanning on specific frequencies, do not enable the retry // mechanism. EXPECT_EQ(0, GetDarkResumeScanRetriesLeft()); EXPECT_CALL(*this, InitiateScanCallback(freqs)); InitiateScanInDarkResume(freqs); EXPECT_EQ(0, GetDarkResumeScanRetriesLeft()); // Otherwise, start channel specific passive scan with retries. freqs.insert(1); EXPECT_LE(freqs.size(), WakeOnWiFi::kMaxFreqsForDarkResumeScanRetries); EXPECT_EQ(0, GetDarkResumeScanRetriesLeft()); EXPECT_CALL(*this, InitiateScanCallback(freqs)); InitiateScanInDarkResume(freqs); EXPECT_EQ(WakeOnWiFi::kMaxDarkResumeScanRetries, GetDarkResumeScanRetriesLeft()); } TEST_F(WakeOnWiFiTestWithMockDispatcher, AddRemoveWakeOnPacketConnection) { const string bad_ip_string("1.1"); const string ip_string1("192.168.0.19"); const string ip_string2("192.168.0.55"); const string ip_string3("192.168.0.74"); IPAddress ip_addr1(ip_string1); IPAddress ip_addr2(ip_string2); IPAddress ip_addr3(ip_string3); Error e; // Add and remove operations will fail if we provide an invalid IP address // string. EnableWakeOnWiFiFeaturesPacket(); AddWakeOnPacketConnection(bad_ip_string, &e); EXPECT_EQ(e.type(), Error::kInvalidArguments); EXPECT_STREQ(e.message().c_str(), ("Invalid ip_address " + bad_ip_string).c_str()); RemoveWakeOnPacketConnection(bad_ip_string, &e); EXPECT_EQ(e.type(), Error::kInvalidArguments); EXPECT_STREQ(e.message().c_str(), ("Invalid ip_address " + bad_ip_string).c_str()); // Add and remove operations will fail if WiFi device does not support // pattern matching functionality, even if the feature is enabled. EnableWakeOnWiFiFeaturesPacket(); ClearWakeOnWiFiTriggersSupported(); AddWakeOnPacketConnection(ip_string1, &e); EXPECT_EQ(e.type(), Error::kNotSupported); EXPECT_STREQ(e.message().c_str(), "Wake on IP address patterns not supported by this WiFi device"); RemoveAllWakeOnPacketConnections(&e); EXPECT_EQ(e.type(), Error::kNotSupported); EXPECT_STREQ(e.message().c_str(), "Wake on IP address patterns not supported by this WiFi device"); RemoveWakeOnPacketConnection(ip_string2, &e); EXPECT_EQ(e.type(), Error::kNotSupported); EXPECT_STREQ(e.message().c_str(), "Wake on IP address patterns not supported by this WiFi device"); // Add operation will fail if pattern matching is supported but the max number // of IP address patterns have already been registered. EnableWakeOnWiFiFeaturesPacketDarkConnect(); GetWakeOnWiFiTriggersSupported()->insert(WakeOnWiFi::kWakeTriggerPattern); SetWakeOnWiFiMaxPatterns(1); GetWakeOnPacketConnections()->AddUnique(IPAddress(ip_string1)); AddWakeOnPacketConnection(ip_string2, &e); EXPECT_EQ(e.type(), Error::kOperationFailed); EXPECT_STREQ(e.message().c_str(), "Max number of IP address patterns already registered"); // Add and remove operations will still execute even when the wake on packet // feature has been disabled. GetWakeOnPacketConnections()->Clear(); SetWakeOnWiFiMaxPatterns(50); DisableWakeOnWiFiFeatures(); GetWakeOnWiFiTriggersSupported()->insert(WakeOnWiFi::kWakeTriggerPattern); AddWakeOnPacketConnection(ip_string1, &e); EXPECT_EQ(GetWakeOnPacketConnections()->Count(), 1); EXPECT_TRUE(GetWakeOnPacketConnections()->Contains(ip_addr1)); AddWakeOnPacketConnection(ip_string2, &e); EXPECT_EQ(GetWakeOnPacketConnections()->Count(), 2); EXPECT_TRUE(GetWakeOnPacketConnections()->Contains(ip_addr2)); RemoveWakeOnPacketConnection(ip_string1, &e); EXPECT_EQ(GetWakeOnPacketConnections()->Count(), 1); RemoveAllWakeOnPacketConnections(&e); EXPECT_TRUE(GetWakeOnPacketConnections()->Empty()); // Normal functioning of add/remove operations when wake on WiFi features // are enabled, the NIC supports pattern matching, and the max number // of patterns have not been registered yet. EnableWakeOnWiFiFeaturesPacketDarkConnect(); GetWakeOnPacketConnections()->Clear(); EXPECT_TRUE(GetWakeOnPacketConnections()->Empty()); AddWakeOnPacketConnection(ip_string1, &e); EXPECT_EQ(GetWakeOnPacketConnections()->Count(), 1); EXPECT_TRUE(GetWakeOnPacketConnections()->Contains(ip_addr1)); EXPECT_FALSE(GetWakeOnPacketConnections()->Contains(ip_addr2)); EXPECT_FALSE(GetWakeOnPacketConnections()->Contains(ip_addr3)); AddWakeOnPacketConnection(ip_string2, &e); EXPECT_EQ(GetWakeOnPacketConnections()->Count(), 2); EXPECT_TRUE(GetWakeOnPacketConnections()->Contains(ip_addr1)); EXPECT_TRUE(GetWakeOnPacketConnections()->Contains(ip_addr2)); EXPECT_FALSE(GetWakeOnPacketConnections()->Contains(ip_addr3)); AddWakeOnPacketConnection(ip_string3, &e); EXPECT_EQ(GetWakeOnPacketConnections()->Count(), 3); EXPECT_TRUE(GetWakeOnPacketConnections()->Contains(ip_addr1)); EXPECT_TRUE(GetWakeOnPacketConnections()->Contains(ip_addr2)); EXPECT_TRUE(GetWakeOnPacketConnections()->Contains(ip_addr3)); RemoveWakeOnPacketConnection(ip_string2, &e); EXPECT_EQ(GetWakeOnPacketConnections()->Count(), 2); EXPECT_TRUE(GetWakeOnPacketConnections()->Contains(ip_addr1)); EXPECT_FALSE(GetWakeOnPacketConnections()->Contains(ip_addr2)); EXPECT_TRUE(GetWakeOnPacketConnections()->Contains(ip_addr3)); // Remove fails if no such address is registered. RemoveWakeOnPacketConnection(ip_string2, &e); EXPECT_EQ(e.type(), Error::kNotFound); EXPECT_STREQ(e.message().c_str(), "No such IP address match registered to wake device"); EXPECT_EQ(GetWakeOnPacketConnections()->Count(), 2); RemoveWakeOnPacketConnection(ip_string1, &e); EXPECT_EQ(GetWakeOnPacketConnections()->Count(), 1); EXPECT_FALSE(GetWakeOnPacketConnections()->Contains(ip_addr1)); EXPECT_FALSE(GetWakeOnPacketConnections()->Contains(ip_addr2)); EXPECT_TRUE(GetWakeOnPacketConnections()->Contains(ip_addr3)); AddWakeOnPacketConnection(ip_string2, &e); EXPECT_EQ(GetWakeOnPacketConnections()->Count(), 2); EXPECT_FALSE(GetWakeOnPacketConnections()->Contains(ip_addr1)); EXPECT_TRUE(GetWakeOnPacketConnections()->Contains(ip_addr2)); EXPECT_TRUE(GetWakeOnPacketConnections()->Contains(ip_addr3)); RemoveAllWakeOnPacketConnections(&e); EXPECT_EQ(GetWakeOnPacketConnections()->Count(), 0); EXPECT_FALSE(GetWakeOnPacketConnections()->Contains(ip_addr1)); EXPECT_FALSE(GetWakeOnPacketConnections()->Contains(ip_addr2)); EXPECT_FALSE(GetWakeOnPacketConnections()->Contains(ip_addr3)); } TEST_F(WakeOnWiFiTestWithDispatcher, OnBeforeSuspend_ClearsEventHistory) { const int kNumEvents = WakeOnWiFi::kMaxDarkResumesPerPeriodShort - 1; vector<ByteString> whitelist; for (int i = 0; i < kNumEvents; ++i) { GetDarkResumeHistory()->RecordEvent(); } EXPECT_EQ(kNumEvents, GetDarkResumeHistory()->Size()); OnBeforeSuspend(true, whitelist, true, 0); EXPECT_TRUE(GetDarkResumeHistory()->Empty()); } TEST_F(WakeOnWiFiTestWithDispatcher, OnBeforeSuspend_SetsWakeOnSSIDWhitelist) { vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); EXPECT_TRUE(GetWakeOnSSIDWhitelist()->empty()); OnBeforeSuspend(true, whitelist, true, 0); EXPECT_FALSE(GetWakeOnSSIDWhitelist()->empty()); EXPECT_EQ(1, GetWakeOnSSIDWhitelist()->size()); } TEST_F(WakeOnWiFiTestWithDispatcher, OnBeforeSuspend_SetsDoneCallback) { vector<ByteString> whitelist; EXPECT_TRUE(SuspendActionsCallbackIsNull()); OnBeforeSuspend(true, whitelist, true, 0); EXPECT_FALSE(SuspendActionsCallbackIsNull()); } TEST_F(WakeOnWiFiTestWithMockDispatcher, OnBeforeSuspend_DHCPLeaseRenewal) { bool is_connected; bool have_dhcp_lease; vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); // If we are connected the time to next lease renewal is short enough, we will // initiate DHCP lease renewal immediately. is_connected = true; have_dhcp_lease = true; EXPECT_CALL(*this, RenewDHCPLeaseCallback()).Times(1); EXPECT_CALL(mock_dispatcher_, PostTask(_)).Times(1); OnBeforeSuspend(is_connected, whitelist, have_dhcp_lease, kTimeToNextLeaseRenewalShort); // No immediate DHCP lease renewal because we are not connected. is_connected = false; have_dhcp_lease = true; EXPECT_CALL(*this, RenewDHCPLeaseCallback()).Times(0); EXPECT_CALL(mock_dispatcher_, PostTask(_)).Times(1); OnBeforeSuspend(is_connected, whitelist, have_dhcp_lease, kTimeToNextLeaseRenewalShort); // No immediate DHCP lease renewal because the time to the next lease renewal // is longer than the threshold. is_connected = true; have_dhcp_lease = true; EXPECT_CALL(*this, RenewDHCPLeaseCallback()).Times(0); EXPECT_CALL(mock_dispatcher_, PostTask(_)).Times(1); OnBeforeSuspend(is_connected, whitelist, have_dhcp_lease, kTimeToNextLeaseRenewalLong); // No immediate DHCP lease renewal because we do not have a DHCP lease that // needs to be renewed. is_connected = true; have_dhcp_lease = false; EXPECT_CALL(*this, RenewDHCPLeaseCallback()).Times(0); EXPECT_CALL(mock_dispatcher_, PostTask(_)).Times(1); OnBeforeSuspend(is_connected, whitelist, have_dhcp_lease, kTimeToNextLeaseRenewalLong); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_ResetsDarkResumeScanRetries) { const bool is_connected = true; vector<ByteString> whitelist; SetDarkResumeScanRetriesLeft(3); EXPECT_EQ(3, GetDarkResumeScanRetriesLeft()); OnDarkResume(is_connected, whitelist); EXPECT_EQ(0, GetDarkResumeScanRetriesLeft()); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_SetsWakeOnSSIDWhitelist) { const bool is_connected = true; vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); EXPECT_TRUE(GetWakeOnSSIDWhitelist()->empty()); OnDarkResume(is_connected, whitelist); EXPECT_FALSE(GetWakeOnSSIDWhitelist()->empty()); EXPECT_EQ(1, GetWakeOnSSIDWhitelist()->size()); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_WakeReasonUnsupported_Connected_Timeout) { // Test that correct actions are taken if we enter OnDarkResume on an // unsupported wake trigger while connected, then timeout on suspend actions // before suspending again. const bool is_connected = true; SetLastWakeReason(WakeOnWiFi::kWakeTriggerUnsupported); vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); InitStateForDarkResume(); EXPECT_TRUE(DarkResumeActionsTimeOutCallbackIsCancelled()); // Renew DHCP lease if we are connected in dark resume. EXPECT_CALL(*this, RenewDHCPLeaseCallback()); EXPECT_CALL(metrics_, NotifyWakeOnWiFiOnDarkResume( WakeOnWiFi::kWakeTriggerUnsupported)); OnDarkResume(is_connected, whitelist); EXPECT_FALSE(DarkResumeActionsTimeOutCallbackIsCancelled()); // Trigger timeout callback. // Since we timeout, we are disconnected before suspend. StartDHCPLeaseRenewalTimer(); SetExpectationsDisconnectedBeforeSuspend(); dispatcher_.DispatchPendingEvents(); EXPECT_FALSE(DHCPLeaseRenewalTimerIsRunning()); VerifyStateDisconnectedBeforeSuspend(); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_WakeReasonUnsupported_Connected_NoAutoconnectableServices) { // Test that correct actions are taken if we enter OnDarkResume on an // unsupported wake trigger while connected, then go back to suspend because // we could not find any services available for autoconnect. const bool is_connected = true; SetLastWakeReason(WakeOnWiFi::kWakeTriggerUnsupported); vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); InitStateForDarkResume(); EXPECT_TRUE(DarkResumeActionsTimeOutCallbackIsCancelled()); // Renew DHCP lease if we are connected in dark resume. EXPECT_CALL(*this, RenewDHCPLeaseCallback()); EXPECT_CALL(metrics_, NotifyWakeOnWiFiOnDarkResume( WakeOnWiFi::kWakeTriggerUnsupported)); OnDarkResume(is_connected, whitelist); EXPECT_FALSE(DarkResumeActionsTimeOutCallbackIsCancelled()); StartDHCPLeaseRenewalTimer(); SetExpectationsDisconnectedBeforeSuspend(); OnNoAutoConnectableServicesAfterScan(whitelist); EXPECT_FALSE(DHCPLeaseRenewalTimerIsRunning()); VerifyStateDisconnectedBeforeSuspend(); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_WakeReasonUnsupported_Connected_LeaseObtained) { // Test that correct actions are taken if we enter OnDarkResume on an // unsupported wake trigger while connected, then connect and obtain a DHCP // lease before suspending again. const bool is_connected = true; const bool have_dhcp_lease = true; const uint32_t time_to_next_lease_renewal = 10; SetLastWakeReason(WakeOnWiFi::kWakeTriggerUnsupported); vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); InitStateForDarkResume(); EXPECT_TRUE(DarkResumeActionsTimeOutCallbackIsCancelled()); // Renew DHCP lease if we are connected in dark resume. EXPECT_CALL(*this, RenewDHCPLeaseCallback()); EXPECT_CALL(metrics_, NotifyWakeOnWiFiOnDarkResume( WakeOnWiFi::kWakeTriggerUnsupported)); OnDarkResume(is_connected, whitelist); EXPECT_FALSE(DarkResumeActionsTimeOutCallbackIsCancelled()); // Lease obtained. // Since a lease is obtained, we are connected before suspend. StopDHCPLeaseRenewalTimer(); StartWakeToScanTimer(); SetExpectationsConnectedBeforeSuspend(); OnConnectedAndReachable(have_dhcp_lease, time_to_next_lease_renewal); EXPECT_TRUE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_FALSE(WakeToScanTimerIsRunning()); VerifyStateConnectedBeforeSuspend(); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_WakeReasonUnsupported_NotConnected_Timeout) { // Test that correct actions are taken if we enter OnDarkResume on an // unsupported wake trigger while not connected, then timeout on suspend // actions before suspending again. const bool is_connected = false; SetLastWakeReason(WakeOnWiFi::kWakeTriggerUnsupported); vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); InitStateForDarkResume(); EXPECT_TRUE(DarkResumeActionsTimeOutCallbackIsCancelled()); // Initiate scan if we are not connected in dark resume. EXPECT_CALL(*this, RemoveSupplicantNetworksCallback()); EXPECT_CALL(metrics_, NotifyDarkResumeInitiateScan()); EXPECT_CALL(*this, InitiateScanCallback(_)); EXPECT_CALL(metrics_, NotifyWakeOnWiFiOnDarkResume( WakeOnWiFi::kWakeTriggerUnsupported)); OnDarkResume(is_connected, whitelist); EXPECT_FALSE(DarkResumeActionsTimeOutCallbackIsCancelled()); // Trigger timeout callback. // Since we timeout, we are disconnected before suspend. StartDHCPLeaseRenewalTimer(); SetExpectationsDisconnectedBeforeSuspend(); dispatcher_.DispatchPendingEvents(); EXPECT_FALSE(DHCPLeaseRenewalTimerIsRunning()); VerifyStateDisconnectedBeforeSuspend(); } TEST_F( WakeOnWiFiTestWithDispatcher, OnDarkResume_WakeReasonUnsupported_NotConnected_NoAutoconnectableServices) { // Test that correct actions are taken if we enter OnDarkResume on an // unsupported wake trigger while not connected, then go back to suspend // because we could not find any services available for autoconnect. const bool is_connected = false; SetLastWakeReason(WakeOnWiFi::kWakeTriggerUnsupported); vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); InitStateForDarkResume(); EXPECT_TRUE(DarkResumeActionsTimeOutCallbackIsCancelled()); // Initiate scan if we are not connected in dark resume. EXPECT_CALL(*this, RemoveSupplicantNetworksCallback()); EXPECT_CALL(metrics_, NotifyDarkResumeInitiateScan()); EXPECT_CALL(*this, InitiateScanCallback(_)); EXPECT_CALL(metrics_, NotifyWakeOnWiFiOnDarkResume( WakeOnWiFi::kWakeTriggerUnsupported)); OnDarkResume(is_connected, whitelist); EXPECT_FALSE(DarkResumeActionsTimeOutCallbackIsCancelled()); StartDHCPLeaseRenewalTimer(); SetExpectationsDisconnectedBeforeSuspend(); OnNoAutoConnectableServicesAfterScan(whitelist); EXPECT_FALSE(DHCPLeaseRenewalTimerIsRunning()); VerifyStateDisconnectedBeforeSuspend(); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_WakeReasonUnsupported_NotConnected_LeaseObtained) { // Test that correct actions are taken if we enter OnDarkResume on an // unsupported wake trigger while connected, then connect and obtain a DHCP // lease before suspending again. const bool is_connected = false; const bool have_dhcp_lease = true; const uint32_t time_to_next_lease_renewal = 10; SetLastWakeReason(WakeOnWiFi::kWakeTriggerUnsupported); vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); InitStateForDarkResume(); EXPECT_TRUE(DarkResumeActionsTimeOutCallbackIsCancelled()); // Initiate scan if we are not connected in dark resume. EXPECT_CALL(*this, RemoveSupplicantNetworksCallback()); EXPECT_CALL(metrics_, NotifyDarkResumeInitiateScan()); EXPECT_CALL(*this, InitiateScanCallback(_)); EXPECT_CALL(metrics_, NotifyWakeOnWiFiOnDarkResume( WakeOnWiFi::kWakeTriggerUnsupported)); OnDarkResume(is_connected, whitelist); EXPECT_FALSE(DarkResumeActionsTimeOutCallbackIsCancelled()); // Lease obtained. // Since a lease is obtained, we are connected before suspend. StopDHCPLeaseRenewalTimer(); StartWakeToScanTimer(); SetExpectationsConnectedBeforeSuspend(); OnConnectedAndReachable(have_dhcp_lease, time_to_next_lease_renewal); EXPECT_TRUE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_FALSE(WakeToScanTimerIsRunning()); VerifyStateConnectedBeforeSuspend(); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_WakeReasonPattern) { // Test that correct actions are taken if we enter dark resume because the // system woke on a packet pattern match. We assume that we wake connected and // and go back to sleep connected if we wake on pattern. const bool is_connected = true; SetLastWakeReason(WakeOnWiFi::kWakeTriggerPattern); vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); InitStateForDarkResume(); EXPECT_TRUE(DarkResumeActionsTimeOutCallbackIsCancelled()); EXPECT_CALL(metrics_, NotifyWakeOnWiFiOnDarkResume(WakeOnWiFi::kWakeTriggerPattern)); OnDarkResume(is_connected, whitelist); EXPECT_FALSE(DarkResumeActionsTimeOutCallbackIsCancelled()); StartWakeToScanTimer(); SetExpectationsConnectedBeforeSuspend(); dispatcher_.DispatchPendingEvents(); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); EXPECT_FALSE(WakeToScanTimerIsRunning()); VerifyStateConnectedBeforeSuspend(); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_WakeReasonDisconnect_NoAutoconnectableServices) { // Test that correct actions are taken if we enter dark resume because the // system woke on a disconnect, and go back to suspend because we could not // find any networks available for autoconnect. const bool is_connected = false; SetLastWakeReason(WakeOnWiFi::kWakeTriggerDisconnect); vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); InitStateForDarkResume(); EXPECT_TRUE(DarkResumeActionsTimeOutCallbackIsCancelled()); EXPECT_CALL(*this, RemoveSupplicantNetworksCallback()); EXPECT_CALL(metrics_, NotifyDarkResumeInitiateScan()); EXPECT_CALL(*this, InitiateScanCallback(_)); EXPECT_CALL(metrics_, NotifyWakeOnWiFiOnDarkResume(WakeOnWiFi::kWakeTriggerDisconnect)); OnDarkResume(is_connected, whitelist); EXPECT_FALSE(DarkResumeActionsTimeOutCallbackIsCancelled()); StartDHCPLeaseRenewalTimer(); SetExpectationsDisconnectedBeforeSuspend(); OnNoAutoConnectableServicesAfterScan(whitelist); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); EXPECT_FALSE(DHCPLeaseRenewalTimerIsRunning()); VerifyStateDisconnectedBeforeSuspend(); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_WakeReasonDisconnect_Timeout) { // Test that correct actions are taken if we enter dark resume because the // system woke on a disconnect, then timeout on suspend actions before // suspending again. const bool is_connected = false; SetLastWakeReason(WakeOnWiFi::kWakeTriggerDisconnect); vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); InitStateForDarkResume(); EXPECT_TRUE(DarkResumeActionsTimeOutCallbackIsCancelled()); EXPECT_CALL(*this, RemoveSupplicantNetworksCallback()); EXPECT_CALL(metrics_, NotifyDarkResumeInitiateScan()); EXPECT_CALL(*this, InitiateScanCallback(_)); EXPECT_CALL(metrics_, NotifyWakeOnWiFiOnDarkResume(WakeOnWiFi::kWakeTriggerDisconnect)); OnDarkResume(is_connected, whitelist); EXPECT_FALSE(DarkResumeActionsTimeOutCallbackIsCancelled()); StartDHCPLeaseRenewalTimer(); SetExpectationsDisconnectedBeforeSuspend(); dispatcher_.DispatchPendingEvents(); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); EXPECT_FALSE(DHCPLeaseRenewalTimerIsRunning()); VerifyStateDisconnectedBeforeSuspend(); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_WakeReasonDisconnect_LeaseObtained) { // Test that correct actions are taken if we enter dark resume because the // system woke on a disconnect, then connect and obtain a DHCP lease before // suspending again. const bool is_connected = false; const bool have_dhcp_lease = true; const uint32_t time_to_next_lease_renewal = 10; SetLastWakeReason(WakeOnWiFi::kWakeTriggerDisconnect); vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); InitStateForDarkResume(); EXPECT_TRUE(DarkResumeActionsTimeOutCallbackIsCancelled()); EXPECT_CALL(*this, RemoveSupplicantNetworksCallback()); EXPECT_CALL(metrics_, NotifyDarkResumeInitiateScan()); EXPECT_CALL(*this, InitiateScanCallback(_)); EXPECT_CALL(metrics_, NotifyWakeOnWiFiOnDarkResume(WakeOnWiFi::kWakeTriggerDisconnect)); OnDarkResume(is_connected, whitelist); EXPECT_FALSE(DarkResumeActionsTimeOutCallbackIsCancelled()); StopDHCPLeaseRenewalTimer(); StartWakeToScanTimer(); SetExpectationsConnectedBeforeSuspend(); OnConnectedAndReachable(have_dhcp_lease, time_to_next_lease_renewal); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); EXPECT_TRUE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_FALSE(WakeToScanTimerIsRunning()); VerifyStateConnectedBeforeSuspend(); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_WakeReasonSSID_NoAutoconnectableServices) { // Test that correct actions are taken if we enter dark resume because the // system woke on SSID, and go back to suspend because we could not find any // networks available for autoconnect. const bool is_connected = false; SetLastWakeReason(WakeOnWiFi::kWakeTriggerSSID); vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); InitStateForDarkResume(); EXPECT_TRUE(DarkResumeActionsTimeOutCallbackIsCancelled()); EXPECT_CALL(*this, RemoveSupplicantNetworksCallback()); EXPECT_CALL(metrics_, NotifyDarkResumeInitiateScan()); EXPECT_CALL(*this, InitiateScanCallback(_)); EXPECT_CALL(metrics_, NotifyWakeOnWiFiOnDarkResume(WakeOnWiFi::kWakeTriggerSSID)); OnDarkResume(is_connected, whitelist); EXPECT_FALSE(DarkResumeActionsTimeOutCallbackIsCancelled()); StartDHCPLeaseRenewalTimer(); SetExpectationsDisconnectedBeforeSuspend(); OnNoAutoConnectableServicesAfterScan(whitelist); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); EXPECT_FALSE(DHCPLeaseRenewalTimerIsRunning()); VerifyStateDisconnectedBeforeSuspend(); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_WakeReasonSSID_Timeout) { // Test that correct actions are taken if we enter dark resume because the // system woke on SSID, then timeout on suspend actions before suspending // again. const bool is_connected = false; SetLastWakeReason(WakeOnWiFi::kWakeTriggerSSID); vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); InitStateForDarkResume(); EXPECT_TRUE(DarkResumeActionsTimeOutCallbackIsCancelled()); EXPECT_CALL(*this, RemoveSupplicantNetworksCallback()); EXPECT_CALL(metrics_, NotifyDarkResumeInitiateScan()); EXPECT_CALL(*this, InitiateScanCallback(GetLastSSIDMatchFreqs())); EXPECT_CALL(metrics_, NotifyWakeOnWiFiOnDarkResume(WakeOnWiFi::kWakeTriggerSSID)); OnDarkResume(is_connected, whitelist); EXPECT_FALSE(DarkResumeActionsTimeOutCallbackIsCancelled()); StartDHCPLeaseRenewalTimer(); SetExpectationsDisconnectedBeforeSuspend(); dispatcher_.DispatchPendingEvents(); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); EXPECT_FALSE(DHCPLeaseRenewalTimerIsRunning()); VerifyStateDisconnectedBeforeSuspend(); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_WakeReasonSSID_LeaseObtained) { // Test that correct actions are taken if we enter dark resume because the // system woke on SSID, then connect and obtain a DHCP lease before suspending // again. const bool is_connected = false; const bool have_dhcp_lease = true; const uint32_t time_to_next_lease_renewal = 10; SetLastWakeReason(WakeOnWiFi::kWakeTriggerSSID); vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); InitStateForDarkResume(); EXPECT_TRUE(DarkResumeActionsTimeOutCallbackIsCancelled()); EXPECT_CALL(*this, RemoveSupplicantNetworksCallback()); EXPECT_CALL(metrics_, NotifyDarkResumeInitiateScan()); EXPECT_CALL(*this, InitiateScanCallback(GetLastSSIDMatchFreqs())); EXPECT_CALL(metrics_, NotifyWakeOnWiFiOnDarkResume(WakeOnWiFi::kWakeTriggerSSID)); OnDarkResume(is_connected, whitelist); EXPECT_FALSE(DarkResumeActionsTimeOutCallbackIsCancelled()); StopDHCPLeaseRenewalTimer(); StartWakeToScanTimer(); SetExpectationsConnectedBeforeSuspend(); OnConnectedAndReachable(have_dhcp_lease, time_to_next_lease_renewal); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); EXPECT_TRUE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_FALSE(WakeToScanTimerIsRunning()); VerifyStateConnectedBeforeSuspend(); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_Connected_DoNotRecordEvent) { const bool is_connected = true; vector<ByteString> whitelist; EXPECT_TRUE(GetDarkResumeHistory()->Empty()); OnDarkResume(is_connected, whitelist); EXPECT_TRUE(GetDarkResumeHistory()->Empty()); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_NotConnected_RecordEvent) { const bool is_connected = false; vector<ByteString> whitelist; EXPECT_TRUE(GetDarkResumeHistory()->Empty()); OnDarkResume(is_connected, whitelist); EXPECT_EQ(1, GetDarkResumeHistory()->Size()); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_NotConnected_MaxDarkResumes_ShortPeriod) { // These 3 dark resume timings are within a 1 minute interval, so as to // trigger the short throttling threshold (3 in 1 minute). const int kTimeSeconds[] = {10, 20, 30}; CHECK_EQ(static_cast<const unsigned int>( WakeOnWiFi::kMaxDarkResumesPerPeriodShort), arraysize(kTimeSeconds)); vector<ByteString> whitelist; // This test assumes that throttling takes place when 3 dark resumes have // been triggered in the last 1 minute. EXPECT_EQ(3, WakeOnWiFi::kMaxDarkResumesPerPeriodShort); EXPECT_EQ(1, WakeOnWiFi::kDarkResumeFrequencySamplingPeriodShortMinutes); // Wake on SSID dark resumes should be recorded in the dark resume history. const bool is_connected = false; SetLastWakeReason(WakeOnWiFi::kWakeTriggerSSID); EXPECT_TRUE(GetDarkResumeHistory()->Empty()); // First two dark resumes take place at 10 and 20 seconds respectively. This // is still within the throttling threshold. for (int i = 0; i < WakeOnWiFi::kMaxDarkResumesPerPeriodShort - 1; ++i) { EXPECT_CALL(metrics_, NotifyWakeOnWiFiThrottled()).Times(0); EXPECT_CALL(time_, GetNow()) .WillRepeatedly(Return(GetTimestampBootTime(kTimeSeconds[i]))); OnDarkResume(is_connected, whitelist); } SetInDarkResume(false); // this happens after BeforeSuspendActions EXPECT_EQ(WakeOnWiFi::kMaxDarkResumesPerPeriodShort - 1, GetDarkResumeHistory()->Size()); // The 3rd dark resume takes place at 30 seconds, which makes 3 dark resumes // in the past minute. Disable wake on WiFi and start wake to scan timer. ResetSuspendActionsDoneCallback(); StartDHCPLeaseRenewalTimer(); StopWakeToScanTimer(); EXPECT_TRUE(SuspendActionsCallbackIsNull()); EXPECT_TRUE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_FALSE(WakeToScanTimerIsRunning()); EXPECT_FALSE(GetDarkResumeHistory()->Empty()); EXPECT_CALL(metrics_, NotifyWakeOnWiFiThrottled()); EXPECT_CALL(time_, GetNow()) .WillRepeatedly(Return(GetTimestampBootTime( kTimeSeconds[WakeOnWiFi::kMaxDarkResumesPerPeriodShort - 1]))); OnDarkResume(is_connected, whitelist); EXPECT_FALSE(SuspendActionsCallbackIsNull()); EXPECT_FALSE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_TRUE(WakeToScanTimerIsRunning()); EXPECT_TRUE(GetDarkResumeHistory()->Empty()); EXPECT_FALSE(GetInDarkResume()); } TEST_F(WakeOnWiFiTestWithDispatcher, OnDarkResume_NotConnected_MaxDarkResumes_LongPeriod) { // These 10 dark resume timings are spaced 1 minute apart so as to trigger the // long throttling threshold (10 in 10 minute) without triggering the short // throttling threshold (3 in 1 minute). const int kTimeSeconds[] = {10, 70, 130, 190, 250, 310, 370, 430, 490, 550}; CHECK_EQ( static_cast<const unsigned int>(WakeOnWiFi::kMaxDarkResumesPerPeriodLong), arraysize(kTimeSeconds)); vector<ByteString> whitelist; // This test assumes that throttling takes place when 3 dark resumes have been // triggered in the last 1 minute, or when 10 dark resumes have been triggered // in the last 10 minutes. EXPECT_EQ(3, WakeOnWiFi::kMaxDarkResumesPerPeriodShort); EXPECT_EQ(1, WakeOnWiFi::kDarkResumeFrequencySamplingPeriodShortMinutes); EXPECT_EQ(10, WakeOnWiFi::kMaxDarkResumesPerPeriodLong); EXPECT_EQ(10, WakeOnWiFi::kDarkResumeFrequencySamplingPeriodLongMinutes); // Wake on SSID dark resumes should be recorded in the dark resume history. const bool is_connected = false; SetLastWakeReason(WakeOnWiFi::kWakeTriggerSSID); EXPECT_TRUE(GetDarkResumeHistory()->Empty()); // The first 9 dark resumes happen once per minute. This is still within the // throttling threshold. for (int i = 0; i < WakeOnWiFi::kMaxDarkResumesPerPeriodLong - 1; ++i) { EXPECT_CALL(metrics_, NotifyWakeOnWiFiThrottled()).Times(0); EXPECT_CALL(time_, GetNow()) .WillRepeatedly(Return(GetTimestampBootTime(kTimeSeconds[i]))); OnDarkResume(is_connected, whitelist); } SetInDarkResume(false); // this happens after BeforeSuspendActions EXPECT_EQ(WakeOnWiFi::kMaxDarkResumesPerPeriodLong - 1, GetDarkResumeHistory()->Size()); // The occurrence of the 10th dark resume makes 10 dark resumes in the past 10 // minutes. Disable wake on WiFi and start wake to scan timer. ResetSuspendActionsDoneCallback(); StartDHCPLeaseRenewalTimer(); StopWakeToScanTimer(); EXPECT_TRUE(SuspendActionsCallbackIsNull()); EXPECT_TRUE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_FALSE(WakeToScanTimerIsRunning()); EXPECT_FALSE(GetDarkResumeHistory()->Empty()); EXPECT_CALL(metrics_, NotifyWakeOnWiFiThrottled()); EXPECT_CALL(time_, GetNow()) .WillRepeatedly(Return(GetTimestampBootTime( kTimeSeconds[WakeOnWiFi::kMaxDarkResumesPerPeriodLong - 1]))); OnDarkResume(is_connected, whitelist); EXPECT_FALSE(SuspendActionsCallbackIsNull()); EXPECT_FALSE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_TRUE(WakeToScanTimerIsRunning()); EXPECT_TRUE(GetDarkResumeHistory()->Empty()); EXPECT_FALSE(GetInDarkResume()); EXPECT_TRUE(GetLastSSIDMatchFreqs().empty()); } TEST_F(WakeOnWiFiTestWithMockDispatcher, OnConnectedAndReachable) { const bool start_lease_renewal_timer = true; ScopedMockLog log; EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); SetInDarkResume(true); ScopeLogger::GetInstance()->EnableScopesByName("wifi"); ScopeLogger::GetInstance()->set_verbose_level(3); EXPECT_CALL(log, Log(_, _, HasSubstr("BeforeSuspendActions"))); OnConnectedAndReachable(start_lease_renewal_timer, kTimeToNextLeaseRenewalLong); SetInDarkResume(false); EXPECT_CALL(log, Log(_, _, HasSubstr("Not in dark resume, so do nothing"))); OnConnectedAndReachable(start_lease_renewal_timer, kTimeToNextLeaseRenewalLong); ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); ScopeLogger::GetInstance()->set_verbose_level(0); } TEST_F(WakeOnWiFiTestWithMockDispatcher, WakeOnWiFiDisabledAfterResume) { // At least one wake on WiFi trigger supported and Wake on WiFi features // are enabled, so disable Wake on WiFi on resume.] EnableWakeOnWiFiFeaturesPacketDarkConnect(); GetWakeOnWiFiTriggers()->insert(WakeOnWiFi::kWakeTriggerPattern); EXPECT_CALL(netlink_manager_, SendNl80211Message(IsDisableWakeOnWiFiMsg(), _, _, _)).Times(1); EXPECT_CALL(metrics_, NotifySuspendWithWakeOnWiFiEnabledDone()).Times(1); OnAfterResume(); // No wake no WiFi triggers supported, so do nothing. ClearWakeOnWiFiTriggersSupported(); EXPECT_CALL(netlink_manager_, SendNl80211Message(IsDisableWakeOnWiFiMsg(), _, _, _)).Times(0); EXPECT_CALL(metrics_, NotifySuspendWithWakeOnWiFiEnabledDone()).Times(0); OnAfterResume(); // Wake on WiFi features disabled, so do nothing. GetWakeOnWiFiTriggersSupported()->insert(WakeOnWiFi::kWakeTriggerPattern); DisableWakeOnWiFiFeatures(); EXPECT_CALL(netlink_manager_, SendNl80211Message(IsDisableWakeOnWiFiMsg(), _, _, _)).Times(0); EXPECT_CALL(metrics_, NotifySuspendWithWakeOnWiFiEnabledDone()).Times(0); OnAfterResume(); // Both WakeOnWiFi triggers are empty and Wake on WiFi features are disabled, // so do nothing. ClearWakeOnWiFiTriggersSupported(); DisableWakeOnWiFiFeatures(); EXPECT_CALL(netlink_manager_, SendNl80211Message(IsDisableWakeOnWiFiMsg(), _, _, _)).Times(0); EXPECT_CALL(metrics_, NotifySuspendWithWakeOnWiFiEnabledDone()).Times(0); OnAfterResume(); } TEST_F(WakeOnWiFiTestWithMockDispatcher, SetWakeOnWiFiFeaturesEnabled) { const string bad_feature("blahblah"); Error e; EnableWakeOnWiFiFeaturesPacketDarkConnect(); EXPECT_STREQ(GetWakeOnWiFiFeaturesEnabled().c_str(), kWakeOnWiFiFeaturesEnabledPacketDarkConnect); EXPECT_FALSE(SetWakeOnWiFiFeaturesEnabled( kWakeOnWiFiFeaturesEnabledPacketDarkConnect, &e)); EXPECT_STREQ(GetWakeOnWiFiFeaturesEnabled().c_str(), kWakeOnWiFiFeaturesEnabledPacketDarkConnect); EXPECT_FALSE(SetWakeOnWiFiFeaturesEnabled(bad_feature, &e)); EXPECT_EQ(e.type(), Error::kInvalidArguments); EXPECT_STREQ(e.message().c_str(), "Invalid Wake on WiFi feature"); EXPECT_STREQ(GetWakeOnWiFiFeaturesEnabled().c_str(), kWakeOnWiFiFeaturesEnabledPacketDarkConnect); EXPECT_TRUE( SetWakeOnWiFiFeaturesEnabled(kWakeOnWiFiFeaturesEnabledPacket, &e)); EXPECT_STREQ(GetWakeOnWiFiFeaturesEnabled().c_str(), kWakeOnWiFiFeaturesEnabledPacket); } TEST_F(WakeOnWiFiTestWithMockDispatcher, ReportConnectedToServiceAfterWake_WakeOnDarkConnectEnabledAndConnected) { const bool is_connected = true; EnableWakeOnWiFiFeaturesPacketDarkConnect(); EXPECT_CALL( metrics_, NotifyConnectedToServiceAfterWake( Metrics::kWiFiConnetionStatusAfterWakeOnWiFiEnabledWakeConnected)); ReportConnectedToServiceAfterWake(is_connected); EnableWakeOnWiFiFeaturesDarkConnect(); EXPECT_CALL( metrics_, NotifyConnectedToServiceAfterWake( Metrics::kWiFiConnetionStatusAfterWakeOnWiFiEnabledWakeConnected)); ReportConnectedToServiceAfterWake(is_connected); } TEST_F( WakeOnWiFiTestWithMockDispatcher, ReportConnectedToServiceAfterWake_WakeOnDarkConnectEnabledAndNotConnected) { const bool is_connected = false; EnableWakeOnWiFiFeaturesPacketDarkConnect(); EXPECT_CALL( metrics_, NotifyConnectedToServiceAfterWake( Metrics::kWiFiConnetionStatusAfterWakeOnWiFiEnabledWakeNotConnected)); ReportConnectedToServiceAfterWake(is_connected); EnableWakeOnWiFiFeaturesDarkConnect(); EXPECT_CALL( metrics_, NotifyConnectedToServiceAfterWake( Metrics::kWiFiConnetionStatusAfterWakeOnWiFiEnabledWakeNotConnected)); ReportConnectedToServiceAfterWake(is_connected); } TEST_F( WakeOnWiFiTestWithMockDispatcher, ReportConnectedToServiceAfterWake_WakeOnDarkConnectDisabledAndConnected) { const bool is_connected = true; EnableWakeOnWiFiFeaturesPacket(); EXPECT_CALL( metrics_, NotifyConnectedToServiceAfterWake( Metrics::kWiFiConnetionStatusAfterWakeOnWiFiDisabledWakeConnected)); ReportConnectedToServiceAfterWake(is_connected); DisableWakeOnWiFiFeatures(); EXPECT_CALL( metrics_, NotifyConnectedToServiceAfterWake( Metrics::kWiFiConnetionStatusAfterWakeOnWiFiDisabledWakeConnected)); ReportConnectedToServiceAfterWake(is_connected); } TEST_F( WakeOnWiFiTestWithMockDispatcher, ReportConnectedToServiceAfterWake_WakeOnDarkConnectDisabledAndNotConnected) { const bool is_connected = false; EnableWakeOnWiFiFeaturesPacket(); EXPECT_CALL( metrics_, NotifyConnectedToServiceAfterWake( Metrics:: kWiFiConnetionStatusAfterWakeOnWiFiDisabledWakeNotConnected)); ReportConnectedToServiceAfterWake(is_connected); DisableWakeOnWiFiFeatures(); EXPECT_CALL( metrics_, NotifyConnectedToServiceAfterWake( Metrics:: kWiFiConnetionStatusAfterWakeOnWiFiDisabledWakeNotConnected)); ReportConnectedToServiceAfterWake(is_connected); } TEST_F(WakeOnWiFiTestWithMockDispatcher, OnNoAutoConnectableServicesAfterScan_InDarkResume) { vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); EnableWakeOnWiFiFeaturesDarkConnect(); SetInDarkResume(true); // Perform disconnect before suspend actions if we are in dark resume. GetWakeOnWiFiTriggers()->clear(); StartDHCPLeaseRenewalTimer(); StopWakeToScanTimer(); OnNoAutoConnectableServicesAfterScan(whitelist); EXPECT_FALSE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_FALSE(WakeToScanTimerIsRunning()); EXPECT_EQ(GetWakeOnWiFiTriggers()->size(), 1); EXPECT_TRUE(GetWakeOnWiFiTriggers()->find(WakeOnWiFi::kWakeTriggerSSID) != GetWakeOnWiFiTriggers()->end()); } TEST_F(WakeOnWiFiTestWithMockDispatcher, OnNoAutoConnectableServicesAfterScan_NotInDarkResume) { vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); EnableWakeOnWiFiFeaturesDarkConnect(); SetInDarkResume(false); // If we are not in dark resume, do nothing. GetWakeOnWiFiTriggers()->clear(); StartDHCPLeaseRenewalTimer(); StopWakeToScanTimer(); OnNoAutoConnectableServicesAfterScan(whitelist); EXPECT_TRUE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_EQ(GetWakeOnWiFiTriggers()->size(), 0); } TEST_F(WakeOnWiFiTestWithMockDispatcher, OnNoAutoConnectableServicesAfterScan_Retry) { vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); EnableWakeOnWiFiFeaturesDarkConnect(); SetInDarkResume(true); SetDarkResumeScanRetriesLeft(1); // Perform a retry. EXPECT_EQ(1, GetDarkResumeScanRetriesLeft()); EXPECT_CALL(metrics_, NotifyDarkResumeScanRetry()); EXPECT_CALL(*this, InitiateScanCallback(GetLastSSIDMatchFreqs())); OnNoAutoConnectableServicesAfterScan(whitelist); EXPECT_EQ(0, GetDarkResumeScanRetriesLeft()); // Still no auto-connectable services after retry. No more retries, so perform // disconnect before suspend actions. GetWakeOnWiFiTriggers()->clear(); StartDHCPLeaseRenewalTimer(); StopWakeToScanTimer(); EXPECT_CALL(*this, InitiateScanCallback(GetLastSSIDMatchFreqs())).Times(0); OnNoAutoConnectableServicesAfterScan(whitelist); EXPECT_FALSE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_FALSE(WakeToScanTimerIsRunning()); EXPECT_EQ(GetWakeOnWiFiTriggers()->size(), 1); EXPECT_TRUE(GetWakeOnWiFiTriggers()->find(WakeOnWiFi::kWakeTriggerSSID) != GetWakeOnWiFiTriggers()->end()); } TEST_F(WakeOnWiFiTestWithMockDispatcher, OnWakeupReasonReceived_Unsupported) { ScopedMockLog log; ScopeLogger::GetInstance()->EnableScopesByName("wifi"); ScopeLogger::GetInstance()->set_verbose_level(3); SetWiphyIndex(kWakeReasonNlMsg_WiphyIndex); SetWakeOnPacketConnMessage msg; NetlinkPacket packet( kWakeReasonUnsupportedNlMsg, sizeof(kWakeReasonUnsupportedNlMsg)); msg.InitFromPacket(&packet, GetWakeupReportMsgContext()); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); EXPECT_CALL(log, Log(_, _, HasSubstr("Wakeup reason: Not wake on WiFi related"))); EXPECT_CALL(metrics_, NotifyWakeupReasonReceived()); EXPECT_CALL(*this, RecordDarkResumeWakeReasonCallback(_)).Times(0); OnWakeupReasonReceived(msg); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); ScopeLogger::GetInstance()->set_verbose_level(0); } TEST_F(WakeOnWiFiTestWithMockDispatcher, OnWakeupReasonReceived_Disconnect) { ScopedMockLog log; ScopeLogger::GetInstance()->EnableScopesByName("wifi"); ScopeLogger::GetInstance()->set_verbose_level(3); SetWiphyIndex(kWakeReasonNlMsg_WiphyIndex); SetWakeOnPacketConnMessage msg; NetlinkPacket packet( kWakeReasonDisconnectNlMsg, sizeof(kWakeReasonDisconnectNlMsg)); msg.InitFromPacket(&packet, GetWakeupReportMsgContext()); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); EXPECT_CALL(log, Log(_, _, HasSubstr("Wakeup reason: Disconnect"))); EXPECT_CALL(metrics_, NotifyWakeupReasonReceived()); EXPECT_CALL(*this, RecordDarkResumeWakeReasonCallback( WakeOnWiFi::kWakeReasonStringDisconnect)); OnWakeupReasonReceived(msg); EXPECT_EQ(WakeOnWiFi::kWakeTriggerDisconnect, GetLastWakeReason()); ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); ScopeLogger::GetInstance()->set_verbose_level(0); } TEST_F(WakeOnWiFiTestWithMockDispatcher, OnWakeupReasonReceived_SSID) { ScopedMockLog log; ScopeLogger::GetInstance()->EnableScopesByName("wifi"); ScopeLogger::GetInstance()->set_verbose_level(3); SetWiphyIndex(kWakeReasonNlMsg_WiphyIndex); SetWakeOnPacketConnMessage msg; NetlinkPacket packet(kWakeReasonSSIDNlMsg, sizeof(kWakeReasonSSIDNlMsg)); msg.InitFromPacket(&packet, GetWakeupReportMsgContext()); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); EXPECT_CALL(log, Log(_, _, HasSubstr("Wakeup reason: SSID"))); EXPECT_CALL(metrics_, NotifyWakeupReasonReceived()); EXPECT_CALL(*this, RecordDarkResumeWakeReasonCallback( WakeOnWiFi::kWakeReasonStringSSID)); OnWakeupReasonReceived(msg); EXPECT_EQ(WakeOnWiFi::kWakeTriggerSSID, GetLastWakeReason()); EXPECT_EQ(arraysize(kSSID1FreqMatches), GetLastSSIDMatchFreqs().size()); for (uint32_t freq : kSSID1FreqMatches) { EXPECT_TRUE(GetLastSSIDMatchFreqs().find(freq) != GetLastSSIDMatchFreqs().end()); } ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); ScopeLogger::GetInstance()->set_verbose_level(0); } TEST_F(WakeOnWiFiTestWithMockDispatcher, OnWakeupReasonReceived_Pattern) { ScopedMockLog log; ScopeLogger::GetInstance()->EnableScopesByName("wifi"); ScopeLogger::GetInstance()->set_verbose_level(3); SetWiphyIndex(kWakeReasonNlMsg_WiphyIndex); SetWakeOnPacketConnMessage msg; NetlinkPacket packet( kWakeReasonPatternNlMsg, sizeof(kWakeReasonPatternNlMsg)); msg.InitFromPacket(&packet, GetWakeupReportMsgContext()); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); EXPECT_CALL(log, Log(_, _, HasSubstr("Wakeup reason: Pattern " + kWakeReasonPatternNlMsg_PattIndex))); EXPECT_CALL(metrics_, NotifyWakeupReasonReceived()); EXPECT_CALL(*this, RecordDarkResumeWakeReasonCallback( WakeOnWiFi::kWakeReasonStringPattern)); OnWakeupReasonReceived(msg); EXPECT_EQ(WakeOnWiFi::kWakeTriggerPattern, GetLastWakeReason()); ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); ScopeLogger::GetInstance()->set_verbose_level(0); } TEST_F(WakeOnWiFiTestWithMockDispatcher, OnWakeupReasonReceived_Error) { ScopedMockLog log; ScopeLogger::GetInstance()->EnableScopesByName("wifi"); ScopeLogger::GetInstance()->set_verbose_level(7); SetWiphyIndex(kWakeReasonNlMsg_WiphyIndex); // kWrongMessageTypeNlMsg has an nlmsg_type of 0x16, which is different from // the 0x13 (i.e. kNl80211FamilyId) that we expect in these unittests. GetWakeOnPacketConnMessage msg0; NetlinkPacket packet0(kWrongMessageTypeNlMsg, sizeof(kWrongMessageTypeNlMsg)); msg0.InitFromPacket(&packet0, GetWakeupReportMsgContext()); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); EXPECT_CALL(log, Log(_, _, HasSubstr("Not a NL80211 Message"))); EXPECT_CALL(metrics_, NotifyWakeupReasonReceived()).Times(0); EXPECT_CALL(*this, RecordDarkResumeWakeReasonCallback(_)).Times(0); OnWakeupReasonReceived(msg0); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); // This message has command NL80211_CMD_GET_WOWLAN, not a // NL80211_CMD_SET_WOWLAN. GetWakeOnPacketConnMessage msg1; NetlinkPacket packet1(kResponseNoIPAddresses, sizeof(kResponseNoIPAddresses)); msg1.InitFromPacket(&packet1, GetWakeupReportMsgContext()); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); EXPECT_CALL(log, Log(_, _, HasSubstr("Not a NL80211_CMD_SET_WOWLAN message"))); EXPECT_CALL(metrics_, NotifyWakeupReasonReceived()).Times(0); EXPECT_CALL(*this, RecordDarkResumeWakeReasonCallback(_)).Times(0); OnWakeupReasonReceived(msg1); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); // Valid message, but wrong wiphy index. SetWiphyIndex(kWakeReasonNlMsg_WiphyIndex + 1); SetWakeOnPacketConnMessage msg2; NetlinkPacket packet( kWakeReasonDisconnectNlMsg, sizeof(kWakeReasonDisconnectNlMsg)); msg2.InitFromPacket(&packet, GetWakeupReportMsgContext()); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); EXPECT_CALL( log, Log(_, _, HasSubstr("Wakeup reason not meant for this interface"))); EXPECT_CALL(metrics_, NotifyWakeupReasonReceived()).Times(0); EXPECT_CALL(*this, RecordDarkResumeWakeReasonCallback(_)).Times(0); OnWakeupReasonReceived(msg2); EXPECT_EQ(WakeOnWiFi::kWakeTriggerUnsupported, GetLastWakeReason()); ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); ScopeLogger::GetInstance()->set_verbose_level(0); } #else // DISABLE_WAKE_ON_WIFI TEST_F(WakeOnWiFiTestWithMockDispatcher, WakeOnWiFiDisabled_AddWakeOnPacketConnection_ReturnsError) { DisableWakeOnWiFiFeatures(); Error e; AddWakeOnPacketConnection("1.1.1.1", &e); EXPECT_EQ(e.type(), Error::kNotSupported); EXPECT_STREQ(e.message().c_str(), WakeOnWiFi::kWakeOnWiFiNotSupported); } TEST_F(WakeOnWiFiTestWithMockDispatcher, WakeOnWiFiDisabled_RemoveWakeOnPacketConnection_ReturnsError) { DisableWakeOnWiFiFeatures(); Error e; RemoveWakeOnPacketConnection("1.1.1.1", &e); EXPECT_EQ(e.type(), Error::kNotSupported); EXPECT_STREQ(e.message().c_str(), WakeOnWiFi::kWakeOnWiFiNotSupported); } TEST_F(WakeOnWiFiTestWithMockDispatcher, WakeOnWiFiDisabled_RemoveAllWakeOnPacketConnections_ReturnsError) { DisableWakeOnWiFiFeatures(); Error e; RemoveAllWakeOnPacketConnections(&e); EXPECT_EQ(e.type(), Error::kNotSupported); EXPECT_STREQ(e.message().c_str(), WakeOnWiFi::kWakeOnWiFiNotSupported); } TEST_F(WakeOnWiFiTestWithMockDispatcher, WakeOnWiFiDisabled_OnBeforeSuspend_ReportsDoneImmediately) { const bool is_connected = true; const bool have_dhcp_lease = true; vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); EXPECT_CALL(*this, DoneCallback(ErrorTypeIs(Error::kSuccess))).Times(1); EXPECT_CALL(*this, RenewDHCPLeaseCallback()).Times(0); OnBeforeSuspend(is_connected, whitelist, have_dhcp_lease, kTimeToNextLeaseRenewalShort); EXPECT_CALL(*this, DoneCallback(ErrorTypeIs(Error::kSuccess))).Times(1); EXPECT_CALL(*this, RenewDHCPLeaseCallback()).Times(0); OnBeforeSuspend(is_connected, whitelist, have_dhcp_lease, kTimeToNextLeaseRenewalLong); } TEST_F(WakeOnWiFiTestWithMockDispatcher, WakeOnWiFiDisabled_OnDarkResume_ReportsDoneImmediately) { const bool is_connected = true; vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); EXPECT_CALL(*this, DoneCallback(ErrorTypeIs(Error::kSuccess))).Times(1); EXPECT_CALL(mock_dispatcher_, PostDelayedTask(_, _)).Times(0); EXPECT_CALL(metrics_, NotifyWakeOnWiFiOnDarkResume(_)).Times(0); OnDarkResume(is_connected, whitelist); EXPECT_CALL(*this, DoneCallback(ErrorTypeIs(Error::kSuccess))).Times(1); EXPECT_CALL(mock_dispatcher_, PostDelayedTask(_, _)).Times(0); EXPECT_CALL(metrics_, NotifyWakeOnWiFiOnDarkResume(_)).Times(0); OnDarkResume(is_connected, whitelist); } TEST_F(WakeOnWiFiTestWithMockDispatcher, WakeOnWiFiDisabled_OnAfterResume_DoesNothing) { DisableWakeOnWiFiFeatures(); EXPECT_CALL(netlink_manager_, SendNl80211Message(_, _, _, _)).Times(0); EXPECT_CALL(metrics_, NotifySuspendWithWakeOnWiFiEnabledDone()).Times(0); OnAfterResume(); } TEST_F(WakeOnWiFiTestWithMockDispatcher, WakeOnWiFiDisabled_SetWakeOnWiFiFeaturesEnabled) { Error e; SetWakeOnWiFiFeaturesNotSupported(); EXPECT_STREQ(GetWakeOnWiFiFeaturesEnabled().c_str(), kWakeOnWiFiFeaturesEnabledNotSupported); EXPECT_FALSE( SetWakeOnWiFiFeaturesEnabled(kWakeOnWiFiFeaturesEnabledNotSupported, &e)); EXPECT_STREQ(GetWakeOnWiFiFeaturesEnabled().c_str(), kWakeOnWiFiFeaturesEnabledNotSupported); EXPECT_EQ(e.type(), Error::kNotSupported); EXPECT_STREQ(e.message().c_str(), WakeOnWiFi::kWakeOnWiFiNotSupported); EXPECT_FALSE( SetWakeOnWiFiFeaturesEnabled(kWakeOnWiFiFeaturesEnabledPacket, &e)); EXPECT_STREQ(GetWakeOnWiFiFeaturesEnabled().c_str(), kWakeOnWiFiFeaturesEnabledNotSupported); EXPECT_EQ(e.type(), Error::kNotSupported); EXPECT_STREQ(e.message().c_str(), WakeOnWiFi::kWakeOnWiFiNotSupported); } TEST_F(WakeOnWiFiTestWithMockDispatcher, WakeOnWiFiDisabled_OnConnectedAndReachable) { ScopedMockLog log; const bool start_lease_renewal_timer = true; ScopeLogger::GetInstance()->EnableScopesByName("wifi"); ScopeLogger::GetInstance()->set_verbose_level(3); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); SetInDarkResume(true); EXPECT_CALL( log, Log(_, _, HasSubstr("Wake on WiFi not supported, so do nothing"))); OnConnectedAndReachable(start_lease_renewal_timer, kTimeToNextLeaseRenewalLong); SetInDarkResume(false); EXPECT_CALL(log, Log(_, _, HasSubstr("Not in dark resume, so do nothing"))); OnConnectedAndReachable(start_lease_renewal_timer, kTimeToNextLeaseRenewalLong); ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); ScopeLogger::GetInstance()->set_verbose_level(0); } TEST_F(WakeOnWiFiTestWithMockDispatcher, WakeOnWiFiDisabled_ReportConnectedToServiceAfterWakeAndConnected) { const bool is_connected = true; EXPECT_CALL( metrics_, NotifyConnectedToServiceAfterWake( Metrics::kWiFiConnetionStatusAfterWakeOnWiFiDisabledWakeConnected)); ReportConnectedToServiceAfterWake(is_connected); } TEST_F(WakeOnWiFiTestWithMockDispatcher, WakeOnWiFiDisabled_ReportConnectedToServiceAfterWakeAndNotConnected) { const bool is_connected = false; EXPECT_CALL( metrics_, NotifyConnectedToServiceAfterWake( Metrics:: kWiFiConnetionStatusAfterWakeOnWiFiDisabledWakeNotConnected)); ReportConnectedToServiceAfterWake(is_connected); } TEST_F(WakeOnWiFiTestWithMockDispatcher, WakeOnWiFiDisabled_OnNoAutoConnectableServicesAfterScan) { vector<ByteString> whitelist; AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); // Do nothing (i.e. do not invoke WakeOnWiFi::BeforeSuspendActions) if wake // on WiFi is not supported, whether or not we are in dark resume. SetInDarkResume(true); GetWakeOnWiFiTriggers()->clear(); StartDHCPLeaseRenewalTimer(); StopWakeToScanTimer(); OnNoAutoConnectableServicesAfterScan(whitelist); EXPECT_FALSE(WakeToScanTimerIsRunning()); EXPECT_TRUE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_EQ(GetWakeOnWiFiTriggers()->size(), 0); SetInDarkResume(false); GetWakeOnWiFiTriggers()->clear(); StartDHCPLeaseRenewalTimer(); StopWakeToScanTimer(); OnNoAutoConnectableServicesAfterScan(whitelist); EXPECT_FALSE(WakeToScanTimerIsRunning()); EXPECT_TRUE(DHCPLeaseRenewalTimerIsRunning()); EXPECT_EQ(GetWakeOnWiFiTriggers()->size(), 0); } TEST_F(WakeOnWiFiTestWithMockDispatcher, WakeOnWiFiDisabled_OnWakeupReasonReceived_DoesNothing) { ScopedMockLog log; ScopeLogger::GetInstance()->EnableScopesByName("wifi"); ScopeLogger::GetInstance()->set_verbose_level(7); SetWakeOnPacketConnMessage msg; NetlinkPacket packet(kWakeReasonSSIDNlMsg, sizeof(kWakeReasonSSIDNlMsg)); msg.InitFromPacket(&packet, GetWakeupReportMsgContext()); EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); EXPECT_CALL( log, Log(_, _, HasSubstr("Wake on WiFi not supported, so do nothing"))); EXPECT_CALL(metrics_, NotifyWakeupReasonReceived()).Times(0); EXPECT_CALL(*this, RecordDarkResumeWakeReasonCallback(_)).Times(0); OnWakeupReasonReceived(msg); ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); ScopeLogger::GetInstance()->set_verbose_level(0); } TEST_F(WakeOnWiFiTestWithMockDispatcher, WakeOnWiFiDisabled_ConfigureSetWakeOnWiFiSettingsMessage_ReturnsFalse) { IPAddressStore no_addresses; IPAddressStore one_address; const char kIPv4AddrString[] = "1.1.1.1"; one_address.AddUnique( IPAddress(string(kIPv4AddrString, sizeof(kIPv4AddrString)))); set<WakeOnWiFi::WakeOnWiFiTrigger> no_trigs; set<WakeOnWiFi::WakeOnWiFiTrigger> one_trig; one_trig.insert(WakeOnWiFi::kWakeTriggerPattern); const int index = 1; // wiphy device number vector<ByteString> whitelist; const uint32_t interval = kNetDetectScanIntervalSeconds; SetWakeOnPacketConnMessage msg; Error e; EXPECT_FALSE(ConfigureSetWakeOnWiFiSettingsMessage( &msg, no_trigs, no_addresses, index, interval, whitelist, &e)); EXPECT_FALSE(ConfigureSetWakeOnWiFiSettingsMessage( &msg, one_trig, one_address, index, interval, whitelist, &e)); } TEST_F(WakeOnWiFiTestWithMockDispatcher, WakeOnWiFiDisabled_WakeOnWiFiSettingsMatch_ReturnsFalse) { // Test that WakeOnWiFi::WakeOnWiFiSettingsMatch unconditionally returns false // when wake-on-WiFi is disabled by testing it against several cases where we // expect it to return true. IPAddressStore all_addresses; set<WakeOnWiFi::WakeOnWiFiTrigger> trigs; vector<ByteString> whitelist; const uint32_t interval = kNetDetectScanIntervalSeconds; GetWakeOnPacketConnMessage msg0; NetlinkPacket packet0(kResponseNoIPAddresses, sizeof(kResponseNoIPAddresses)); msg0.InitFromPacket(&packet0, NetlinkMessage::MessageContext()); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg0, trigs, all_addresses, interval, whitelist)); trigs.insert(WakeOnWiFi::kWakeTriggerPattern); all_addresses.AddUnique( IPAddress(string(kIPV4Address0, sizeof(kIPV4Address0)))); GetWakeOnPacketConnMessage msg1; NetlinkPacket packet1(kResponseIPV40, sizeof(kResponseIPV40)); msg1.InitFromPacket(&packet1, NetlinkMessage::MessageContext()); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg1, trigs, all_addresses, interval, whitelist)); trigs.insert(WakeOnWiFi::kWakeTriggerDisconnect); GetWakeOnPacketConnMessage msg2; NetlinkPacket packet2(kResponseIPV40WakeOnDisconnect, sizeof(kResponseIPV40WakeOnDisconnect)); msg2.InitFromPacket(&packet2, NetlinkMessage::MessageContext()); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg2, trigs, all_addresses, interval, whitelist)); trigs.erase(WakeOnWiFi::kWakeTriggerDisconnect); all_addresses.AddUnique( IPAddress(string(kIPV4Address1, sizeof(kIPV4Address1)))); GetWakeOnPacketConnMessage msg3; NetlinkPacket packet3(kResponseIPV401, sizeof(kResponseIPV401)); msg3.InitFromPacket(&packet3, NetlinkMessage::MessageContext()); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg3, trigs, all_addresses, interval, whitelist)); all_addresses.AddUnique( IPAddress(string(kIPV6Address0, sizeof(kIPV6Address0)))); GetWakeOnPacketConnMessage msg4; NetlinkPacket packet4(kResponseIPV401IPV60, sizeof(kResponseIPV401IPV60)); msg4.InitFromPacket(&packet4, NetlinkMessage::MessageContext()); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg4, trigs, all_addresses, interval, whitelist)); all_addresses.AddUnique( IPAddress(string(kIPV6Address1, sizeof(kIPV6Address1)))); GetWakeOnPacketConnMessage msg5; NetlinkPacket packet5(kResponseIPV401IPV601, sizeof(kResponseIPV401IPV601)); msg5.InitFromPacket(&packet5, NetlinkMessage::MessageContext()); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg5, trigs, all_addresses, interval, whitelist)); all_addresses.Clear(); trigs.clear(); trigs.insert(WakeOnWiFi::kWakeTriggerSSID); AddSSIDToWhitelist(kSSIDBytes1, sizeof(kSSIDBytes1), &whitelist); AddSSIDToWhitelist(kSSIDBytes2, sizeof(kSSIDBytes2), &whitelist); GetWakeOnPacketConnMessage msg6; NetlinkPacket packet6(kResponseWakeOnSSID, sizeof(kResponseWakeOnSSID)); msg6.InitFromPacket(&packet6, NetlinkMessage::MessageContext()); EXPECT_FALSE( WakeOnWiFiSettingsMatch(msg6, trigs, all_addresses, interval, whitelist)); } TEST_F(WakeOnWiFiTestWithMockDispatcher, WakeOnWiFiDisabled_ParseWakeOnWiFiCapabilities_DoesNothing) { // |kNewWiphyNlMsg| should indicate that the NIC supports wake on pattern // (on up to |kNewWiphyNlMsg_MaxPatterns| registered patterns), // supports wake on SSID (on up to |kNewWiphyNlMsg_MaxSSIDs| SSIDs), and // supports wake on disconnect. Test that // WakeOnWiFi::ParseWakeOnWiFiCapabilities does nothing and does not parse // these capabilities when wake-on-WiFi is disabled. ClearWakeOnWiFiTriggersSupported(); SetWakeOnWiFiMaxSSIDs(0); NewWiphyMessage msg; NetlinkPacket packet(kNewWiphyNlMsg, sizeof(kNewWiphyNlMsg)); msg.InitFromPacket(&packet, NetlinkMessage::MessageContext()); ParseWakeOnWiFiCapabilities(msg); EXPECT_TRUE(GetWakeOnWiFiTriggersSupported()->empty()); EXPECT_EQ(0, GetWakeOnWiFiMaxPatterns()); EXPECT_EQ(0, GetWakeOnWiFiMaxSSIDs()); } #endif // DISABLE_WAKE_ON_WIFI } // namespace shill