| // Copyright 2018 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "shill/wifi/wifi.h" |
| |
| #include <gmock/gmock.h> |
| #include <linux/if.h> |
| #include <linux/netlink.h> // Needs typedefs from sys/socket.h. |
| #include <netinet/ether.h> |
| #include <sys/socket.h> |
| |
| #include <iterator> |
| #include <memory> |
| #include <set> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include <base/check.h> |
| #include <base/containers/fixed_flat_set.h> |
| #include <base/files/file_util.h> |
| #include <base/memory/ref_counted.h> |
| #include <base/time/time.h> |
| #include <base/rand_util.h> |
| #include <base/strings/string_number_conversions.h> |
| #include <base/strings/string_split.h> |
| #include <base/strings/string_util.h> |
| #include <base/strings/stringprintf.h> |
| #include <chromeos/dbus/service_constants.h> |
| #include <chromeos/patchpanel/dbus/client.h> |
| #include <net-base/http_url.h> |
| #include <net-base/mac_address.h> |
| #include <net-base/mock_netlink_manager.h> |
| #include <net-base/mock_rtnl_handler.h> |
| #include <net-base/netlink_packet.h> |
| #include <net-base/netlink_message.h> |
| |
| #include "shill/data_types.h" |
| #include "shill/dbus/dbus_control.h" |
| #include "shill/error.h" |
| #include "shill/event_dispatcher.h" |
| #include "shill/manager.h" |
| #include "shill/metrics.h" |
| #include "shill/mock_adaptors.h" |
| #include "shill/mock_control.h" |
| #include "shill/mock_device_info.h" |
| #include "shill/mock_eap_credentials.h" |
| #include "shill/mock_event_dispatcher.h" |
| #include "shill/mock_log.h" |
| #include "shill/mock_manager.h" |
| #include "shill/mock_metrics.h" |
| #include "shill/mock_power_manager.h" |
| #include "shill/mock_time.h" |
| #include "shill/network/mock_network.h" |
| #include "shill/network/network.h" |
| #include "shill/store/key_value_store.h" |
| #include "shill/store/property_store_test.h" |
| #include "shill/supplicant/mock_supplicant_bss_proxy.h" |
| #include "shill/supplicant/mock_supplicant_eap_state_handler.h" |
| #include "shill/supplicant/mock_supplicant_interface_proxy.h" |
| #include "shill/supplicant/mock_supplicant_network_proxy.h" |
| #include "shill/supplicant/mock_supplicant_process_proxy.h" |
| #include "shill/supplicant/supplicant_manager.h" |
| #include "shill/supplicant/wpa_supplicant.h" |
| #include "shill/technology.h" |
| #include "shill/test_event_dispatcher.h" |
| #include "shill/testing.h" |
| #include "shill/wifi/ieee80211.h" |
| #include "shill/wifi/mock_passpoint_credentials.h" |
| #include "shill/wifi/mock_wake_on_wifi.h" |
| #include "shill/wifi/mock_wifi_link_statistics.h" |
| #include "shill/wifi/mock_wifi_provider.h" |
| #include "shill/wifi/mock_wifi_service.h" |
| #include "shill/wifi/nl80211_message.h" |
| #include "shill/wifi/nl80211_message_matchers.h" |
| #include "shill/wifi/passpoint_credentials.h" |
| #include "shill/wifi/wake_on_wifi.h" |
| #include "shill/wifi/wifi_endpoint.h" |
| #include "shill/wifi/wifi_link_statistics.h" |
| #include "shill/wifi/wifi_phy.h" |
| #include "shill/wifi/wifi_service.h" |
| |
| using ::testing::_; |
| using ::testing::AllOf; |
| using ::testing::AnyNumber; |
| using ::testing::AtLeast; |
| using ::testing::ByMove; |
| using ::testing::ContainsRegex; |
| using ::testing::DoAll; |
| using ::testing::EndsWith; |
| using ::testing::Field; |
| using ::testing::HasSubstr; |
| using ::testing::InSequence; |
| using ::testing::Invoke; |
| using ::testing::InvokeWithoutArgs; |
| using ::testing::Mock; |
| using ::testing::MockFunction; |
| using ::testing::NiceMock; |
| using ::testing::Optional; |
| using ::testing::Ref; |
| using ::testing::Return; |
| using ::testing::ReturnRef; |
| using ::testing::SetArgPointee; |
| using ::testing::StrEq; |
| using ::testing::StrictMock; |
| using ::testing::Test; |
| using ::testing::WithArg; |
| |
| namespace shill { |
| |
| namespace { |
| |
| constexpr uint16_t kNl80211FamilyId = 0x13; |
| constexpr int kInterfaceIndex = 1234; |
| constexpr uint32_t kPhyIndex = 5678; |
| constexpr net_base::MacAddress kPermDeviceAddress{0x01, 0x23, 0x45, |
| 0x67, 0x89, 0xab}; |
| |
| // Bytes representing a NL80211_CMD_NEW_WIPHY message reporting the WiFi |
| // capabilities of a NIC with wiphy index |kNewWiphyNlMsg_PhyIndex| which |
| // supports operating bands with the frequencies specified in |
| // |kNewWiphyNlMsg_UniqueFrequencies|. |
| const uint8_t kNewWiphyNlMsg[] = { |
| 0x68, 0x0c, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, |
| 0xf6, 0x31, 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, 0x04, 0x00, 0x00, 0x00, |
| 0x05, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x38, 0x00, |
| 0xd1, 0x08, 0x00, 0x00, 0x06, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x05, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x68, 0x00, |
| 0x04, 0x00, 0x8b, 0x00, 0x04, 0x00, 0x8c, 0x00, 0x18, 0x00, 0x39, 0x00, |
| 0x01, 0xac, 0x0f, 0x00, 0x05, 0xac, 0x0f, 0x00, 0x02, 0xac, 0x0f, 0x00, |
| 0x04, 0xac, 0x0f, 0x00, 0x06, 0xac, 0x0f, 0x00, 0x05, 0x00, 0x56, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x66, 0x00, 0x08, 0x00, 0x71, 0x00, |
| 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x72, 0x00, 0x03, 0x00, 0x00, 0x00, |
| 0x08, 0x00, 0x69, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x6a, 0x00, |
| 0x03, 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, 0x05, 0x00, 0x04, 0x00, 0x06, 0x00, 0x04, 0x00, 0x08, 0x00, |
| 0x04, 0x00, 0x09, 0x00, 0x50, 0x05, 0x16, 0x00, 0xf8, 0x01, 0x00, 0x00, |
| 0x14, 0x00, 0x03, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, |
| 0xef, 0x11, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00, |
| 0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x28, 0x01, 0x01, 0x00, |
| 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x6c, 0x09, 0x00, 0x00, |
| 0x08, 0x00, 0x06, 0x00, 0x6c, 0x07, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, |
| 0x08, 0x00, 0x01, 0x00, 0x71, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, |
| 0x6c, 0x07, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, |
| 0x76, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x6c, 0x07, 0x00, 0x00, |
| 0x14, 0x00, 0x03, 0x00, 0x08, 0x00, 0x01, 0x00, 0x7b, 0x09, 0x00, 0x00, |
| 0x08, 0x00, 0x06, 0x00, 0x6c, 0x07, 0x00, 0x00, 0x14, 0x00, 0x04, 0x00, |
| 0x08, 0x00, 0x01, 0x00, 0x80, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, |
| 0x6c, 0x07, 0x00, 0x00, 0x14, 0x00, 0x05, 0x00, 0x08, 0x00, 0x01, 0x00, |
| 0x85, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x6c, 0x07, 0x00, 0x00, |
| 0x14, 0x00, 0x06, 0x00, 0x08, 0x00, 0x01, 0x00, 0x8a, 0x09, 0x00, 0x00, |
| 0x08, 0x00, 0x06, 0x00, 0x6c, 0x07, 0x00, 0x00, 0x14, 0x00, 0x07, 0x00, |
| 0x08, 0x00, 0x01, 0x00, 0x8f, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, |
| 0x6c, 0x07, 0x00, 0x00, 0x14, 0x00, 0x08, 0x00, 0x08, 0x00, 0x01, 0x00, |
| 0x94, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x6c, 0x07, 0x00, 0x00, |
| 0x14, 0x00, 0x09, 0x00, 0x08, 0x00, 0x01, 0x00, 0x99, 0x09, 0x00, 0x00, |
| 0x08, 0x00, 0x06, 0x00, 0x6c, 0x07, 0x00, 0x00, 0x14, 0x00, 0x0a, 0x00, |
| 0x08, 0x00, 0x01, 0x00, 0x9e, 0x09, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, |
| 0x6c, 0x07, 0x00, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x01, 0x00, |
| 0xa3, 0x09, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x08, 0x00, 0x06, 0x00, |
| 0x6c, 0x07, 0x00, 0x00, 0x18, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x01, 0x00, |
| 0xa8, 0x09, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x08, 0x00, 0x06, 0x00, |
| 0x6c, 0x07, 0x00, 0x00, 0x18, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x01, 0x00, |
| 0xb4, 0x09, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x08, 0x00, 0x06, 0x00, |
| 0xd0, 0x07, 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, 0x54, 0x03, 0x01, 0x00, |
| 0x14, 0x00, 0x03, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, |
| 0xef, 0x11, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x00, |
| 0x05, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc0, 0x02, 0x01, 0x00, |
| 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x3c, 0x14, 0x00, 0x00, |
| 0x08, 0x00, 0x06, 0x00, 0xd0, 0x07, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, |
| 0x08, 0x00, 0x01, 0x00, 0x50, 0x14, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, |
| 0x04, 0x00, 0x04, 0x00, 0x08, 0x00, 0x06, 0x00, 0xd0, 0x07, 0x00, 0x00, |
| 0x14, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x64, 0x14, 0x00, 0x00, |
| 0x08, 0x00, 0x06, 0x00, 0xd0, 0x07, 0x00, 0x00, 0x14, 0x00, 0x03, 0x00, |
| 0x08, 0x00, 0x01, 0x00, 0x78, 0x14, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, |
| 0xd0, 0x07, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x01, 0x00, |
| 0x8c, 0x14, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, |
| 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0xd0, 0x07, 0x00, 0x00, |
| 0x20, 0x00, 0x05, 0x00, 0x08, 0x00, 0x01, 0x00, 0xa0, 0x14, 0x00, 0x00, |
| 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, |
| 0x08, 0x00, 0x06, 0x00, 0xd0, 0x07, 0x00, 0x00, 0x20, 0x00, 0x06, 0x00, |
| 0x08, 0x00, 0x01, 0x00, 0xb4, 0x14, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, |
| 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, |
| 0xd0, 0x07, 0x00, 0x00, 0x20, 0x00, 0x07, 0x00, 0x08, 0x00, 0x01, 0x00, |
| 0xc8, 0x14, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, |
| 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0xd0, 0x07, 0x00, 0x00, |
| 0x20, 0x00, 0x08, 0x00, 0x08, 0x00, 0x01, 0x00, 0x7c, 0x15, 0x00, 0x00, |
| 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, |
| 0x08, 0x00, 0x06, 0x00, 0xd0, 0x07, 0x00, 0x00, 0x20, 0x00, 0x09, 0x00, |
| 0x08, 0x00, 0x01, 0x00, 0x90, 0x15, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, |
| 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, |
| 0xd0, 0x07, 0x00, 0x00, 0x20, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x01, 0x00, |
| 0xa4, 0x15, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, |
| 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0xd0, 0x07, 0x00, 0x00, |
| 0x20, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x01, 0x00, 0xb8, 0x15, 0x00, 0x00, |
| 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, |
| 0x08, 0x00, 0x06, 0x00, 0xd0, 0x07, 0x00, 0x00, 0x20, 0x00, 0x0c, 0x00, |
| 0x08, 0x00, 0x01, 0x00, 0xcc, 0x15, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, |
| 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, |
| 0xd0, 0x07, 0x00, 0x00, 0x20, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x01, 0x00, |
| 0xe0, 0x15, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, |
| 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0xd0, 0x07, 0x00, 0x00, |
| 0x20, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x01, 0x00, 0xf4, 0x15, 0x00, 0x00, |
| 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, |
| 0x08, 0x00, 0x06, 0x00, 0xd0, 0x07, 0x00, 0x00, 0x20, 0x00, 0x0f, 0x00, |
| 0x08, 0x00, 0x01, 0x00, 0x08, 0x16, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, |
| 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, |
| 0xd0, 0x07, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, 0x01, 0x00, |
| 0x1c, 0x16, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, |
| 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, 0xd0, 0x07, 0x00, 0x00, |
| 0x20, 0x00, 0x11, 0x00, 0x08, 0x00, 0x01, 0x00, 0x30, 0x16, 0x00, 0x00, |
| 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, |
| 0x08, 0x00, 0x06, 0x00, 0xd0, 0x07, 0x00, 0x00, 0x20, 0x00, 0x12, 0x00, |
| 0x08, 0x00, 0x01, 0x00, 0x44, 0x16, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, |
| 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x08, 0x00, 0x06, 0x00, |
| 0xd0, 0x07, 0x00, 0x00, 0x14, 0x00, 0x13, 0x00, 0x08, 0x00, 0x01, 0x00, |
| 0x71, 0x16, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0xd0, 0x07, 0x00, 0x00, |
| 0x1c, 0x00, 0x14, 0x00, 0x08, 0x00, 0x01, 0x00, 0x85, 0x16, 0x00, 0x00, |
| 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x08, 0x00, 0x06, 0x00, |
| 0xd0, 0x07, 0x00, 0x00, 0x1c, 0x00, 0x15, 0x00, 0x08, 0x00, 0x01, 0x00, |
| 0x99, 0x16, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, |
| 0x08, 0x00, 0x06, 0x00, 0xd0, 0x07, 0x00, 0x00, 0x1c, 0x00, 0x16, 0x00, |
| 0x08, 0x00, 0x01, 0x00, 0xad, 0x16, 0x00, 0x00, 0x04, 0x00, 0x03, 0x00, |
| 0x04, 0x00, 0x04, 0x00, 0x08, 0x00, 0x06, 0x00, 0xd0, 0x07, 0x00, 0x00, |
| 0x1c, 0x00, 0x17, 0x00, 0x08, 0x00, 0x01, 0x00, 0xc1, 0x16, 0x00, 0x00, |
| 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x08, 0x00, 0x06, 0x00, |
| 0xd0, 0x07, 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, 0xd4, 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, 0x52, 0x00, 0x00, 0x00, 0x08, 0x00, 0x14, 0x00, |
| 0x51, 0x00, 0x00, 0x00, 0x08, 0x00, 0x15, 0x00, 0x54, 0x00, 0x00, 0x00, |
| 0x08, 0x00, 0x16, 0x00, 0x57, 0x00, 0x00, 0x00, 0x08, 0x00, 0x17, 0x00, |
| 0x55, 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0x2d, 0x00, 0x00, 0x00, |
| 0x08, 0x00, 0x19, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1a, 0x00, |
| 0x30, 0x00, 0x00, 0x00, 0x08, 0x00, 0x6f, 0x00, 0x88, 0x13, 0x00, 0x00, |
| 0x04, 0x00, 0x6c, 0x00, 0xac, 0x03, 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, 0x14, 0x01, 0x64, 0x00, |
| 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 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, 0x0c, 0x00, 0x79, 0x00, |
| 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x06, 0x00, 0x50, 0x00, 0x78, 0x00, |
| 0x4c, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x01, 0x00, |
| 0x08, 0x00, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, |
| 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x05, 0x00, 0x04, 0x00, 0x08, 0x00, |
| 0x18, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, |
| 0x0c, 0x00, 0x02, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x09, 0x00, |
| 0x08, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, |
| 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x8f, 0x00, 0x03, 0x00, 0x00, 0x00, |
| 0x1e, 0x00, 0x94, 0x00, 0x42, 0x08, 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}; |
| const uint32_t kNewWiphyNlMsg_PhyIndex = 2; |
| const uint32_t kNewWiphyNlMsg_ChangedPhyIndex = 3; |
| const int kNewWiphyNlMsg_Nl80211AttrWiphyOffset = 4; |
| |
| const uint32_t kScanTriggerMsgPhyIndex = 0; |
| const uint8_t kActiveScanTriggerNlMsg[] = { |
| 0x44, 0x01, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, |
| 0x0c, 0x00, 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x08, 0x00, 0x2d, 0x00, 0x04, 0x00, 0x00, 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}; |
| |
| const uint8_t kPassiveScanTriggerNlMsg[] = { |
| 0x40, 0x01, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, |
| 0x0c, 0x00, 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x04, 0x00, 0x2d, 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}; |
| |
| void AddVendorIE(uint32_t oui, |
| uint8_t vendor_type, |
| const std::vector<uint8_t>& data, |
| std::vector<uint8_t>* ies) { |
| ies->push_back(IEEE_80211::kElemIdVendor); // type |
| ies->push_back(4 + data.size()); // length |
| ies->push_back((oui >> 16) & 0xff); // OUI MSByte |
| ies->push_back((oui >> 8) & 0xff); // OUI middle octet |
| ies->push_back(oui & 0xff); // OUI LSByte |
| ies->push_back(vendor_type); // OUI Type |
| ies->insert(ies->end(), data.begin(), data.end()); |
| } |
| |
| void AddIEWithData(uint8_t type, |
| std::vector<uint8_t> data, |
| std::vector<uint8_t>* ies) { |
| ies->push_back(type); // type |
| ies->push_back(data.size()); // length |
| ies->insert(ies->end(), data.begin(), data.end()); |
| } |
| |
| void AddANQPCapability(uint16_t cap, std::vector<uint8_t>* ies) { |
| ies->push_back(cap); // cap LSByte |
| ies->push_back(cap >> 8); // cap MSByte |
| } |
| |
| } // namespace |
| |
| class WiFiPropertyTest : public PropertyStoreTest { |
| public: |
| WiFiPropertyTest() |
| : device_(new WiFi(manager(), |
| "wifi", |
| std::nullopt, |
| kInterfaceIndex, |
| kPhyIndex, |
| std::make_unique<MockWakeOnWiFi>())) {} |
| ~WiFiPropertyTest() override = default; |
| |
| protected: |
| MockMetrics metrics_; |
| net_base::MockNetlinkManager netlink_manager_; |
| WiFiRefPtr device_; |
| }; |
| |
| TEST_F(WiFiPropertyTest, Contains) { |
| EXPECT_TRUE(device_->store().Contains(kNameProperty)); |
| EXPECT_FALSE(device_->store().Contains("")); |
| } |
| |
| TEST_F(WiFiPropertyTest, SetProperty) { |
| { |
| Error error; |
| device_->mutable_store()->SetAnyProperty( |
| kBgscanSignalThresholdProperty, PropertyStoreTest::kInt32V, &error); |
| EXPECT_TRUE(error.IsSuccess()); |
| } |
| { |
| Error error; |
| device_->mutable_store()->SetAnyProperty( |
| kScanIntervalProperty, PropertyStoreTest::kUint16V, &error); |
| EXPECT_TRUE(error.IsSuccess()); |
| } |
| // Ensure that an attempt to write a R/O property returns InvalidArgs error. |
| { |
| Error error; |
| device_->mutable_store()->SetAnyProperty(kScanningProperty, |
| PropertyStoreTest::kBoolV, &error); |
| ASSERT_TRUE(error.IsFailure()); |
| EXPECT_EQ(Error::kInvalidArguments, error.type()); |
| } |
| |
| { |
| Error error; |
| device_->mutable_store()->SetAnyProperty( |
| kBgscanMethodProperty, |
| brillo::Any(std::string(WPASupplicant::kNetworkBgscanMethodSimple)), |
| &error); |
| EXPECT_TRUE(error.IsSuccess()); |
| } |
| |
| { |
| Error error; |
| device_->mutable_store()->SetAnyProperty( |
| kBgscanMethodProperty, |
| brillo::Any(std::string("not a real scan method")), &error); |
| ASSERT_TRUE(error.IsFailure()); |
| EXPECT_EQ(Error::kInvalidArguments, error.type()); |
| } |
| } |
| |
| TEST_F(WiFiPropertyTest, BgscanMethodProperty) { |
| EXPECT_NE(WPASupplicant::kNetworkBgscanMethodLearn, |
| WiFi::kDefaultBgscanMethod); |
| EXPECT_TRUE(device_->bgscan_method_.empty()); |
| |
| std::string method; |
| Error unused_error; |
| EXPECT_TRUE(device_->store().GetStringProperty(kBgscanMethodProperty, &method, |
| &unused_error)); |
| EXPECT_EQ(WiFi::kDefaultBgscanMethod, method); |
| EXPECT_EQ(WPASupplicant::kNetworkBgscanMethodSimple, method); |
| |
| Error error; |
| device_->mutable_store()->SetAnyProperty( |
| kBgscanMethodProperty, |
| brillo::Any(std::string(WPASupplicant::kNetworkBgscanMethodLearn)), |
| &error); |
| EXPECT_TRUE(error.IsSuccess()); |
| EXPECT_EQ(WPASupplicant::kNetworkBgscanMethodLearn, device_->bgscan_method_); |
| EXPECT_TRUE(device_->store().GetStringProperty(kBgscanMethodProperty, &method, |
| &unused_error)); |
| EXPECT_EQ(WPASupplicant::kNetworkBgscanMethodLearn, method); |
| |
| EXPECT_TRUE( |
| device_->mutable_store()->ClearProperty(kBgscanMethodProperty, &error)); |
| EXPECT_TRUE(device_->store().GetStringProperty(kBgscanMethodProperty, &method, |
| &unused_error)); |
| EXPECT_EQ(WiFi::kDefaultBgscanMethod, method); |
| EXPECT_TRUE(device_->bgscan_method_.empty()); |
| } |
| |
| MATCHER_P(EndpointMatch, endpoint, "") { |
| return arg->ssid() == endpoint->ssid() && |
| arg->network_mode() == endpoint->network_mode() && |
| arg->security_mode() == endpoint->security_mode(); |
| } |
| |
| class WiFiObjectTest : public ::testing::TestWithParam<std::string> { |
| public: |
| explicit WiFiObjectTest(std::unique_ptr<EventDispatcher> dispatcher) |
| : event_dispatcher_(std::move(dispatcher)), |
| manager_(&control_interface_, event_dispatcher_.get(), &metrics_), |
| power_manager_(new MockPowerManager(control_interface())), |
| wifi_provider_(&manager_), |
| supplicant_process_proxy_(new NiceMock<MockSupplicantProcessProxy>()), |
| supplicant_bss_proxy_(new NiceMock<MockSupplicantBSSProxy>()), |
| dhcp_hostname_("chromeos"), |
| adaptor_(new DeviceMockAdaptor()), |
| eap_state_handler_(new NiceMock<MockSupplicantEAPStateHandler>()), |
| wifi_link_statistics_(new NiceMock<MockWiFiLinkStatistics>()), |
| supplicant_interface_proxy_( |
| new NiceMock<MockSupplicantInterfaceProxy>()), |
| supplicant_network_proxy_(new NiceMock<MockSupplicantNetworkProxy>()) { |
| ON_CALL(*device_info(), GetPermAddress(kInterfaceIndex)) |
| .WillByDefault(Return(kPermDeviceAddress)); |
| wifi_ = new WiFi(&manager_, kDeviceName, kDeviceAddress, kInterfaceIndex, |
| kPhyIndex, std::make_unique<MockWakeOnWiFi>()); |
| manager_.supplicant_manager()->set_proxy(supplicant_process_proxy_); |
| ON_CALL(*supplicant_process_proxy_, CreateInterface(_, _)) |
| .WillByDefault(DoAll(SetArgPointee<1>(RpcIdentifier("/default/path")), |
| Return(true))); |
| ON_CALL(*supplicant_process_proxy_, GetInterface(_, _)) |
| .WillByDefault(DoAll(SetArgPointee<1>(RpcIdentifier("/default/path")), |
| Return(true))); |
| ON_CALL(*supplicant_interface_proxy_, AddNetwork(_, _)) |
| .WillByDefault(DoAll(SetArgPointee<1>(RpcIdentifier("/default/path")), |
| Return(true))); |
| ON_CALL(*supplicant_interface_proxy_, Disconnect()) |
| .WillByDefault(Return(true)); |
| ON_CALL(*supplicant_interface_proxy_, RemoveNetwork(_)) |
| .WillByDefault(Return(true)); |
| ON_CALL(*supplicant_interface_proxy_, Scan(_)).WillByDefault(Return(true)); |
| ON_CALL(*supplicant_interface_proxy_, EnableMacAddressRandomization(_, _)) |
| .WillByDefault(Return(true)); |
| ON_CALL(*supplicant_interface_proxy_, DisableMacAddressRandomization()) |
| .WillByDefault(Return(true)); |
| ON_CALL(*supplicant_network_proxy_, SetEnabled(_)) |
| .WillByDefault(Return(true)); |
| |
| ON_CALL(*manager(), IsSuspending()).WillByDefault(Return(false)); |
| |
| ON_CALL(control_interface_, CreateSupplicantInterfaceProxy(_, _)) |
| .WillByDefault( |
| Invoke(this, &WiFiObjectTest::CreateSupplicantInterfaceProxy)); |
| ON_CALL(control_interface_, CreateSupplicantBSSProxy(_, _)) |
| .WillByDefault(Invoke(this, &WiFiObjectTest::CreateSupplicantBSSProxy)); |
| ON_CALL(control_interface_, CreateSupplicantNetworkProxy(_)) |
| .WillByDefault( |
| Invoke(this, &WiFiObjectTest::CreateSupplicantNetworkProxy)); |
| Nl80211Message::SetMessageType(kNl80211FamilyId); |
| |
| auto network = std::make_unique<MockNetwork>(kInterfaceIndex, kDeviceName, |
| Technology::kWiFi); |
| network_ = network.get(); |
| wifi_->set_network_for_testing(std::move(network)); |
| |
| // Transfers ownership. |
| wifi_->eap_state_handler_.reset(eap_state_handler_); |
| |
| wifi_->provider_ = &wifi_provider_; |
| wifi_->time_ = &time_; |
| wifi_->netlink_manager_ = &netlink_manager_; |
| wifi_->adaptor_.reset(adaptor_); // Transfers ownership. |
| wifi_->wifi_link_statistics_.reset(wifi_link_statistics_); |
| |
| manager_.set_power_manager(power_manager_); // Transfers ownership. |
| |
| wake_on_wifi_ = static_cast<MockWakeOnWiFi*>(wifi_->wake_on_wifi_.get()); |
| } |
| |
| void SetUp() override { |
| // EnableScopes... so that we can EXPECT_CALL for scoped log messages. |
| ScopeLogger::GetInstance()->EnableScopesByName("wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(3); |
| static_cast<Device*>(wifi_.get())->rtnl_handler_ = &rtnl_handler_; |
| EXPECT_CALL(manager_, UpdateEnabledTechnologies()).Times(AnyNumber()); |
| EXPECT_CALL(manager_, CreateDefaultDHCPOption()) |
| .WillRepeatedly(Return(DHCPProvider::Options{ |
| .use_arp_gateway = true, |
| .hostname = dhcp_hostname_, |
| })); |
| EXPECT_CALL(*supplicant_bss_proxy_, Die()).Times(AnyNumber()); |
| } |
| |
| void TearDown() override { |
| EXPECT_CALL(*wifi_provider(), OnEndpointRemoved(_)) |
| .WillRepeatedly(Return(nullptr)); |
| wifi_->SelectService(nullptr); |
| if (supplicant_bss_proxy_) { |
| EXPECT_CALL(*supplicant_bss_proxy_, Die()); |
| } |
| // must Stop WiFi instance, to clear its list of services. |
| // otherwise, the WiFi instance will not be deleted. (because |
| // services reference a WiFi instance, creating a cycle.) |
| wifi_->Stop(base::DoNothing()); |
| // Reset scope logging, to avoid interfering with other tests. |
| ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(0); |
| } |
| |
| // Needs to be public since it is called via Invoke(). |
| void StopWiFi() { |
| wifi_->SetEnabled(false); // Stop(nullptr, ResultCallback()); |
| } |
| |
| void ResetPendingService() { SetPendingService(nullptr); } |
| |
| void SetScanState(WiFiState::PhyState new_state, |
| WiFiState::ScanMethod new_method, |
| const char* reason) { |
| wifi_->SetPhyState(new_state, new_method, reason); |
| } |
| |
| void VerifyScanState(WiFiState::PhyState state, |
| WiFiState::ScanMethod method) const { |
| EXPECT_EQ(state, wifi_->wifi_state_->GetPhyState()); |
| EXPECT_EQ(method, wifi_->wifi_state_->GetScanMethod()); |
| } |
| |
| void VerifyEnsuredScanState(WiFiState::EnsuredScanState state) const { |
| EXPECT_EQ(state, wifi_->wifi_state_->GetEnsuredScanState()); |
| } |
| |
| void PropertiesChanged(const KeyValueStore& props) { |
| wifi_->PropertiesChanged(props); |
| } |
| |
| void SignalChanged(const KeyValueStore& props) { |
| wifi_->SignalChanged(props); |
| } |
| |
| void SelectService(const WiFiServiceRefPtr& service) { |
| wifi_->SelectService(service); |
| } |
| |
| bool UpdateSupplicantProperties(const WiFiService* service, |
| const KeyValueStore& kv, |
| Error* error) { |
| return wifi_->UpdateSupplicantProperties(service, kv, error); |
| } |
| |
| void Scan(Error* error, const std::string& reason, bool is_dbus_call) { |
| wifi_->Scan(error, reason, is_dbus_call); |
| } |
| |
| void TermsAndConditions(const std::string& url) { |
| wifi_->TermsAndConditions(url); |
| } |
| |
| void ANQPQueryDone(const std::string& addr, const std::string& result) { |
| wifi_->ANQPQueryDone(addr, result); |
| } |
| |
| void NotifyANQPInformationChanged(const WiFiEndpointConstRefPtr& endpoint) { |
| wifi_->NotifyANQPInformationChanged(endpoint); |
| } |
| |
| WiFiPhy::Priority GetPriority() { return wifi_->priority(); } |
| |
| bool SetPriority(WiFiPhy::Priority priority) { |
| return wifi_->SetPriority(priority); |
| } |
| |
| protected: |
| using MockWiFiServiceRefPtr = scoped_refptr<MockWiFiService>; |
| using MockPasspointCredentialsRefPtr = |
| scoped_refptr<MockPasspointCredentials>; |
| |
| // Simulate the course of events when the last endpoint of a service is |
| // removed. |
| class EndpointRemovalHandler { |
| public: |
| EndpointRemovalHandler(WiFiRefPtr wifi, const WiFiServiceRefPtr& service) |
| : wifi_(wifi), service_(service) {} |
| virtual ~EndpointRemovalHandler() = default; |
| |
| WiFiServiceRefPtr OnEndpointRemoved( |
| const WiFiEndpointConstRefPtr& endpoint) { |
| wifi_->DisassociateFromService(service_); |
| return service_; |
| } |
| |
| private: |
| WiFiRefPtr wifi_; |
| WiFiServiceRefPtr service_; |
| }; |
| |
| std::unique_ptr<EndpointRemovalHandler> MakeEndpointRemovalHandler( |
| const WiFiServiceRefPtr& service) { |
| return std::make_unique<EndpointRemovalHandler>(wifi_, service); |
| } |
| |
| void CancelScanTimer() { wifi_->scan_timer_callback_.Cancel(); } |
| // This function creates a new endpoint. We synthesize new |path| and |
| // |bssid| values, since we don't really care what they are for unit tests. |
| // If "use_ssid" is true, we used the passed-in ssid, otherwise we create a |
| // synthesized value for it as well. |
| WiFiEndpointRefPtr MakeNewEndpoint(bool use_ssid, |
| std::string* ssid, |
| RpcIdentifier* path, |
| net_base::MacAddress* bssid) { |
| bss_counter_++; |
| if (!use_ssid) { |
| *ssid = base::StringPrintf("ssid%d", bss_counter_); |
| } |
| *path = RpcIdentifier(base::StringPrintf("/interface/bss%d", bss_counter_)); |
| *bssid = net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, bss_counter_); |
| WiFiEndpointRefPtr endpoint = MakeEndpoint(*ssid, *bssid); |
| EXPECT_CALL(wifi_provider_, OnEndpointAdded(EndpointMatch(endpoint))) |
| .Times(1); |
| return endpoint; |
| } |
| WiFiEndpointRefPtr MakeEndpoint(const std::string& ssid, |
| net_base::MacAddress bssid) { |
| return MakeEndpointWithMode(ssid, bssid, kNetworkModeInfrastructure); |
| } |
| WiFiEndpointRefPtr MakeEndpointWithMode(const std::string& ssid, |
| net_base::MacAddress bssid, |
| const std::string& mode) { |
| return WiFiEndpoint::MakeOpenEndpoint(&control_interface_, nullptr, ssid, |
| bssid, mode, 0, 0); |
| } |
| MockWiFiServiceRefPtr MakeMockServiceWithSSID(std::vector<uint8_t> ssid, |
| const WiFiSecurity& security) { |
| return new NiceMock<MockWiFiService>(&manager_, &wifi_provider_, ssid, |
| kModeManaged, security.SecurityClass(), |
| security, false); |
| } |
| MockWiFiServiceRefPtr MakeMockService(const WiFiSecurity& security) { |
| return MakeMockServiceWithSSID(std::vector<uint8_t>(1, 'a'), security); |
| } |
| RpcIdentifier MakeNewEndpointAndService(int16_t signal_strength, |
| uint16_t frequency, |
| WiFiEndpointRefPtr* endpoint_ptr, |
| MockWiFiServiceRefPtr* service_ptr) { |
| std::string ssid; |
| RpcIdentifier path; |
| net_base::MacAddress bssid; |
| WiFiEndpointRefPtr endpoint = MakeNewEndpoint(false, &ssid, &path, &bssid); |
| MockWiFiServiceRefPtr service = |
| MakeMockServiceWithSSID(endpoint->ssid(), endpoint->security_mode()); |
| EXPECT_CALL(wifi_provider_, FindServiceForEndpoint(EndpointMatch(endpoint))) |
| .WillRepeatedly(Return(service)); |
| ON_CALL(*service, GetBSSIDConnectableEndpointCount()) |
| .WillByDefault(Return(1)); |
| ReportBSS(path, ssid, bssid, signal_strength, frequency, |
| kNetworkModeInfrastructure, 0); |
| if (service_ptr) { |
| *service_ptr = service; |
| } |
| if (endpoint_ptr) { |
| *endpoint_ptr = endpoint; |
| } |
| return path; |
| } |
| RpcIdentifier AddEndpointToService(WiFiServiceRefPtr service, |
| int16_t signal_strength, |
| uint16_t frequency, |
| WiFiEndpointRefPtr* endpoint_ptr) { |
| std::string ssid(service->ssid().begin(), service->ssid().end()); |
| RpcIdentifier path; |
| net_base::MacAddress bssid; |
| WiFiEndpointRefPtr endpoint = MakeNewEndpoint(true, &ssid, &path, &bssid); |
| EXPECT_CALL(wifi_provider_, FindServiceForEndpoint(EndpointMatch(endpoint))) |
| .WillRepeatedly(Return(service)); |
| ReportBSS(path, ssid, bssid, signal_strength, frequency, |
| kNetworkModeInfrastructure, 0); |
| if (endpoint_ptr) { |
| *endpoint_ptr = endpoint; |
| } |
| return path; |
| } |
| void InitiateConnect(WiFiServiceRefPtr service) { |
| Error error; |
| wifi_->ConnectTo(service.get(), &error); |
| } |
| void InitiateDisconnect(WiFiServiceRefPtr service) { |
| wifi_->DisconnectFrom(service.get()); |
| } |
| void InitiateDisconnectIfActive(WiFiServiceRefPtr service) { |
| wifi_->DisconnectFromIfActive(service.get()); |
| } |
| MockWiFiServiceRefPtr SetupConnectingService( |
| const RpcIdentifier& network_path, |
| WiFiEndpointRefPtr* endpoint_ptr, |
| RpcIdentifier* bss_path_ptr) { |
| MockWiFiServiceRefPtr service; |
| WiFiEndpointRefPtr endpoint; |
| RpcIdentifier bss_path( |
| MakeNewEndpointAndService(0, 0, &endpoint, &service)); |
| if (!network_path.value().empty()) { |
| EXPECT_CALL(*service, GetSupplicantConfigurationParameters()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), AddNetwork(_, _)) |
| .WillOnce(DoAll(SetArgPointee<1>(network_path), Return(true))); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), SelectNetwork(network_path)); |
| } |
| InitiateConnect(service); |
| EXPECT_EQ(service->state(), Service::kStateAssociating); |
| Mock::VerifyAndClearExpectations(service.get()); |
| EXPECT_FALSE(GetPendingTimeout().IsCancelled()); |
| if (endpoint_ptr) { |
| *endpoint_ptr = endpoint; |
| } |
| if (bss_path_ptr) { |
| *bss_path_ptr = bss_path; |
| } |
| return service; |
| } |
| |
| MockWiFiServiceRefPtr SetupConnectedService(const RpcIdentifier& network_path, |
| WiFiEndpointRefPtr* endpoint_ptr, |
| RpcIdentifier* bss_path_ptr) { |
| WiFiEndpointRefPtr endpoint; |
| RpcIdentifier bss_path; |
| MockWiFiServiceRefPtr service = |
| SetupConnectingService(network_path, &endpoint, &bss_path); |
| if (endpoint_ptr) { |
| *endpoint_ptr = endpoint; |
| } |
| if (bss_path_ptr) { |
| *bss_path_ptr = bss_path; |
| } |
| EXPECT_CALL(*service, NotifyCurrentEndpoint(EndpointMatch(endpoint))); |
| ReportCurrentBSSChanged(bss_path); |
| EXPECT_TRUE(GetPendingTimeout().IsCancelled()); |
| Mock::VerifyAndClearExpectations(service.get()); |
| |
| ReportStateChanged(WPASupplicant::kInterfaceStateAssociated); |
| EXPECT_FALSE(GetHandshakeTimeout().IsCancelled()); |
| |
| EXPECT_CALL(*service, ResetSuspectedCredentialFailures()); |
| ReportStateChanged(WPASupplicant::kInterfaceStateCompleted); |
| EXPECT_TRUE(GetHandshakeTimeout().IsCancelled()); |
| EXPECT_EQ(service->state(), Service::kStateConfiguring); |
| Mock::VerifyAndClearExpectations(service.get()); |
| |
| EXPECT_EQ(service, GetCurrentService()); |
| return service; |
| } |
| |
| void FireScanTimer() { wifi_->ScanTimerHandler(); } |
| void TriggerScan() { wifi_->Scan(nullptr, __func__, false); } |
| const WiFiServiceRefPtr& GetCurrentService() { |
| return wifi_->current_service_; |
| } |
| void SetCurrentService(const WiFiServiceRefPtr& service) { |
| wifi_->current_service_ = service; |
| } |
| const WiFi::EndpointMap& GetEndpointMap() { |
| return wifi_->endpoint_by_rpcid_; |
| } |
| const WiFiServiceRefPtr& GetPendingService() { |
| return wifi_->pending_service_; |
| } |
| const base::CancelableOnceClosure& GetPendingTimeout() { |
| return wifi_->pending_timeout_callback_; |
| } |
| const base::CancelableOnceClosure& GetHandshakeTimeout() { |
| return wifi_->handshake_timeout_callback_; |
| } |
| const base::CancelableOnceClosure& GetReconnectTimeoutCallback() { |
| return wifi_->reconnect_timeout_callback_; |
| } |
| const ServiceRefPtr& GetSelectedService() { |
| return wifi_->selected_service(); |
| } |
| const RpcIdentifier& GetSupplicantBSS() { return wifi_->supplicant_bss_; } |
| std::optional<net_base::MacAddress> GetPreSuspendBSSID() { |
| return wifi_->pre_suspend_bssid(); |
| } |
| void SetSupplicantBSS(const RpcIdentifier& bss) { |
| wifi_->supplicant_bss_ = bss; |
| } |
| base::TimeDelta GetReconnectTimeout() { return WiFi::kReconnectTimeout; } |
| const base::CancelableOnceClosure& GetScanTimer() { |
| return wifi_->scan_timer_callback_; |
| } |
| // note: the tests need the proxies referenced by WiFi (not the |
| // proxies instantiated by WiFiObjectTest), to ensure that WiFi |
| // sets up its proxies correctly. |
| MockSupplicantInterfaceProxy* GetSupplicantInterfaceProxyFromWiFi() { |
| return static_cast<MockSupplicantInterfaceProxy*>( |
| wifi_->supplicant_interface_proxy_.get()); |
| } |
| // This function returns the supplicant interface proxy whether |
| // or not we have passed the instantiated object to the WiFi instance |
| // from WiFiObjectTest, so tests don't need to worry about when they |
| // set expectations relative to StartWiFi(). |
| MockSupplicantInterfaceProxy* GetSupplicantInterfaceProxy() { |
| MockSupplicantInterfaceProxy* proxy = GetSupplicantInterfaceProxyFromWiFi(); |
| return proxy ? proxy : supplicant_interface_proxy_.get(); |
| } |
| MockSupplicantNetworkProxy* GetSupplicantNetworkProxy() { |
| return supplicant_network_proxy_.get(); |
| } |
| const std::string& GetSupplicantState() { return wifi_->supplicant_state_; } |
| IEEE_80211::WiFiReasonCode GetSupplicantDisconnectReason() { |
| return wifi_->supplicant_disconnect_reason_; |
| } |
| const WiFiPhy* GetWiFiPhy() { return wifi_->GetWiFiPhy(); } |
| |
| void SetWiFiPhy(const WiFiPhy* phy) { |
| ON_CALL(*wifi_provider(), GetPhyAtIndex(wifi_->phy_index_)) |
| .WillByDefault(Return(phy)); |
| } |
| |
| WiFiLinkStatistics::StationStats GetStationStats() { |
| return wifi_->station_stats_; |
| } |
| |
| void ClearCachedCredentials(const WiFiService* service) { |
| return wifi_->ClearCachedCredentials(service); |
| } |
| void NotifyEndpointChanged(const WiFiEndpointConstRefPtr& endpoint) { |
| wifi_->NotifyEndpointChanged(endpoint); |
| } |
| bool RemoveNetwork(const RpcIdentifier& network) { |
| return wifi_->RemoveNetwork(network); |
| } |
| KeyValueStore CreateBSSProperties(const std::string& ssid, |
| net_base::MacAddress bssid, |
| int16_t signal_strength, |
| uint16_t frequency, |
| const char* mode, |
| uint32_t age); |
| void RemoveBSS(const RpcIdentifier& bss_path); |
| void ReportBSS(const RpcIdentifier& bss_path, |
| const std::string& ssid, |
| net_base::MacAddress bssid, |
| int16_t signal_strength, |
| uint16_t frequency, |
| const char* mode, |
| uint32_t age); |
| void ReportBSSWithIEs(const RpcIdentifier& bss_path, |
| const std::string& ssid, |
| net_base::MacAddress bssid, |
| int16_t signal_strength, |
| uint16_t frequency, |
| const char* mode, |
| const std::vector<uint8_t>& ies); |
| void ReportGetDHCPLease() { wifi_->OnGetDHCPLease(wifi_->interface_index()); } |
| void ReportIPv4ConfiguredWithDHCPLease() { |
| wifi_->OnIPv4ConfiguredWithDHCPLease(wifi_->interface_index()); |
| } |
| void ReportIPv6ConfiguredWithSLAACAddress() { |
| wifi_->OnIPv6ConfiguredWithSLAACAddress(wifi_->interface_index()); |
| } |
| |
| // Calls the delayed version of the BSS methods. |
| void BSSAdded(const RpcIdentifier& bss_path, |
| const KeyValueStore& properties) { |
| wifi_->BSSAdded(bss_path, properties); |
| } |
| void BSSRemoved(const RpcIdentifier& bss_path) { |
| wifi_->BSSRemoved(bss_path); |
| } |
| |
| void ReportIPConfigFailure() { wifi_->OnIPConfigFailure(); } |
| void ReportConnected() { wifi_->OnConnected(); } |
| void ReportSelectedServiceChanged(const ServiceRefPtr& old_service) { |
| wifi_->OnSelectedServiceChanged(old_service); |
| } |
| void ReportLinkUp() { wifi_->LinkEvent(IFF_LOWER_UP, IFF_LOWER_UP); } |
| void ScanDone(const bool& success) { wifi_->ScanDone(success); } |
| void ReportScanFailed() { wifi_->ScanFailedTask(); } |
| void ReportScanDone() { wifi_->ScanDoneTask(); } |
| void ReportCurrentBSSChanged(const RpcIdentifier& new_bss) { |
| wifi_->CurrentBSSChanged(new_bss); |
| } |
| void ReportStateChanged(const std::string& new_state) { |
| EXPECT_CALL(wifi_provider_, WiFiDeviceStateChanged).Times(1); |
| wifi_->StateChanged(new_state); |
| } |
| void ReportDisconnectReasonChanged(int32_t reason) { |
| wifi_->DisconnectReasonChanged(reason); |
| } |
| void ReportCurrentAuthModeChanged(const std::string& auth_mode) { |
| wifi_->CurrentAuthModeChanged(auth_mode); |
| } |
| void ReportWiFiDebugScopeChanged(bool enabled) { |
| wifi_->OnWiFiDebugScopeChanged(enabled); |
| } |
| void RequestStationInfo(WiFiLinkStatistics::Trigger trigger) { |
| wifi_->RequestStationInfo(trigger); |
| } |
| void StopRequestingStationInfo() { wifi_->StopRequestingStationInfo(); } |
| void EmitStationInfoRequest(WiFiLinkStatistics::Trigger trigger) { |
| wifi_->EmitStationInfoRequestEvent(trigger); |
| } |
| void EmitStationInfoReceivedEvent( |
| const WiFiLinkStatistics::StationStats& stats) { |
| wifi_->EmitStationInfoReceivedEvent(stats); |
| } |
| void ReportReceivedRtnlLinkStatistics(const rtnl_link_stats64& stats) { |
| wifi_->OnReceivedRtnlLinkStatistics(stats); |
| } |
| KeyValueStore GetLinkStatistics() { |
| return wifi_->GetLinkStatistics(nullptr); |
| } |
| void SetPendingService(const WiFiServiceRefPtr& service) { |
| wifi_->SetPendingService(service); |
| } |
| void SetServiceNetworkRpcId(const WiFiServiceRefPtr& service, |
| const RpcIdentifier& rpcid) { |
| wifi_->rpcid_by_service_[service.get()] = rpcid; |
| } |
| bool RpcIdByServiceIsEmpty() { return wifi_->rpcid_by_service_.empty(); } |
| bool SetScanInterval(uint16_t interval_seconds, Error* error) { |
| return wifi_->SetScanInterval(interval_seconds, error); |
| } |
| uint16_t GetScanInterval() { return wifi_->GetScanInterval(nullptr); } |
| void StartWiFi(bool supplicant_present) { |
| EXPECT_CALL( |
| netlink_manager_, |
| SendOrPostMessage( |
| IsNl80211Command(kNl80211FamilyId, NL80211_CMD_GET_WIPHY), _)); |
| EXPECT_CALL( |
| netlink_manager_, |
| SendOrPostMessage( |
| IsNl80211Command(kNl80211FamilyId, NL80211_CMD_GET_STATION), _)) |
| .Times(AtLeast(0)); |
| |
| wifi_->supplicant_present_ = supplicant_present; |
| wifi_->SetEnabled(true); // Start(nullptr, ResultCallback()); |
| if (supplicant_present) |
| // Mimic the callback from |supplicant_process_proxy_|. |
| wifi_->OnSupplicantPresence(true); |
| } |
| void StartWiFi() { StartWiFi(true); } |
| void OnAfterResume() { |
| if (wifi_->enabled_) |
| EXPECT_CALL(*wake_on_wifi_, OnAfterResume()); |
| wifi_->OnAfterResume(); |
| } |
| void OnBeforeSuspend() { |
| wifi_->OnBeforeSuspend(base::BindOnce(&WiFiObjectTest::SuspendCallback, |
| base::Unretained(this))); |
| } |
| void OnDarkResume() { |
| wifi_->OnDarkResume(base::BindOnce(&WiFiObjectTest::SuspendCallback, |
| base::Unretained(this))); |
| } |
| void RemoveSupplicantNetworks() { wifi_->RemoveSupplicantNetworks(); } |
| void InitiateScan() { wifi_->InitiateScan(); } |
| void InitiateScanInDarkResume(const WiFi::FreqSet& freqs) { |
| wifi_->InitiateScanInDarkResume(freqs); |
| } |
| void TriggerPassiveScan(const WiFi::FreqSet& freqs) { |
| wifi_->TriggerPassiveScan(freqs); |
| } |
| void OnSupplicantAppear() { |
| wifi_->OnSupplicantPresence(true); |
| EXPECT_TRUE(wifi_->supplicant_present_); |
| } |
| void OnSupplicantVanish() { |
| wifi_->OnSupplicantPresence(false); |
| EXPECT_FALSE(wifi_->supplicant_present_); |
| } |
| void OnLinkMonitorFailure(net_base::IPFamily family) { |
| wifi_->OnLinkMonitorFailure(family); |
| } |
| bool GetSupplicantPresent() { return wifi_->supplicant_present_; } |
| bool GetIsRoamingInProgress() { return wifi_->is_roaming_in_progress_; } |
| void SetIsRoamingInProgress(bool is_roaming_in_progress) { |
| wifi_->is_roaming_in_progress_ = is_roaming_in_progress; |
| } |
| bool SetBgscanMethod(const std::string& method) { |
| Error error; |
| wifi_->mutable_store()->SetAnyProperty(kBgscanMethodProperty, |
| brillo::Any(method), &error); |
| return error.IsSuccess(); |
| } |
| |
| void AppendBgscan(WiFiService* service, KeyValueStore* service_params) { |
| wifi_->AppendBgscan(service, service_params); |
| } |
| |
| void ReportCertification(const KeyValueStore& properties) { |
| wifi_->CertificationTask(properties); |
| } |
| |
| void ReportEAPEvent(const std::string& status, const std::string& parameter) { |
| wifi_->EAPEventTask(status, parameter); |
| } |
| |
| void ReportPskMismatch() { wifi_->PskMismatchTask(); } |
| |
| void RestartFastScanAttempts() { wifi_->RestartFastScanAttempts(); } |
| |
| void SetFastScansRemaining(int num) { wifi_->fast_scans_remaining_ = num; } |
| |
| void StartReconnectTimer() { wifi_->StartReconnectTimer(); } |
| |
| void StopReconnectTimer() { wifi_->StopReconnectTimer(); } |
| |
| bool SuspectCredentials(const WiFiServiceRefPtr& service, |
| Service::ConnectFailure* failure) { |
| return wifi_->SuspectCredentials(service, failure); |
| } |
| |
| void OnNeighborReachabilityEvent(const net_base::IPAddress& ip_address, |
| patchpanel::Client::NeighborRole role, |
| patchpanel::Client::NeighborStatus status) { |
| wifi_->OnNeighborReachabilityEvent(wifi_->interface_index(), ip_address, |
| role, status); |
| } |
| |
| MOCK_METHOD(void, ReliableLinkCallback, ()); |
| |
| void SetReliableLinkCallback() { |
| wifi_->reliable_link_callback_.Reset(base::BindOnce( |
| &WiFiObjectTest::ReliableLinkCallback, base::Unretained(this))); |
| } |
| |
| bool ReliableLinkCallbackIsCancelled() { |
| return wifi_->reliable_link_callback_.IsCancelled(); |
| } |
| |
| bool SetBgscanShortInterval(const uint16_t& interval, Error* error) { |
| return wifi_->SetBgscanShortInterval(interval, error); |
| } |
| |
| bool SetBgscanSignalThreshold(const int32_t& threshold, Error* error) { |
| return wifi_->SetBgscanSignalThreshold(threshold, error); |
| } |
| |
| void TimeoutPendingConnection(MockWiFiServiceRefPtr service) { |
| auto& pending_timeout = GetPendingTimeout(); |
| |
| EXPECT_FALSE(pending_timeout.IsCancelled()); |
| EXPECT_EQ(service, GetPendingService()); |
| // The timeout handler is calling Disconnect() on service, which eventually |
| // leads to WiFi::DisconnectFrom() call - which should be tested as part of |
| // handling of the pending timeout. Instead of mocking this up let's invoke |
| // the actual code to make the call. |
| EXPECT_CALL(*service, Disconnect(_, HasSubstr("PendingTimeoutHandler"))) |
| .WillOnce(Invoke([service](auto err, auto reason) { |
| service->Service::Disconnect(err, reason); |
| })); |
| pending_timeout.callback().Run(); |
| } |
| |
| void OnNewWiphy(const Nl80211Message& new_wiphy_message) { |
| wifi_->OnNewWiphy(new_wiphy_message); |
| } |
| |
| bool IsConnectedToCurrentService() { |
| return wifi_->IsConnectedToCurrentService(); |
| } |
| |
| MockControl* control_interface() { return &control_interface_; } |
| |
| MockMetrics* metrics() { return &metrics_; } |
| |
| MockManager* manager() { return &manager_; } |
| |
| MockPowerManager* power_manager() { return power_manager_; } |
| |
| MockDeviceInfo* device_info() { return manager_.mock_device_info(); } |
| |
| MockNetwork* network() { return network_; } |
| |
| const WiFiConstRefPtr wifi() const { return wifi_; } |
| |
| MockWiFiProvider* wifi_provider() { return &wifi_provider_; } |
| |
| void ReportConnectedToServiceAfterWake() { |
| wifi_->ReportConnectedToServiceAfterWake(); |
| } |
| |
| void StartScanTimer() { wifi_->StartScanTimer(); } |
| |
| bool GetBroadcastProbeWasSkipped() { |
| return wifi_->broadcast_probe_was_skipped_; |
| } |
| |
| uint32_t GetPhyIndex() { return wifi_->phy_index_; } |
| |
| uint32_t SetPhyIndex(uint32_t phy_index) { |
| return wifi_->phy_index_ = phy_index; |
| } |
| |
| void ParseFeatureFlags(const Nl80211Message& nl80211_message) { |
| wifi_->ParseFeatureFlags(nl80211_message); |
| } |
| |
| void ParseCipherSuites(const Nl80211Message& nl80211_message) { |
| wifi_->ParseCipherSuites(nl80211_message); |
| } |
| |
| bool CipherSuiteSupported(uint32_t cipher_suite) { |
| return base::Contains(wifi_->supported_cipher_suites_, cipher_suite); |
| } |
| |
| bool GetRandomMacSupported() { return wifi_->random_mac_supported_; } |
| |
| void SetRandomMacSupported(bool supported) { |
| wifi_->random_mac_supported_ = supported; |
| } |
| |
| bool GetRandomMacEnabled() { return wifi_->random_mac_enabled_; } |
| |
| void SetRandomMacEnabled(bool enabled) { |
| Error error; |
| wifi_->SetRandomMacEnabled(enabled, &error); |
| } |
| |
| std::vector<unsigned char> GetRandomMacMask() { return WiFi::kRandomMacMask; } |
| |
| void HandleNetlinkBroadcast(const net_base::NetlinkMessage& netlink_message) { |
| wifi_->HandleNetlinkBroadcast(netlink_message); |
| } |
| |
| void RetrieveLinkStatistics(WiFiLinkStatistics::Trigger event) { |
| wifi_->RetrieveLinkStatistics(event); |
| } |
| |
| bool ScanFailedCallbackIsCancelled() { |
| return wifi_->scan_failed_callback_.IsCancelled(); |
| } |
| |
| void SetWiFiEnabled(bool enabled) { wifi_->enabled_ = enabled; } |
| |
| void OnRegChange(const Nl80211Message& msg) { |
| EXPECT_CALL(wifi_provider_, RegionChanged(_)).Times(AtLeast(0)); |
| wifi_->OnRegChange(msg); |
| } |
| |
| void OnGetReg(const Nl80211Message& msg) { wifi_->OnGetReg(msg); } |
| |
| void EnsureScanAndConnectToBestService() { |
| wifi_->EnsureScanAndConnectToBestService(nullptr); |
| } |
| |
| void SetEnsuredScanState(WiFiState::EnsuredScanState ensured_scan_state) { |
| wifi_->wifi_state_->SetEnsuredScanState(ensured_scan_state); |
| } |
| |
| void HandleEnsuredScan( |
| WiFiState::EnsuredScanState ensured_scan_state, |
| WiFiState::EnsuredScanState expected_ensured_scan_state) { |
| wifi_->wifi_state_->SetEnsuredScanState(ensured_scan_state); |
| wifi_->HandleEnsuredScan(); |
| EXPECT_EQ(expected_ensured_scan_state, |
| wifi_->wifi_state_->GetEnsuredScanState()); |
| } |
| |
| MOCK_METHOD(void, SuspendCallback, (const Error&)); |
| |
| // Reporting of MaxScanSSID capability can (in theory) behave in three ways: |
| // - failing D-Bus communication (provide optional arg with 'false') |
| // - having capabilities w/o MaxScanSSID (provide limit < 0) |
| // - having capabilities w/ MaxScanSSID (provide limit >= 0) |
| void SetInterfaceScanLimit(int limit, bool success = true) { |
| brillo::VariantDictionary caps{}; |
| |
| if (!success) { |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), GetCapabilities(_)) |
| .WillOnce(Return(false)); |
| } else { |
| if (limit >= 0) |
| caps[WPASupplicant::kInterfaceCapabilityMaxScanSSID] = limit; |
| |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), GetCapabilities(_)) |
| .WillOnce( |
| DoAll(SetArgPointee<0>( |
| KeyValueStore::ConvertFromVariantDictionary(caps)), |
| Return(true))); |
| } |
| } |
| |
| bool AddCred(const PasspointCredentialsRefPtr& credentials) { |
| return wifi_->AddCred(credentials); |
| } |
| |
| bool RemoveCred(const PasspointCredentialsRefPtr& credentials) { |
| return wifi_->RemoveCred(credentials); |
| } |
| |
| void ReportInterworkingAPAdded(const RpcIdentifier& BSS, |
| const RpcIdentifier& cred, |
| const KeyValueStore& properties) { |
| wifi_->InterworkingAPAdded(BSS, cred, properties); |
| } |
| |
| void ReportInterworkingSelectDone() { wifi_->InterworkingSelectDone(); } |
| |
| bool NeedInterworkingSelect() { return wifi_->need_interworking_select_; } |
| |
| void TriggerNetworkStart() { |
| // Reset the state and set to completed again to trigger Network start. |
| wifi_->supplicant_state_ = WPASupplicant::kInterfaceStateDisconnected; |
| wifi_->StateChanged(WPASupplicant::kInterfaceStateCompleted); |
| } |
| |
| bool GetWEPSupport() { return wifi_->SupportsWEP(); } |
| |
| void SetWEPSupport(bool supported) { |
| if (supported) { |
| wifi_->supported_cipher_suites_.insert(WiFi::kWEP40CipherCode); |
| wifi_->supported_cipher_suites_.insert(WiFi::kWEP104CipherCode); |
| return; |
| } |
| wifi_->supported_cipher_suites_.erase(WiFi::kWEP40CipherCode); |
| wifi_->supported_cipher_suites_.erase(WiFi::kWEP104CipherCode); |
| } |
| |
| std::optional<net_base::MacAddress> perm_address() const { |
| return wifi_->perm_address_; |
| } |
| void SetMacAddress(net_base::MacAddress addr) { |
| wifi_->set_mac_address(addr); |
| } |
| std::string GetStorageIdentifier() const { |
| return wifi_->GetStorageIdentifier(); |
| } |
| |
| std::unique_ptr<EventDispatcher> event_dispatcher_; |
| MockWakeOnWiFi* wake_on_wifi_; // Owned by |wifi_|. |
| NiceMock<net_base::MockRTNLHandler> rtnl_handler_; |
| MockTime time_; |
| net_base::MockNetlinkManager netlink_manager_; |
| |
| private: |
| MockControl control_interface_; |
| MockMetrics metrics_; |
| MockManager manager_; |
| MockPowerManager* power_manager_; // Owned by |manager_|. |
| WiFiRefPtr wifi_; |
| NiceMock<MockWiFiProvider> wifi_provider_; |
| int bss_counter_ = 0; |
| MockNetwork* network_; // Owned by |wifi_| |
| |
| // protected fields interspersed between private fields, due to |
| // initialization order |
| protected: |
| static const char kDeviceName[]; |
| static const net_base::MacAddress kDeviceAddress; |
| static const char kNetworkModeAdHoc[]; |
| static const char kNetworkModeInfrastructure[]; |
| static const RpcIdentifier kBSSName; |
| static const char kSSIDName[]; |
| |
| MockSupplicantProcessProxy* supplicant_process_proxy_; |
| std::unique_ptr<MockSupplicantBSSProxy> supplicant_bss_proxy_; |
| std::string dhcp_hostname_; |
| |
| // These pointers track mock objects owned by the WiFi device instance |
| // and manager so we can perform expectations against them. |
| DeviceMockAdaptor* adaptor_; |
| MockSupplicantEAPStateHandler* eap_state_handler_; |
| MockWiFiLinkStatistics* wifi_link_statistics_; |
| |
| private: |
| std::unique_ptr<SupplicantInterfaceProxyInterface> |
| CreateSupplicantInterfaceProxy(SupplicantEventDelegateInterface* delegate, |
| const RpcIdentifier& object_path) { |
| CHECK(supplicant_interface_proxy_); |
| return std::move(supplicant_interface_proxy_); |
| } |
| |
| std::unique_ptr<SupplicantNetworkProxyInterface> CreateSupplicantNetworkProxy( |
| const RpcIdentifier& object_path) { |
| return std::move(supplicant_network_proxy_); |
| } |
| |
| std::unique_ptr<SupplicantBSSProxyInterface> CreateSupplicantBSSProxy( |
| WiFiEndpoint* wifi_endpoint, const RpcIdentifier& object_path) { |
| return std::move(supplicant_bss_proxy_); |
| } |
| |
| std::unique_ptr<MockSupplicantInterfaceProxy> supplicant_interface_proxy_; |
| std::unique_ptr<MockSupplicantNetworkProxy> supplicant_network_proxy_; |
| }; |
| |
| const char WiFiObjectTest::kDeviceName[] = "wlan0"; |
| const net_base::MacAddress WiFiObjectTest::kDeviceAddress( |
| 0x00, 0x01, 0x02, 0x03, 0x04, 0x05); |
| const char WiFiObjectTest::kNetworkModeAdHoc[] = "ad-hoc"; |
| const char WiFiObjectTest::kNetworkModeInfrastructure[] = "infrastructure"; |
| const RpcIdentifier WiFiObjectTest::kBSSName("bss0"); |
| const char WiFiObjectTest::kSSIDName[] = "ssid0"; |
| |
| void WiFiObjectTest::RemoveBSS(const RpcIdentifier& bss_path) { |
| wifi_->BSSRemovedTask(bss_path); |
| } |
| |
| KeyValueStore WiFiObjectTest::CreateBSSProperties(const std::string& ssid, |
| net_base::MacAddress bssid, |
| int16_t signal_strength, |
| uint16_t frequency, |
| const char* mode, |
| uint32_t age) { |
| KeyValueStore bss_properties; |
| bss_properties.Set<std::vector<uint8_t>>( |
| "SSID", std::vector<uint8_t>(ssid.begin(), ssid.end())); |
| bss_properties.Set<std::vector<uint8_t>>("BSSID", bssid.ToBytes()); |
| bss_properties.Set<int16_t>(WPASupplicant::kBSSPropertySignal, |
| signal_strength); |
| bss_properties.Set<uint16_t>(WPASupplicant::kBSSPropertyFrequency, frequency); |
| bss_properties.Set<std::string>(WPASupplicant::kBSSPropertyMode, mode); |
| bss_properties.Set<uint32_t>(WPASupplicant::kBSSPropertyAge, age); |
| |
| return bss_properties; |
| } |
| |
| void WiFiObjectTest::ReportBSS(const RpcIdentifier& bss_path, |
| const std::string& ssid, |
| net_base::MacAddress bssid, |
| int16_t signal_strength, |
| uint16_t frequency, |
| const char* mode, |
| uint32_t age) { |
| wifi_->BSSAddedTask( |
| bss_path, |
| CreateBSSProperties(ssid, bssid, signal_strength, frequency, mode, age)); |
| } |
| |
| void WiFiObjectTest::ReportBSSWithIEs(const RpcIdentifier& bss_path, |
| const std::string& ssid, |
| net_base::MacAddress bssid, |
| int16_t signal_strength, |
| uint16_t frequency, |
| const char* mode, |
| const std::vector<uint8_t>& ies) { |
| KeyValueStore properties = |
| CreateBSSProperties(ssid, bssid, signal_strength, frequency, mode, 0); |
| properties.Set<std::vector<uint8_t>>(WPASupplicant::kBSSPropertyIEs, ies); |
| wifi_->BSSAddedTask(bss_path, properties); |
| } |
| |
| // Most of our tests involve using a real EventDispatcher object. |
| class WiFiMainTest : public WiFiObjectTest { |
| public: |
| WiFiMainTest() |
| : WiFiObjectTest(std::make_unique<EventDispatcherForTest>()), |
| test_event_dispatcher_( |
| static_cast<EventDispatcherForTest*>(event_dispatcher_.get())) {} |
| |
| protected: |
| void StartScan(WiFiState::ScanMethod method) { |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| EXPECT_CALL(*adaptor_, EmitBoolChanged(kPoweredProperty, _)) |
| .Times(AnyNumber()); |
| |
| ExpectScanStart(method, false); |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| VerifyScanState(WiFiState::PhyState::kScanning, method); |
| } |
| |
| MockWiFiServiceRefPtr AttemptConnection(WiFiState::ScanMethod method, |
| WiFiEndpointRefPtr* endpoint, |
| RpcIdentifier* bss_path) { |
| WiFiEndpointRefPtr fake_endpoint; |
| if (!endpoint) { |
| endpoint = &fake_endpoint; // If caller doesn't care about endpoint. |
| } |
| |
| RpcIdentifier fake_bss_path; |
| if (!bss_path) { |
| bss_path = &fake_bss_path; // If caller doesn't care about bss_path. |
| } |
| |
| ExpectScanStop(); |
| ExpectConnecting(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectingService(RpcIdentifier(""), endpoint, bss_path); |
| ReportScanDone(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| VerifyScanState(WiFiState::PhyState::kConnecting, method); |
| |
| return service; |
| } |
| |
| void ExpectScanStart(WiFiState::ScanMethod method, bool is_continued) { |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)); |
| if (!is_continued) { |
| EXPECT_CALL(*adaptor_, EmitBoolChanged(kScanningProperty, true)); |
| EXPECT_CALL(*metrics(), NotifyDeviceScanStarted(_)); |
| } |
| } |
| |
| // Scanning can stop for any reason (including transitioning to connecting). |
| void ExpectScanStop() { |
| EXPECT_CALL(*adaptor_, EmitBoolChanged(kScanningProperty, false)); |
| } |
| |
| void ExpectConnecting() { |
| EXPECT_CALL(*metrics(), NotifyDeviceScanFinished(_)); |
| EXPECT_CALL(*metrics(), NotifyDeviceConnectStarted(_)); |
| } |
| |
| void ExpectNotConnecting() { |
| EXPECT_CALL(*metrics(), NotifyDeviceScanFinished(_)).Times(0); |
| EXPECT_CALL(*metrics(), NotifyDeviceConnectStarted(_)).Times(0); |
| } |
| |
| void ExpectConnected() { |
| EXPECT_CALL(*metrics(), NotifyDeviceConnectFinished(_)); |
| ExpectScanIdle(); |
| } |
| |
| void ExpectFoundNothing() { |
| EXPECT_CALL(*metrics(), NotifyDeviceScanFinished(_)); |
| EXPECT_CALL(*metrics(), ResetConnectTimer(_)); |
| ExpectScanIdle(); |
| } |
| |
| void ExpectScanIdle() { |
| EXPECT_CALL(*metrics(), ResetScanTimer(_)); |
| EXPECT_CALL(*metrics(), ResetConnectTimer(_)).RetiresOnSaturation(); |
| } |
| |
| EventDispatcherForTest* test_event_dispatcher_; |
| }; |
| |
| TEST_F(WiFiMainTest, GetStorageIdentifier) { |
| // First test the base line - that the stored hardware MAC is what we expect. |
| EXPECT_EQ(perm_address(), kPermDeviceAddress); |
| auto storage_id = GetStorageIdentifier(); |
| // Now check the expected storage ID and that it does no change when MAC |
| // address changes. |
| EXPECT_EQ(storage_id, std::string("device_") + perm_address()->ToHexString()); |
| net_base::MacAddress::DataType bytes; |
| base::RandBytes(bytes); |
| SetMacAddress(net_base::MacAddress(bytes)); |
| EXPECT_EQ(storage_id, GetStorageIdentifier()); |
| } |
| |
| TEST_F(WiFiMainTest, ProxiesSetUpDuringStart) { |
| EXPECT_EQ(nullptr, GetSupplicantInterfaceProxyFromWiFi()); |
| |
| StartWiFi(); |
| EXPECT_NE(nullptr, GetSupplicantInterfaceProxyFromWiFi()); |
| } |
| |
| TEST_F(WiFiMainTest, SupplicantPresent) { |
| EXPECT_FALSE(GetSupplicantPresent()); |
| } |
| |
| TEST_F(WiFiMainTest, OnSupplicantAppearStarted) { |
| EXPECT_EQ(nullptr, GetSupplicantInterfaceProxyFromWiFi()); |
| |
| StartWiFi(false); // No supplicant present. |
| EXPECT_EQ(nullptr, GetSupplicantInterfaceProxyFromWiFi()); |
| |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveAllNetworks()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), FlushBSS(0)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), SetFastReauth(false)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), SetScanInterval(_)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveAllCreds()); |
| |
| OnSupplicantAppear(); |
| EXPECT_NE(nullptr, GetSupplicantInterfaceProxyFromWiFi()); |
| |
| // If supplicant reappears while the device is started, the device should be |
| // restarted. |
| EXPECT_CALL(*manager(), DeregisterDevice(_)); |
| EXPECT_CALL(*manager(), RegisterDevice(_)); |
| OnSupplicantAppear(); |
| } |
| |
| TEST_F(WiFiMainTest, OnSupplicantAppearStopped) { |
| EXPECT_EQ(nullptr, GetSupplicantInterfaceProxyFromWiFi()); |
| |
| OnSupplicantAppear(); |
| EXPECT_EQ(nullptr, GetSupplicantInterfaceProxyFromWiFi()); |
| |
| // If supplicant reappears while the device is stopped, the device should not |
| // be restarted. |
| EXPECT_CALL(*manager(), DeregisterDevice(_)).Times(0); |
| OnSupplicantAppear(); |
| } |
| |
| TEST_F(WiFiMainTest, OnSupplicantVanishStarted) { |
| EXPECT_EQ(nullptr, GetSupplicantInterfaceProxyFromWiFi()); |
| |
| StartWiFi(); |
| EXPECT_NE(nullptr, GetSupplicantInterfaceProxyFromWiFi()); |
| EXPECT_TRUE(GetSupplicantPresent()); |
| |
| EXPECT_CALL(*manager(), DeregisterDevice(_)); |
| EXPECT_CALL(*manager(), RegisterDevice(_)); |
| OnSupplicantVanish(); |
| } |
| |
| TEST_F(WiFiMainTest, OnSupplicantVanishStopped) { |
| OnSupplicantAppear(); |
| EXPECT_TRUE(GetSupplicantPresent()); |
| EXPECT_CALL(*manager(), DeregisterDevice(_)).Times(0); |
| OnSupplicantVanish(); |
| } |
| |
| TEST_F(WiFiMainTest, OnSupplicantVanishedWhileConnected) { |
| StartWiFi(); |
| WiFiEndpointRefPtr endpoint; |
| WiFiServiceRefPtr service( |
| SetupConnectedService(RpcIdentifier(""), &endpoint, nullptr)); |
| ScopedMockLog log; |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| EXPECT_CALL(log, Log(logging::LOGGING_ERROR, _, |
| EndsWith("silently resetting current_service_."))); |
| EXPECT_CALL(*manager(), DeregisterDevice(_)) |
| .WillOnce(InvokeWithoutArgs(this, &WiFiObjectTest::StopWiFi)); |
| std::unique_ptr<EndpointRemovalHandler> handler = |
| MakeEndpointRemovalHandler(service); |
| EXPECT_CALL(*wifi_provider(), OnEndpointRemoved(EndpointMatch(endpoint))) |
| .WillOnce( |
| Invoke(handler.get(), &EndpointRemovalHandler::OnEndpointRemoved)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()).Times(0); |
| EXPECT_CALL(*manager(), RegisterDevice(_)); |
| OnSupplicantVanish(); |
| EXPECT_EQ(nullptr, GetCurrentService()); |
| } |
| |
| TEST_F(WiFiMainTest, CleanStart) { |
| EXPECT_CALL(*supplicant_process_proxy_, CreateInterface(_, _)); |
| EXPECT_CALL(*supplicant_process_proxy_, GetInterface(_, _)) |
| .Times(AnyNumber()) |
| .WillRepeatedly(Return(false)); |
| EXPECT_TRUE(GetScanTimer().IsCancelled()); |
| StartWiFi(); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| EXPECT_FALSE(GetScanTimer().IsCancelled()); |
| } |
| |
| TEST_F(WiFiMainTest, ClearCachedCredentials) { |
| StartWiFi(); |
| RpcIdentifier network("/test/path"); |
| WiFiServiceRefPtr service(SetupConnectedService(network, nullptr, nullptr)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveNetwork(network)); |
| ClearCachedCredentials(service.get()); |
| } |
| |
| TEST_F(WiFiMainTest, NotifyEndpointChanged) { |
| WiFiEndpointRefPtr endpoint = MakeEndpoint( |
| "ssid", net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); |
| EXPECT_CALL(*wifi_provider(), OnEndpointUpdated(EndpointMatch(endpoint))); |
| NotifyEndpointChanged(endpoint); |
| } |
| |
| TEST_F(WiFiMainTest, RemoveNetwork) { |
| RpcIdentifier network("/test/path"); |
| StartWiFi(); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveNetwork(network)) |
| .WillOnce(Return(true)); |
| EXPECT_TRUE(RemoveNetwork(network)); |
| } |
| |
| TEST_F(WiFiMainTest, StartNetworkUseArpGateway) { |
| StartWiFi(); |
| |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| RpcIdentifier bss_path = MakeNewEndpointAndService(-90, 0, nullptr, &service); |
| InitiateConnect(service); |
| ReportCurrentBSSChanged(bss_path); |
| |
| const auto dhcp_matcher = |
| Optional(AllOf(Field(&DHCPProvider::Options::use_arp_gateway, true), |
| Field(&DHCPProvider::Options::hostname, dhcp_hostname_))); |
| EXPECT_CALL(*network(), |
| Start(AllOf(Field(&Network::StartOptions::dhcp, dhcp_matcher), |
| Field(&Network::StartOptions::accept_ra, true)))); |
| TriggerNetworkStart(); |
| Mock::VerifyAndClearExpectations(service.get()); |
| } |
| |
| TEST_F(WiFiMainTest, RemoveNetworkFailed) { |
| RpcIdentifier network("/test/path"); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveNetwork(network)) |
| .WillRepeatedly(Return(false)); |
| StartWiFi(); |
| EXPECT_FALSE(RemoveNetwork(network)); |
| } |
| |
| TEST_F(WiFiMainTest, Restart) { |
| EXPECT_CALL(*supplicant_process_proxy_, CreateInterface(_, _)) |
| .Times(AnyNumber()) |
| .WillRepeatedly(Return(false)); |
| EXPECT_CALL(*supplicant_process_proxy_, GetInterface(_, _)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)); |
| EXPECT_CALL(*metrics(), SendToUMA(Metrics::kMetricWifiSupplicantAttempts, 1)); |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| TEST_F(WiFiMainTest, StartClearsState) { |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveAllNetworks()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), FlushBSS(_)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveAllCreds()); |
| StartWiFi(); |
| } |
| |
| TEST_F(WiFiMainTest, NoScansWhileConnecting) { |
| // Setup 'connecting' state. |
| StartScan(WiFiState::ScanMethod::kFull); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| |
| ExpectScanStop(); |
| ExpectConnecting(); |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| InitiateConnect(service); |
| VerifyScanState(WiFiState::PhyState::kConnecting, |
| WiFiState::ScanMethod::kFull); |
| |
| // If we're connecting, we ignore scan requests and stay on channel. |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)).Times(0); |
| TriggerScan(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| Mock::VerifyAndClearExpectations(service.get()); |
| |
| // Terminate the scan. |
| ExpectFoundNothing(); |
| TimeoutPendingConnection(service); |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| |
| // Start a fresh scan. |
| ExpectScanStart(WiFiState::ScanMethod::kFull, false); |
| TriggerScan(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| Mock::VerifyAndClearExpectations(service.get()); |
| |
| // Similarly, ignore scans when our connected service is reconnecting. |
| ExpectScanStop(); |
| ExpectScanIdle(); |
| SetPendingService(nullptr); |
| SetCurrentService(service); |
| EXPECT_CALL(*service, IsConnecting()).WillOnce(Return(true)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)).Times(0); |
| TriggerScan(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| Mock::VerifyAndClearExpectations(service.get()); |
| |
| // But otherwise we'll honor the request. |
| EXPECT_CALL(*service, IsConnecting()) |
| .Times(AtLeast(2)) |
| .WillRepeatedly(Return(false)); |
| ExpectScanStart(WiFiState::ScanMethod::kFull, false); |
| TriggerScan(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| Mock::VerifyAndClearExpectations(service.get()); |
| |
| // Silence messages from the destructor. |
| ExpectScanStop(); |
| ExpectScanIdle(); |
| } |
| |
| TEST_F(WiFiMainTest, ResetScanStateWhenScanFailed) { |
| StartScan(WiFiState::ScanMethod::kFull); |
| ExpectScanStop(); |
| VerifyScanState(WiFiState::PhyState::kScanning, WiFiState::ScanMethod::kFull); |
| ReportScanFailed(); |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| } |
| |
| TEST_F(WiFiMainTest, ResumeStartsScanWhenIdle) { |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)); |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| ReportScanDone(); |
| ASSERT_TRUE(wifi()->IsIdle()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)); |
| OnAfterResume(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| TEST_F(WiFiMainTest, ResumeDoesNotScanIfConnected) { |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| ReportScanDone(); |
| CancelScanTimer(); |
| EXPECT_TRUE(GetScanTimer().IsCancelled()); |
| ASSERT_TRUE(wifi()->IsIdle()); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| OnAfterResume(); |
| EXPECT_FALSE(GetScanTimer().IsCancelled()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)).Times(0); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| TEST_F(WiFiMainTest, SuspendDoesNotStartScan) { |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)); |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| ASSERT_TRUE(wifi()->IsIdle()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)).Times(0); |
| OnBeforeSuspend(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| TEST_F(WiFiMainTest, ResumeDoesNotStartScanWhenNotIdle) { |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)); |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| WiFiServiceRefPtr service( |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr)); |
| EXPECT_FALSE(wifi()->IsIdle()); |
| ScopedMockLog log; |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| EXPECT_CALL(log, Log(_, _, EndsWith("already connecting or connected."))); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)).Times(0); |
| OnAfterResume(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| TEST_F(WiFiMainTest, ResumeDoesNotStartScanWhenDisabled) { |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)); |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)).Times(0); |
| SetWiFiEnabled(false); |
| OnBeforeSuspend(); |
| OnAfterResume(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| TEST_F(WiFiMainTest, PreSuspendBSSIDSet) { |
| StartWiFi(); |
| WiFiEndpointRefPtr endpoint; |
| SetupConnectedService(RpcIdentifier(""), &endpoint, nullptr); |
| const std::optional<net_base::MacAddress> bssid = |
| GetCurrentService()->bssid(); |
| OnBeforeSuspend(); |
| EXPECT_EQ(GetPreSuspendBSSID(), bssid); |
| } |
| |
| TEST_F(WiFiMainTest, ResumeWithCurrentService) { |
| StartWiFi(); |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| |
| OnAfterResume(); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| } |
| |
| TEST_F(WiFiMainTest, ScanResults) { |
| EXPECT_CALL(*wifi_provider(), OnEndpointAdded(_)).Times(3); |
| StartWiFi(); |
| // Ad-hoc networks will be dropped. |
| ReportBSS(RpcIdentifier("bss0"), "ssid0", |
| net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 0, 0, |
| kNetworkModeAdHoc, 0); |
| ReportBSS(RpcIdentifier("bss1"), "ssid1", |
| net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x01), 1, 0, |
| kNetworkModeInfrastructure, 0); |
| ReportBSS(RpcIdentifier("bss2"), "ssid2", |
| net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x02), 2, 0, |
| kNetworkModeInfrastructure, 0); |
| ReportBSS(RpcIdentifier("bss3"), "ssid3", |
| net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x03), 3, 0, |
| kNetworkModeInfrastructure, 0); |
| const uint16_t frequency = 2412; |
| ReportBSS(RpcIdentifier("bss4"), "ssid4", |
| net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x04), 4, |
| frequency, kNetworkModeAdHoc, 0); |
| |
| const WiFi::EndpointMap& endpoints_by_rpcid = GetEndpointMap(); |
| EXPECT_EQ(3, endpoints_by_rpcid.size()); |
| |
| for (const auto& endpoint : endpoints_by_rpcid) { |
| EXPECT_NE(kNetworkModeAdHoc, endpoint.second->network_mode()); |
| EXPECT_NE(endpoint.second->bssid(), |
| net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); |
| EXPECT_NE(endpoint.second->bssid(), |
| net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x04)); |
| } |
| } |
| |
| TEST_F(WiFiMainTest, ScanCompleted) { |
| StartWiFi(); |
| WiFiEndpointRefPtr ap0 = MakeEndpoint( |
| "ssid0", net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); |
| WiFiEndpointRefPtr ap1 = MakeEndpoint( |
| "ssid1", net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x01)); |
| EXPECT_CALL(*wifi_provider(), OnEndpointAdded(EndpointMatch(ap0))).Times(1); |
| EXPECT_CALL(*wifi_provider(), OnEndpointAdded(EndpointMatch(ap1))).Times(1); |
| ReportBSS(RpcIdentifier("bss0"), ap0->ssid_string(), ap0->bssid(), 0, 0, |
| kNetworkModeInfrastructure, 0); |
| ReportBSS(RpcIdentifier("bss1"), ap1->ssid_string(), ap1->bssid(), 0, 0, |
| kNetworkModeInfrastructure, 0); |
| manager()->set_suppress_autoconnect(true); |
| ReportScanDone(); |
| EXPECT_FALSE(manager()->suppress_autoconnect()); |
| Mock::VerifyAndClearExpectations(wifi_provider()); |
| |
| EXPECT_CALL(*wifi_provider(), OnEndpointAdded(_)).Times(0); |
| |
| // BSSes with SSIDs that start with nullptr should be filtered. |
| ReportBSS(RpcIdentifier("bss2"), std::string(1, 0), |
| net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x02), 3, 0, |
| kNetworkModeInfrastructure, 0); |
| |
| // BSSes with empty SSIDs should be filtered. |
| ReportBSS(RpcIdentifier("bss2"), std::string(), |
| net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x02), 3, 0, |
| kNetworkModeInfrastructure, 0); |
| } |
| |
| TEST_F(WiFiMainTest, EnsuredScan) { |
| // Setup |
| EXPECT_CALL(*adaptor_, EmitBoolChanged(kPoweredProperty, _)) |
| .Times(AnyNumber()); |
| ExpectScanStart(WiFiState::ScanMethod::kFull, false); |
| StartWiFi(); |
| VerifyEnsuredScanState(WiFiState::EnsuredScanState::kIdle); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| // Handle the initial scan from setup |
| ExpectScanStop(); |
| ReportScanDone(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| VerifyEnsuredScanState(WiFiState::EnsuredScanState::kIdle); |
| |
| // Ensure the Scan |
| ExpectScanStart(WiFiState::ScanMethod::kFull, false); |
| EnsureScanAndConnectToBestService(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| // Verify the ensured scan |
| VerifyScanState(WiFiState::PhyState::kScanning, WiFiState::ScanMethod::kFull); |
| VerifyEnsuredScanState(WiFiState::EnsuredScanState::kScanning); |
| ExpectScanStop(); |
| ReportScanDone(); |
| |
| // Verify that ConnectToBestServices is called |
| EXPECT_CALL(*manager(), ConnectToBestWiFiService()); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| VerifyEnsuredScanState(WiFiState::EnsuredScanState::kIdle); |
| } |
| |
| TEST_F(WiFiMainTest, ConnectToBestWiFiServiceDeviceDisabled) { |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| EnsureScanAndConnectToBestService(); |
| |
| // Verify that ConnectToBestWiFiService is not called |
| EXPECT_CALL(*manager(), ConnectToBestWiFiService()).Times(0); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| VerifyEnsuredScanState(WiFiState::EnsuredScanState::kIdle); |
| } |
| |
| TEST_F(WiFiMainTest, ConnectToBestWiFiServiceNoSupplicant) { |
| // Setup Start without SupplicantProxy to ensure idle state. |
| StartWiFi(false); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| // Handle the initial scan from setup |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| VerifyEnsuredScanState(WiFiState::EnsuredScanState::kIdle); |
| EnsureScanAndConnectToBestService(); |
| VerifyEnsuredScanState(WiFiState::EnsuredScanState::kScanning); |
| // Verify that ConnectToBestWiFiService is not called |
| EXPECT_CALL(*manager(), ConnectToBestWiFiService()).Times(0); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| VerifyEnsuredScanState(WiFiState::EnsuredScanState::kIdle); |
| } |
| |
| TEST_F(WiFiMainTest, QueueEnsuredScan) { |
| // Setup |
| EXPECT_CALL(*adaptor_, EmitBoolChanged(kPoweredProperty, _)) |
| .Times(AnyNumber()); |
| ExpectScanStart(WiFiState::ScanMethod::kFull, false); |
| StartWiFi(); |
| VerifyEnsuredScanState(WiFiState::EnsuredScanState::kIdle); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| // Queue the ensured scan |
| EnsureScanAndConnectToBestService(); |
| ExpectScanStart(WiFiState::ScanMethod::kFull, false); |
| VerifyScanState(WiFiState::PhyState::kScanning, WiFiState::ScanMethod::kFull); |
| VerifyEnsuredScanState(WiFiState::EnsuredScanState::kWaiting); |
| // Handle the initial scan from setup |
| ExpectScanStop(); |
| ReportScanDone(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| // Verify the ensured scan |
| VerifyScanState(WiFiState::PhyState::kScanning, WiFiState::ScanMethod::kFull); |
| VerifyEnsuredScanState(WiFiState::EnsuredScanState::kScanning); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| // Handle the ensured scan |
| ExpectScanStop(); |
| ReportScanDone(); |
| |
| // Verify that ConnectToBestWiFiService is called |
| EXPECT_CALL(*manager(), ConnectToBestWiFiService()); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| VerifyEnsuredScanState(WiFiState::EnsuredScanState::kIdle); |
| } |
| |
| TEST_F(WiFiMainTest, QueuedEnsuredScan) { |
| // Setup |
| EXPECT_CALL(*adaptor_, EmitBoolChanged(kPoweredProperty, _)) |
| .Times(AnyNumber()); |
| ExpectScanStart(WiFiState::ScanMethod::kFull, false); |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| // Handle the initial scan from setup |
| ExpectScanStop(); |
| ReportScanDone(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| |
| // Queue the ensured scan |
| SetEnsuredScanState(WiFiState::EnsuredScanState::kWaiting); |
| VerifyEnsuredScanState(WiFiState::EnsuredScanState::kWaiting); |
| |
| // Ensure that an idle -> idle transition triggers a scan. |
| SetScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone, ""); |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| ExpectScanStart(WiFiState::ScanMethod::kFull, false); |
| |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| // Verify the ensured scan |
| VerifyScanState(WiFiState::PhyState::kScanning, WiFiState::ScanMethod::kFull); |
| VerifyEnsuredScanState(WiFiState::EnsuredScanState::kScanning); |
| ExpectScanStop(); |
| ReportScanDone(); |
| |
| // Verify that ConnectToBestWiFiService is called |
| EXPECT_CALL(*manager(), ConnectToBestWiFiService()); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| TEST_F(WiFiMainTest, QueuedEnsuredScanFinished) { |
| // Setup |
| EXPECT_CALL(*adaptor_, EmitBoolChanged(kPoweredProperty, _)) |
| .Times(AnyNumber()); |
| ExpectScanStart(WiFiState::ScanMethod::kFull, false); |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| // Handle the initial scan from setup |
| ExpectScanStop(); |
| ReportScanDone(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| // Verify that ConnectToBestWiFiService is called |
| EXPECT_CALL(*manager(), ConnectToBestWiFiService()); |
| // Simulate an idle radio when a scan had been queued |
| HandleEnsuredScan(WiFiState::EnsuredScanState::kScanning, |
| WiFiState::EnsuredScanState::kIdle); |
| // Verify that there wasn't an extra scan |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| } |
| |
| TEST_F(WiFiMainTest, LoneBSSRemovedWhileConnected) { |
| StartWiFi(); |
| WiFiEndpointRefPtr endpoint; |
| RpcIdentifier bss_path; |
| WiFiServiceRefPtr service( |
| SetupConnectedService(RpcIdentifier(""), &endpoint, &bss_path)); |
| std::unique_ptr<EndpointRemovalHandler> handler = |
| MakeEndpointRemovalHandler(service); |
| EXPECT_CALL(*wifi_provider(), OnEndpointRemoved(EndpointMatch(endpoint))) |
| .WillOnce( |
| Invoke(handler.get(), &EndpointRemovalHandler::OnEndpointRemoved)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()); |
| RemoveBSS(bss_path); |
| } |
| |
| TEST_F(WiFiMainTest, GetCurrentEndpoint) { |
| StartWiFi(); |
| WiFiEndpointRefPtr endpoint; |
| RpcIdentifier bss_path; |
| MockWiFiServiceRefPtr service( |
| SetupConnectedService(RpcIdentifier(""), &endpoint, &bss_path)); |
| const WiFiEndpointConstRefPtr current_endpoint = wifi()->GetCurrentEndpoint(); |
| EXPECT_NE(nullptr, current_endpoint); |
| EXPECT_EQ(current_endpoint->bssid(), endpoint->bssid()); |
| } |
| |
| TEST_F(WiFiMainTest, NonSolitaryBSSRemoved) { |
| StartWiFi(); |
| WiFiEndpointRefPtr endpoint; |
| RpcIdentifier bss_path; |
| WiFiServiceRefPtr service( |
| SetupConnectedService(RpcIdentifier(""), &endpoint, &bss_path)); |
| EXPECT_CALL(*wifi_provider(), OnEndpointRemoved(EndpointMatch(endpoint))) |
| .WillOnce(Return(nullptr)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()).Times(0); |
| RemoveBSS(bss_path); |
| } |
| |
| TEST_F(WiFiMainTest, ReconnectPreservesDBusPath) { |
| StartWiFi(); |
| RpcIdentifier kPath("/test/path"); |
| MockWiFiServiceRefPtr service(SetupConnectedService(kPath, nullptr, nullptr)); |
| |
| // Return the service to a connectable state. |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()); |
| InitiateDisconnect(service); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| |
| // Complete the disconnection by reporting a BSS change. |
| ReportCurrentBSSChanged(RpcIdentifier(WPASupplicant::kCurrentBSSNull)); |
| |
| // A second connection attempt should remember the DBus path associated |
| // with this service, and should not request new configuration parameters. |
| EXPECT_CALL(*service, GetSupplicantConfigurationParameters()).Times(0); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), AddNetwork(_, _)).Times(0); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), SelectNetwork(kPath)); |
| InitiateConnect(service); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectPendingService) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service( |
| SetupConnectingService(RpcIdentifier(""), nullptr, nullptr)); |
| EXPECT_EQ(GetPendingService(), service); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()); |
| EXPECT_CALL(*service, SetFailure(_)).Times(0); |
| service->set_expecting_disconnect(true); |
| InitiateDisconnect(service); |
| EXPECT_EQ(service->state(), Service::kStateIdle); |
| EXPECT_EQ(nullptr, GetPendingService()); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectPendingServiceWithFailure) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service( |
| SetupConnectingService(RpcIdentifier(""), nullptr, nullptr)); |
| EXPECT_EQ(GetPendingService(), service); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()); |
| EXPECT_CALL(*service, ShouldIgnoreFailure()).WillOnce(Return(false)); |
| EXPECT_CALL(*service, SetFailure(Service::kFailureUnknown)); |
| InitiateDisconnect(service); |
| EXPECT_EQ(service->state(), Service::kStateIdle); |
| EXPECT_EQ(nullptr, GetPendingService()); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectPendingServiceWithOutOfRange) { |
| StartWiFi(); |
| |
| // Initiate connection with weak signal |
| MockWiFiServiceRefPtr service; |
| MakeNewEndpointAndService(-90, 0, nullptr, &service); |
| InitiateConnect(service); |
| |
| EXPECT_EQ(GetPendingService(), service); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()); |
| EXPECT_CALL(*service, ShouldIgnoreFailure()).WillOnce(Return(false)); |
| EXPECT_CALL(*service, SetFailure(Service::kFailureOutOfRange)); |
| EXPECT_CALL(*service, SignalLevel()).WillRepeatedly(Return(-90)); |
| ReportDisconnectReasonChanged(-IEEE_80211::kReasonCodeInactivity); |
| InitiateDisconnect(service); |
| EXPECT_EQ(service->state(), Service::kStateIdle); |
| EXPECT_EQ(nullptr, GetPendingService()); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectPendingServiceWithCurrent) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service0( |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr)); |
| EXPECT_EQ(service0, GetCurrentService()); |
| EXPECT_EQ(nullptr, GetPendingService()); |
| |
| // We don't explicitly call Disconnect() while transitioning to a new |
| // service. Instead, we use the side-effect of SelectNetwork (verified in |
| // SetupConnectingService). |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()).Times(0); |
| MockWiFiServiceRefPtr service1( |
| SetupConnectingService(RpcIdentifier("/new/path"), nullptr, nullptr)); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| |
| EXPECT_EQ(service0, GetCurrentService()); |
| EXPECT_EQ(service1, GetPendingService()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()); |
| InitiateDisconnect(service1); |
| EXPECT_EQ(service1->state(), Service::kStateIdle); |
| |
| // |current_service_| will be unchanged until supplicant signals |
| // that CurrentBSS has changed. |
| EXPECT_EQ(service0, GetCurrentService()); |
| // |pending_service_| is updated immediately. |
| EXPECT_EQ(nullptr, GetPendingService()); |
| EXPECT_TRUE(GetPendingTimeout().IsCancelled()); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectCurrentService) { |
| StartWiFi(); |
| RpcIdentifier kPath("/fake/path"); |
| MockWiFiServiceRefPtr service(SetupConnectedService(kPath, nullptr, nullptr)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()); |
| service->set_expecting_disconnect(true); |
| InitiateDisconnect(service); |
| |
| // |current_service_| should not change until supplicant reports |
| // a BSS change. |
| EXPECT_EQ(service, GetCurrentService()); |
| |
| // Expect that the entry associated with this network will be disabled. |
| auto network_proxy = std::make_unique<MockSupplicantNetworkProxy>(); |
| EXPECT_CALL(*network_proxy, SetEnabled(false)).WillOnce(Return(true)); |
| EXPECT_CALL(*control_interface(), CreateSupplicantNetworkProxy(kPath)) |
| .WillOnce(Return(ByMove(std::move(network_proxy)))); |
| |
| EXPECT_CALL(*eap_state_handler_, Reset()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveNetwork(kPath)).Times(0); |
| EXPECT_CALL(*service, SetFailure(_)).Times(0); |
| ReportCurrentBSSChanged(RpcIdentifier(WPASupplicant::kCurrentBSSNull)); |
| EXPECT_EQ(service->state(), Service::kStateIdle); |
| EXPECT_EQ(nullptr, GetCurrentService()); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectCurrentServiceWithFailure) { |
| StartWiFi(); |
| RpcIdentifier kPath("/fake/path"); |
| MockWiFiServiceRefPtr service(SetupConnectedService(kPath, nullptr, nullptr)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()); |
| InitiateDisconnect(service); |
| |
| // |current_service_| should not change until supplicant reports |
| // a BSS change. |
| EXPECT_EQ(service, GetCurrentService()); |
| |
| // Expect that the entry associated with this network will be disabled. |
| auto network_proxy = std::make_unique<MockSupplicantNetworkProxy>(); |
| EXPECT_CALL(*network_proxy, SetEnabled(false)).WillOnce(Return(true)); |
| EXPECT_CALL(*control_interface(), CreateSupplicantNetworkProxy(kPath)) |
| .WillOnce(Return(ByMove(std::move(network_proxy)))); |
| |
| EXPECT_CALL(*eap_state_handler_, Reset()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveNetwork(kPath)).Times(0); |
| EXPECT_CALL(*service, ShouldIgnoreFailure()).WillOnce(Return(false)); |
| EXPECT_CALL(*service, SetFailure(Service::kFailureUnknown)); |
| ReportCurrentBSSChanged(RpcIdentifier(WPASupplicant::kCurrentBSSNull)); |
| EXPECT_EQ(service->state(), Service::kStateIdle); |
| EXPECT_EQ(nullptr, GetCurrentService()); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectCurrentServiceWithOutOfRange) { |
| StartWiFi(); |
| |
| // Setup connection with weak signal |
| RpcIdentifier kPath("/fake/path"); |
| MockWiFiServiceRefPtr service; |
| RpcIdentifier bss_path(MakeNewEndpointAndService(-80, 0, nullptr, &service)); |
| EXPECT_CALL(*service, GetSupplicantConfigurationParameters()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), AddNetwork(_, _)) |
| .WillOnce(DoAll(SetArgPointee<1>(kPath), Return(true))); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), SelectNetwork(kPath)); |
| InitiateConnect(service); |
| ReportCurrentBSSChanged(bss_path); |
| ReportStateChanged(WPASupplicant::kInterfaceStateCompleted); |
| |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()); |
| EXPECT_CALL(*service, SignalLevel()).WillRepeatedly(Return(-80)); |
| InitiateDisconnect(service); |
| |
| // |current_service_| should not change until supplicant reports |
| // a BSS change. |
| EXPECT_EQ(service, GetCurrentService()); |
| |
| // Expect that the entry associated with this network will be disabled. |
| auto network_proxy = std::make_unique<MockSupplicantNetworkProxy>(); |
| EXPECT_CALL(*network_proxy, SetEnabled(false)).WillOnce(Return(true)); |
| EXPECT_CALL(*control_interface(), CreateSupplicantNetworkProxy(kPath)) |
| .WillOnce(Return(ByMove(std::move(network_proxy)))); |
| |
| EXPECT_CALL(*eap_state_handler_, Reset()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveNetwork(kPath)).Times(0); |
| EXPECT_CALL(*service, ShouldIgnoreFailure()).WillOnce(Return(false)); |
| EXPECT_CALL(*service, SetFailure(Service::kFailureOutOfRange)); |
| ReportDisconnectReasonChanged(-IEEE_80211::kReasonCodeInactivity); |
| ReportCurrentBSSChanged(RpcIdentifier(WPASupplicant::kCurrentBSSNull)); |
| EXPECT_EQ(service->state(), Service::kStateIdle); |
| EXPECT_EQ(nullptr, GetCurrentService()); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectCurrentServiceWithErrors) { |
| StartWiFi(); |
| RpcIdentifier kPath("/fake/path"); |
| WiFiServiceRefPtr service(SetupConnectedService(kPath, nullptr, nullptr)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()) |
| .WillOnce(Return(false)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveNetwork(kPath)).Times(1); |
| InitiateDisconnect(service); |
| |
| // We may sometimes fail to disconnect via supplicant, and we patch up some |
| // state when this happens. |
| EXPECT_EQ(nullptr, GetCurrentService()); |
| EXPECT_EQ(nullptr, GetSelectedService()); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectCurrentServiceWithPending) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service0( |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr)); |
| MockWiFiServiceRefPtr service1( |
| SetupConnectingService(RpcIdentifier(""), nullptr, nullptr)); |
| EXPECT_EQ(service0, GetCurrentService()); |
| EXPECT_EQ(service1, GetPendingService()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()).Times(0); |
| InitiateDisconnect(service0); |
| |
| EXPECT_EQ(service0, GetCurrentService()); |
| EXPECT_EQ(service1, GetPendingService()); |
| EXPECT_FALSE(GetPendingTimeout().IsCancelled()); |
| |
| EXPECT_CALL(*service0, SetFailure(_)).Times(0); |
| ReportCurrentBSSChanged(RpcIdentifier(WPASupplicant::kCurrentBSSNull)); |
| EXPECT_EQ(service0->state(), Service::kStateIdle); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectCurrentServiceWhileRoaming) { |
| StartWiFi(); |
| RpcIdentifier kPath("/fake/path"); |
| WiFiServiceRefPtr service(SetupConnectedService(kPath, nullptr, nullptr)); |
| |
| // As it roams to another AP, supplicant signals that it is in |
| // the authenticating state. |
| ReportStateChanged(WPASupplicant::kInterfaceStateAuthenticating); |
| |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveNetwork(kPath)); |
| InitiateDisconnect(service); |
| |
| // Because the interface was not connected, we should have immediately |
| // forced ourselves into a disconnected state. |
| EXPECT_EQ(nullptr, GetCurrentService()); |
| EXPECT_EQ(nullptr, GetSelectedService()); |
| |
| // Check calls before TearDown/dtor. |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectWithWiFiServiceConnected) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service0( |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr)); |
| NiceScopedMockLog log; |
| ScopeLogger::GetInstance()->EnableScopesByName("wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(2); |
| EXPECT_CALL(log, Log(_, _, ContainsRegex("DisconnectFromIfActive.*service"))) |
| .Times(1); |
| EXPECT_CALL(log, Log(_, _, ContainsRegex("DisconnectFrom[^a-zA-Z].*service"))) |
| .Times(1); |
| EXPECT_CALL(*service0, IsActive(_)).Times(0); |
| InitiateDisconnectIfActive(service0); |
| |
| Mock::VerifyAndClearExpectations(&log); |
| Mock::VerifyAndClearExpectations(service0.get()); |
| ScopeLogger::GetInstance()->set_verbose_level(0); |
| ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectWithWiFiServiceIdle) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service0( |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr)); |
| InitiateDisconnectIfActive(service0); |
| ReportCurrentBSSChanged(RpcIdentifier(WPASupplicant::kCurrentBSSNull)); |
| MockWiFiServiceRefPtr service1( |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr)); |
| NiceScopedMockLog log; |
| ScopeLogger::GetInstance()->EnableScopesByName("wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(2); |
| EXPECT_CALL(log, Log(_, _, ContainsRegex("DisconnectFromIfActive.*service"))) |
| .Times(1); |
| EXPECT_CALL(*service0, IsActive(_)).WillOnce(Return(false)); |
| EXPECT_CALL(log, Log(_, _, HasSubstr("is not active, no need"))).Times(1); |
| EXPECT_CALL(log, Log(logging::LOGGING_WARNING, _, |
| ContainsRegex("In .*DisconnectFrom\\(.*\\):"))) |
| .Times(0); |
| InitiateDisconnectIfActive(service0); |
| |
| Mock::VerifyAndClearExpectations(&log); |
| Mock::VerifyAndClearExpectations(service0.get()); |
| ScopeLogger::GetInstance()->set_verbose_level(0); |
| ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectWithWiFiServiceConnectedInError) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service0( |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr)); |
| SetCurrentService(nullptr); |
| ResetPendingService(); |
| NiceScopedMockLog log; |
| ScopeLogger::GetInstance()->EnableScopesByName("wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(2); |
| EXPECT_CALL(log, Log(_, _, ContainsRegex("DisconnectFromIfActive.*service"))) |
| .Times(1); |
| EXPECT_CALL(*service0, IsActive(_)).WillOnce(Return(true)); |
| EXPECT_CALL(log, Log(_, _, ContainsRegex("DisconnectFrom[^a-zA-Z].*service"))) |
| .Times(1); |
| EXPECT_CALL(log, Log(logging::LOGGING_WARNING, _, |
| ContainsRegex("In .*DisconnectFrom\\(.*\\):"))) |
| .Times(1); |
| InitiateDisconnectIfActive(service0); |
| |
| Mock::VerifyAndClearExpectations(&log); |
| Mock::VerifyAndClearExpectations(service0.get()); |
| ScopeLogger::GetInstance()->set_verbose_level(0); |
| ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); |
| } |
| |
| TEST_F(WiFiMainTest, TimeoutPendingServiceWithEndpoints) { |
| StartScan(WiFiState::ScanMethod::kFull); |
| const base::CancelableOnceClosure& pending_timeout = GetPendingTimeout(); |
| EXPECT_TRUE(pending_timeout.IsCancelled()); |
| MockWiFiServiceRefPtr service = |
| AttemptConnection(WiFiState::ScanMethod::kFull, nullptr, nullptr); |
| |
| EXPECT_CALL(*service, SignalLevel()).WillRepeatedly(Return(-80)); |
| |
| // Innocuous redundant call to NotifyDeviceScanFinished. |
| ExpectFoundNothing(); |
| EXPECT_CALL(*metrics(), NotifyDeviceConnectFinished(_)).Times(0); |
| NiceScopedMockLog log; |
| ScopeLogger::GetInstance()->EnableScopesByName("wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(10); |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| EXPECT_CALL(log, Log(_, _, HasSubstr("-> FULL_NOCONNECTION"))); |
| |
| // In PendingTimeoutHandler we depend on Service internal behaviour for |
| // SetFailure() so let's "unmock" SetFailure() and call the implementation. |
| EXPECT_CALL(*service, SetFailure(_)) |
| .WillRepeatedly(WithArg<0>([&service](auto failure) { |
| service->WiFiService::SetFailure(failure); |
| })); |
| // Timeout the connection attempt. |
| TimeoutPendingConnection(service); |
| // Service state should be idle, so it is connectable again. |
| EXPECT_EQ(service->state(), Service::kStateIdle); |
| |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| EXPECT_EQ(nullptr, GetPendingService()); |
| Mock::VerifyAndClearExpectations(service.get()); |
| |
| ScopeLogger::GetInstance()->set_verbose_level(0); |
| ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); |
| } |
| |
| TEST_F(WiFiMainTest, TimeoutPendingServiceWithoutEndpoints) { |
| StartWiFi(); |
| const base::CancelableOnceClosure& pending_timeout = GetPendingTimeout(); |
| EXPECT_TRUE(pending_timeout.IsCancelled()); |
| MockWiFiServiceRefPtr service( |
| SetupConnectingService(RpcIdentifier(""), nullptr, nullptr)); |
| EXPECT_FALSE(pending_timeout.IsCancelled()); |
| EXPECT_EQ(service, GetPendingService()); |
| // We expect the service to get a disconnect call, but in this scenario |
| // the service does nothing. |
| EXPECT_CALL(*service, Disconnect(_, HasSubstr("PendingTimeoutHandler"))); |
| // current_endpoint_ == nullptr so, without endpoint, |
| // the service should return min possible value of int16_t |
| EXPECT_CALL(*service, SignalLevel()) |
| .WillRepeatedly(Return(WiFiService::SignalLevelMin)); |
| // DisconnectFrom() should be called directly from WiFi. |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()); |
| // In PendingTimeoutHandler we depend on Service internal behaviour for |
| // SetFailure() so let's "unmock" SetFailure() and call the implementation. |
| EXPECT_CALL(*service, SetFailure(_)) |
| .WillRepeatedly(WithArg<0>([&service](auto failure) { |
| service->WiFiService::SetFailure(failure); |
| })); |
| pending_timeout.callback().Run(); |
| EXPECT_EQ(service->state(), Service::kStateIdle); |
| EXPECT_EQ(nullptr, GetPendingService()); |
| } |
| |
| TEST_F(WiFiMainTest, HandshakeTimerCancelledByConnectionFailure) { |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| auto& handshake_timeout = GetHandshakeTimeout(); |
| WiFiEndpointRefPtr endpoint; |
| RpcIdentifier bss_path; |
| MockWiFiServiceRefPtr service( |
| SetupConnectingService(RpcIdentifier(""), &endpoint, &bss_path)); |
| |
| // When 802.11 association finishes, the pending timer stops and the handshake |
| // timer starts. Note the pending timer is stopped by BSS change and the |
| // handshake timers is triggered by supplicant state change. |
| ReportCurrentBSSChanged(bss_path); |
| EXPECT_TRUE(GetPendingTimeout().IsCancelled()); |
| EXPECT_TRUE(handshake_timeout.IsCancelled()); |
| ReportStateChanged(WPASupplicant::kInterfaceStateAssociated); |
| EXPECT_FALSE(handshake_timeout.IsCancelled()); |
| |
| // When handshake fails, the timer is cancelled. |
| ReportStateChanged(WPASupplicant::kInterfaceStateDisconnected); |
| EXPECT_TRUE(handshake_timeout.IsCancelled()); |
| } |
| |
| TEST_F(WiFiMainTest, TimeoutHandshake) { |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| auto& handshake_timeout = GetHandshakeTimeout(); |
| WiFiEndpointRefPtr endpoint; |
| RpcIdentifier bss_path; |
| MockWiFiServiceRefPtr service( |
| SetupConnectingService(RpcIdentifier(""), &endpoint, &bss_path)); |
| |
| // When 802.11 association finishes, the pending timer stops and the handshake |
| // timer starts. Note the pending timer is stopped by BSS change and the |
| // handshake timers is triggered by supplicant state change. |
| ReportCurrentBSSChanged(bss_path); |
| EXPECT_TRUE(GetPendingTimeout().IsCancelled()); |
| EXPECT_TRUE(handshake_timeout.IsCancelled()); |
| ReportStateChanged(WPASupplicant::kInterfaceStateAssociated); |
| EXPECT_FALSE(handshake_timeout.IsCancelled()); |
| EXPECT_EQ(nullptr, GetPendingService()); |
| EXPECT_NE(nullptr, GetCurrentService()); |
| |
| // Handshake timeout initiates disconnection. |
| EXPECT_CALL(*service, Disconnect(_, HasSubstr("HandshakeTimeoutHandler"))); |
| test_event_dispatcher_->task_environment().FastForwardBy(base::Seconds(15)); |
| |
| // Make sure shill doesn't handle disconnect until it receives the |
| // |CurrentBSSChanged| signal from supplicant. |
| // Here we invoke |DisconnectFrom| through |InitiateDisconnect| because the |
| // mocked service is not full-fledged to call |DisconnectFrom|. This is |
| // covered in |WiFiServiceTest.DisconnectWithWiFi|. |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()); |
| InitiateDisconnect(service); |
| EXPECT_NE(nullptr, GetCurrentService()); |
| ReportCurrentBSSChanged(RpcIdentifier(WPASupplicant::kCurrentBSSNull)); |
| EXPECT_EQ(service->state(), Service::kStateIdle); |
| EXPECT_EQ(nullptr, GetCurrentService()); |
| |
| // Verify expectations now, because WiFi may report other state changes |
| // when WiFi is Stop()-ed (during TearDown()). |
| Mock::VerifyAndClearExpectations(service.get()); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectInvalidService) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service; |
| MakeNewEndpointAndService(0, 0, nullptr, &service); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()).Times(0); |
| InitiateDisconnect(service); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectCurrentServiceFailure) { |
| StartWiFi(); |
| RpcIdentifier kPath("/fake/path"); |
| WiFiServiceRefPtr service(SetupConnectedService(kPath, nullptr, nullptr)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()) |
| .WillRepeatedly(Return(false)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveNetwork(kPath)); |
| InitiateDisconnect(service); |
| EXPECT_EQ(nullptr, GetCurrentService()); |
| } |
| |
| TEST_F(WiFiMainTest, Stop) { |
| StartWiFi(); |
| WiFiEndpointRefPtr endpoint0; |
| RpcIdentifier kPath("/fake/path"); |
| WiFiServiceRefPtr service0(SetupConnectedService(kPath, &endpoint0, nullptr)); |
| WiFiEndpointRefPtr endpoint1; |
| MakeNewEndpointAndService(0, 0, &endpoint1, nullptr); |
| |
| EXPECT_CALL(*wifi_provider(), OnEndpointRemoved(EndpointMatch(endpoint0))) |
| .WillOnce(Return(nullptr)); |
| EXPECT_CALL(*wifi_provider(), OnEndpointRemoved(EndpointMatch(endpoint1))) |
| .WillOnce(Return(nullptr)); |
| EXPECT_CALL(*wifi_provider(), ResetServicesAutoConnectCooldownTime()) |
| .Times(1); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveNetwork(kPath)).Times(1); |
| StopWiFi(); |
| Mock::VerifyAndClearExpectations(wifi_provider()); |
| EXPECT_TRUE(GetScanTimer().IsCancelled()); |
| EXPECT_FALSE(wifi()->weak_ptr_factory_while_started_.HasWeakPtrs()); |
| } |
| |
| TEST_F(WiFiMainTest, StopWhileConnected) { |
| StartWiFi(); |
| WiFiEndpointRefPtr endpoint; |
| WiFiServiceRefPtr service( |
| SetupConnectedService(RpcIdentifier(""), &endpoint, nullptr)); |
| std::unique_ptr<EndpointRemovalHandler> handler = |
| MakeEndpointRemovalHandler(service); |
| EXPECT_CALL(*wifi_provider(), OnEndpointRemoved(EndpointMatch(endpoint))) |
| .WillOnce( |
| Invoke(handler.get(), &EndpointRemovalHandler::OnEndpointRemoved)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()); |
| StopWiFi(); |
| EXPECT_EQ(nullptr, GetCurrentService()); |
| } |
| |
| TEST_F(WiFiMainTest, StopDisconnectReason) { |
| StartWiFi(); |
| |
| KeyValueStore props; |
| props.Set<int32_t>(WPASupplicant::kInterfacePropertyDisconnectReason, |
| -IEEE_80211::kReasonCodeSenderHasLeft); |
| |
| PropertiesChanged(props); |
| StopWiFi(); |
| EXPECT_CALL(*metrics(), |
| Notify80211Disconnect(Metrics::kDisconnectedNotByAp, |
| IEEE_80211::kReasonCodeSenderHasLeft)); |
| |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| TEST_F(WiFiMainTest, SignalChanged) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| // Use a reference to the endpoint instance in the WiFi device instead of |
| // the copy returned by SetupConnectedService(). |
| WiFiEndpointRefPtr endpoint = GetEndpointMap().begin()->second; |
| |
| KeyValueStore props; |
| props.Set<int32_t>(WPASupplicant::kSignalChangePropertyRSSI, -70); |
| KeyValueStore properties; |
| properties.Set<KeyValueStore>(WPASupplicant::kSignalChangeProperty, props); |
| |
| PropertiesChanged(properties); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| EXPECT_EQ(GetStationStats().signal, -70); |
| EXPECT_EQ(endpoint->signal_strength(), -70); |
| |
| StopWiFi(); |
| } |
| |
| TEST_F(WiFiMainTest, LowRSSIScanTrigger) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| // Use a reference to the endpoint instance in the WiFi device instead of |
| // the copy returned by SetupConnectedService(). |
| WiFiEndpointRefPtr endpoint = GetEndpointMap().begin()->second; |
| |
| // Trigger ScanDoneTask so that the phy state is idle |
| ReportScanDone(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| KeyValueStore props; |
| props.Set<int32_t>(WPASupplicant::kSignalChangePropertyRSSI, -50); |
| KeyValueStore properties; |
| properties.Set<KeyValueStore>(WPASupplicant::kSignalChangeProperty, props); |
| |
| // Low RSSI (0 -> -50) should trigger scan |
| PropertiesChanged(properties); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| EXPECT_EQ(endpoint->signal_strength(), -50); |
| |
| ReportScanDone(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| props.Set<int32_t>(WPASupplicant::kSignalChangePropertyRSSI, -60); |
| properties.Set<KeyValueStore>(WPASupplicant::kSignalChangeProperty, props); |
| |
| // Another RSSI drop should be throttled |
| PropertiesChanged(properties); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)).Times(0); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| EXPECT_EQ(endpoint->signal_strength(), -60); |
| |
| StopWiFi(); |
| } |
| |
| TEST_F(WiFiMainTest, LowRSSIScanTriggerDisabled) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| // Use a reference to the endpoint instance in the WiFi device instead of |
| // the copy returned by SetupConnectedService(). |
| WiFiEndpointRefPtr endpoint = GetEndpointMap().begin()->second; |
| EXPECT_TRUE(SetBgscanMethod(WPASupplicant::kNetworkBgscanMethodNone)); |
| |
| // Trigger ScanDoneTask so that the phy state is idle |
| ReportScanDone(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| KeyValueStore props; |
| props.Set<int32_t>(WPASupplicant::kSignalChangePropertyRSSI, -50); |
| KeyValueStore properties; |
| properties.Set<KeyValueStore>(WPASupplicant::kSignalChangeProperty, props); |
| |
| // Low RSSI (0 -> -50) should not trigger scan when bgscan method == none. |
| PropertiesChanged(properties); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)).Times(0); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| EXPECT_EQ(endpoint->signal_strength(), -50); |
| |
| StopWiFi(); |
| } |
| |
| TEST_F(WiFiMainTest, SignalChangedBeaconAverage) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| // Use a reference to the endpoint instance in the WiFi device instead of |
| // the copy returned by SetupConnectedService(). |
| WiFiEndpointRefPtr endpoint = GetEndpointMap().begin()->second; |
| |
| KeyValueStore props; |
| props.Set<int32_t>(WPASupplicant::kSignalChangePropertyRSSI, -70); |
| props.Set<int32_t>(WPASupplicant::kSignalChangePropertyAverageBeaconRSSI, |
| -60); |
| KeyValueStore properties; |
| properties.Set<KeyValueStore>(WPASupplicant::kSignalChangeProperty, props); |
| |
| PropertiesChanged(properties); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| EXPECT_EQ(GetStationStats().signal, -70); |
| EXPECT_EQ(endpoint->signal_strength(), -60); |
| |
| StopWiFi(); |
| } |
| |
| TEST_F(WiFiMainTest, SignalChangedAverage) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| // Use a reference to the endpoint instance in the WiFi device instead of |
| // the copy returned by SetupConnectedService(). |
| WiFiEndpointRefPtr endpoint = GetEndpointMap().begin()->second; |
| |
| KeyValueStore props; |
| props.Set<int32_t>(WPASupplicant::kSignalChangePropertyRSSI, -70); |
| props.Set<int32_t>(WPASupplicant::kSignalChangePropertyAverageRSSI, -65); |
| props.Set<int32_t>(WPASupplicant::kSignalChangePropertyAverageBeaconRSSI, |
| -60); |
| KeyValueStore properties; |
| properties.Set<KeyValueStore>(WPASupplicant::kSignalChangeProperty, props); |
| |
| PropertiesChanged(properties); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| EXPECT_EQ(GetStationStats().signal, -70); |
| EXPECT_EQ(endpoint->signal_strength(), -65); |
| |
| StopWiFi(); |
| } |
| |
| TEST_F(WiFiMainTest, UpdateLinkSpeed) { |
| StartWiFi(); |
| WiFiEndpointRefPtr endpoint; |
| RpcIdentifier bss_path; |
| MockWiFiServiceRefPtr service( |
| SetupConnectedService(RpcIdentifier(""), &endpoint, &bss_path)); |
| |
| KeyValueStore props; |
| // We dont care about Signal but signal related properties are required. |
| props.Set<int32_t>(WPASupplicant::kSignalChangePropertyRSSI, -70); |
| props.Set<uint32_t>(WPASupplicant::kSignalChangePropertyRxSpeed, 20000UL); |
| props.Set<uint32_t>(WPASupplicant::kSignalChangePropertyTxSpeed, 50000UL); |
| KeyValueStore properties; |
| properties.Set<KeyValueStore>(WPASupplicant::kSignalChangeProperty, props); |
| |
| EXPECT_CALL(*service, SetDownlinkSpeedKbps(20000)).Times(1); |
| EXPECT_CALL(*service, SetUplinkSpeedKbps(50000)).Times(1); |
| |
| PropertiesChanged(properties); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| StopWiFi(); |
| } |
| |
| TEST_F(WiFiMainTest, EmptyLinkSpeed) { |
| StartWiFi(); |
| WiFiEndpointRefPtr endpoint; |
| RpcIdentifier bss_path; |
| MockWiFiServiceRefPtr service( |
| SetupConnectedService(RpcIdentifier(""), &endpoint, &bss_path)); |
| |
| KeyValueStore props; |
| // We dont care about Signal but signal related properties are required. |
| // Check if link speeds will be set when the properties are not set. |
| props.Set<int32_t>(WPASupplicant::kSignalChangePropertyRSSI, -70); |
| KeyValueStore properties; |
| properties.Set<KeyValueStore>(WPASupplicant::kSignalChangeProperty, props); |
| |
| EXPECT_CALL(*service, SetDownlinkSpeedKbps(_)).Times(0); |
| EXPECT_CALL(*service, SetUplinkSpeedKbps(_)).Times(0); |
| |
| PropertiesChanged(properties); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| StopWiFi(); |
| } |
| |
| TEST_F(WiFiMainTest, UpdateLinkSpeedWhenDisconnected) { |
| StartWiFi(); |
| WiFiEndpointRefPtr endpoint; |
| RpcIdentifier bss_path; |
| MockWiFiServiceRefPtr service( |
| SetupConnectedService(RpcIdentifier(""), &endpoint, &bss_path)); |
| |
| // Disconnect wifi and make sure it is disconnected. |
| ReportCurrentBSSChanged(RpcIdentifier(WPASupplicant::kCurrentBSSNull)); |
| EXPECT_EQ(nullptr, GetCurrentService()); |
| |
| KeyValueStore props; |
| // We dont care about Signal but signal related properties are required. |
| // Check if link speeds will be set when wifi is disconnected. |
| props.Set<int32_t>(WPASupplicant::kSignalChangePropertyRSSI, -70); |
| props.Set<uint32_t>(WPASupplicant::kSignalChangePropertyRxSpeed, 20000UL); |
| props.Set<uint32_t>(WPASupplicant::kSignalChangePropertyTxSpeed, 50000UL); |
| KeyValueStore properties; |
| properties.Set<KeyValueStore>(WPASupplicant::kSignalChangeProperty, props); |
| |
| EXPECT_CALL(*service, SetDownlinkSpeedKbps(_)).Times(0); |
| EXPECT_CALL(*service, SetUplinkSpeedKbps(_)).Times(0); |
| |
| PropertiesChanged(properties); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| StopWiFi(); |
| } |
| |
| TEST_F(WiFiMainTest, ReconnectTimer) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service( |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr)); |
| EXPECT_CALL(*service, IsConnected(nullptr)).WillRepeatedly(Return(true)); |
| EXPECT_TRUE(GetReconnectTimeoutCallback().IsCancelled()); |
| ReportStateChanged(WPASupplicant::kInterfaceStateDisconnected); |
| EXPECT_FALSE(GetReconnectTimeoutCallback().IsCancelled()); |
| ReportStateChanged(WPASupplicant::kInterfaceStateCompleted); |
| EXPECT_TRUE(GetReconnectTimeoutCallback().IsCancelled()); |
| ReportStateChanged(WPASupplicant::kInterfaceStateDisconnected); |
| EXPECT_FALSE(GetReconnectTimeoutCallback().IsCancelled()); |
| ReportCurrentBSSChanged(kBSSName); |
| EXPECT_TRUE(GetReconnectTimeoutCallback().IsCancelled()); |
| ReportStateChanged(WPASupplicant::kInterfaceStateDisconnected); |
| EXPECT_FALSE(GetReconnectTimeoutCallback().IsCancelled()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()); |
| GetReconnectTimeoutCallback().callback().Run(); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| EXPECT_TRUE(GetReconnectTimeoutCallback().IsCancelled()); |
| } |
| |
| MATCHER_P(ScanRequestHasHiddenSSIDAndSkipsBroadcast, ssid, "") { |
| if (!arg.template Contains<ByteArrays>(WPASupplicant::kPropertyScanSSIDs)) { |
| return false; |
| } |
| |
| ByteArrays ssids = |
| arg.template Get<ByteArrays>(WPASupplicant::kPropertyScanSSIDs); |
| // When the ssid limit is 1, a valid Scan containing a |
| // single hidden SSID should only contain the SSID we are looking for. |
| return ssids.size() == 1 && ssids[0] == ssid; |
| } |
| |
| MATCHER_P(ScanRequestHasHiddenSSID, ssid, "") { |
| if (!arg.template Contains<ByteArrays>(WPASupplicant::kPropertyScanSSIDs)) { |
| return false; |
| } |
| |
| ByteArrays ssids = |
| arg.template Get<ByteArrays>(WPASupplicant::kPropertyScanSSIDs); |
| // A valid Scan containing a single hidden SSID should contain |
| // two SSID entries: one containing the SSID we are looking for, |
| // and an empty entry, signifying that we also want to do a |
| // broadcast probe request for all non-hidden APs as well. |
| return ssids.size() == 2 && ssids[0] == ssid && ssids[1].empty(); |
| } |
| |
| MATCHER_P(ScanRequestHasHiddenSSIDs, hidden_ssids, "") { |
| if (!arg.template Contains<ByteArrays>(WPASupplicant::kPropertyScanSSIDs)) { |
| return false; |
| } |
| |
| ByteArrays ssids = |
| arg.template Get<ByteArrays>(WPASupplicant::kPropertyScanSSIDs); |
| // A valid Scan containing a N SSIDs should contain N+1 SSID entries: one for |
| // each SSID we are looking for, and an empty entry, signifying that we also |
| // want to do a broadcast probe request for all non-hidden APs as well. |
| if (ssids.size() != hidden_ssids.size() + 1) |
| return false; |
| |
| for (size_t i = 0; i < hidden_ssids.size(); ++i) { |
| if (ssids[i] != hidden_ssids[i]) |
| return false; |
| } |
| |
| return ssids[ssids.size() - 1].empty(); |
| } |
| |
| MATCHER(ScanRequestHasNoHiddenSSID, "") { |
| return !arg.template Contains<ByteArrays>(WPASupplicant::kPropertyScanSSIDs); |
| } |
| |
| // When the driver reports that it supports 0 SSIDs in the scan request, no |
| // hidden SSIDs should be included. |
| TEST_F(WiFiMainTest, ScanHiddenRespectsMaxSSIDs0) { |
| SetInterfaceScanLimit(0); |
| |
| // Introduce 8 hidden SSIDs. |
| ByteArrays ssids{{'a'}, {'b'}, {'c'}, {'d'}, {'e'}, {'f'}, {'g'}, {'h'}}; |
| EXPECT_CALL(*wifi_provider(), GetHiddenSSIDList()) |
| .WillRepeatedly(Return(ssids)); |
| StartWiFi(); |
| |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), |
| Scan(ScanRequestHasNoHiddenSSID())); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| // When the driver reports that it supports 1 SSIDs in the scan request, it |
| // should alternate between including a hidden SSID and including a broadcast |
| // entry. |
| TEST_F(WiFiMainTest, ScanHiddenRespectsMaxSSIDs1) { |
| SetInterfaceScanLimit(1); |
| |
| // Introduce 8 hidden SSIDs. |
| ByteArrays ssids{{'a'}, {'b'}, {'c'}, {'d'}, {'e'}, {'f'}, {'g'}, {'h'}}; |
| EXPECT_CALL(*wifi_provider(), GetHiddenSSIDList()) |
| .WillRepeatedly(Return(ssids)); |
| |
| // First scan |
| StartWiFi(); |
| // Start by including hidden entry |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), |
| Scan(ScanRequestHasHiddenSSIDAndSkipsBroadcast(ssids[0]))); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| // Second scan |
| InitiateScan(); |
| // Now we have no hidden SSID and do the broadcast scan |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), |
| Scan(ScanRequestHasNoHiddenSSID())); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| // Third scan |
| InitiateScan(); |
| // back to doing a hidden SSID scan |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), |
| Scan(ScanRequestHasHiddenSSIDAndSkipsBroadcast(ssids[0]))); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| // When the driver reports that it supports smaller number of SSIDs than we have |
| // in our configuration, we should respect that and send one less than the |
| // driver capability with additional empty entry signalling broadcast scan. |
| // Here we test this with driver/configuration values 2/8 respectively. |
| TEST_F(WiFiMainTest, ScanHiddenLimitToCapability) { |
| SetInterfaceScanLimit(2); |
| |
| // Introduce 8 hidden SSIDs. |
| ByteArrays ssids{{'a'}, {'b'}, {'c'}, {'d'}, {'e'}, {'f'}, {'g'}, {'h'}}; |
| EXPECT_CALL(*wifi_provider(), GetHiddenSSIDList()) |
| .WillRepeatedly(Return(ssids)); |
| StartWiFi(); |
| |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), |
| Scan(ScanRequestHasHiddenSSID(ssids[0]))); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| // When the driver reports that it supports more SSIDs in the scan request than |
| // we have in our configuration then all hidden SSIDs should be included (along |
| // with the broadcast entry). Here we test this with driver/configuration |
| // values 9/8 respectively. |
| TEST_F(WiFiMainTest, ScanHiddenUseAllSSIDs) { |
| SetInterfaceScanLimit(9); |
| |
| // Introduce 8 hidden SSIDs. |
| ByteArrays ssids{{'a'}, {'b'}, {'c'}, {'d'}, {'e'}, {'f'}, {'g'}, {'h'}}; |
| EXPECT_CALL(*wifi_provider(), GetHiddenSSIDList()) |
| .WillRepeatedly(Return(ssids)); |
| StartWiFi(); |
| |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), |
| Scan(ScanRequestHasHiddenSSIDs(ssids))); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| // WPA supplicant has its own limit of number of hidden networks that it accepts |
| // for scan (as of writing this: 16) so let's test that when driver reports more |
| // and we have that many hidden networks then we remove those above the limit |
| // (as usual the limit includes 1 additional empty entry for broadcast scan). |
| TEST_F(WiFiMainTest, ScanHiddenLimitCapToSupplicantLimit) { |
| SetInterfaceScanLimit(20); |
| |
| ByteArrays ssids{{'a'}, {'b'}, {'c'}, {'d'}, {'e'}, {'f'}, {'g'}, {'h'}, |
| {'i'}, {'j'}, {'k'}, {'l'}, {'m'}, {'n'}, {'o'}, {'p'}}; |
| ByteArrays first_15{ssids.begin(), ssids.begin() + 15}; |
| EXPECT_CALL(*wifi_provider(), GetHiddenSSIDList()) |
| .WillRepeatedly(Return(ssids)); |
| StartWiFi(); |
| |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), |
| Scan(ScanRequestHasHiddenSSIDs(first_15))); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| // Obtaining MaxScanSSID can fail in two ways - either we can fail in D-Bus |
| // communication or we can get capabilities with this property missing. In |
| // both cases we should fall back to a default value (4) so at most 3 hidden |
| // networks are requested. This test checks the "failed D-Bus" (see comments |
| // at SetInterfaceScanLimit()). |
| TEST_F(WiFiMainTest, ScanHiddenFailedDBusRespectsDefaultMaxSSIDs) { |
| SetInterfaceScanLimit(0, false); |
| |
| ByteArrays ssids{{'a'}, {'b'}, {'c'}, {'d'}, {'e'}, {'f'}, {'g'}, {'h'}}; |
| ByteArrays first_3{ssids.begin(), ssids.begin() + 3}; |
| EXPECT_CALL(*wifi_provider(), GetHiddenSSIDList()) |
| .WillRepeatedly(Return(ssids)); |
| StartWiFi(); |
| |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), |
| Scan(ScanRequestHasHiddenSSIDs(first_3))); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| // See comment above - this test checks the case of Capabilities with missing |
| // MaxScanSSID property. |
| TEST_F(WiFiMainTest, ScanHiddenMissingValueRespectsDefaultMaxSSIDs) { |
| SetInterfaceScanLimit(-1); |
| |
| ByteArrays ssids{{'a'}, {'b'}, {'c'}, {'d'}, {'e'}, {'f'}, {'g'}, {'h'}}; |
| ByteArrays first_3{ssids.begin(), ssids.begin() + 3}; |
| EXPECT_CALL(*wifi_provider(), GetHiddenSSIDList()) |
| .WillRepeatedly(Return(ssids)); |
| StartWiFi(); |
| |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), |
| Scan(ScanRequestHasHiddenSSIDs(first_3))); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| TEST_F(WiFiMainTest, ScanNoHidden) { |
| StartWiFi(); |
| EXPECT_CALL(*wifi_provider(), GetHiddenSSIDList()) |
| .WillOnce(Return(ByteArrays())); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), |
| Scan(ScanRequestHasNoHiddenSSID())); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| TEST_F(WiFiMainTest, ScanWiFiDisabledAfterResume) { |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)).Times(0); |
| StartWiFi(); |
| StopWiFi(); |
| OnAfterResume(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| TEST_F(WiFiMainTest, ScanRejected) { |
| ScopedMockLog log; |
| StartWiFi(); |
| ReportScanDone(); |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| EXPECT_CALL(log, Log(_, _, EndsWith("Scan failed"))).Times(1); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)).WillOnce(Return(false)); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| MATCHER_P(AllowRoam, allow_roam_expected, "") { |
| if (!arg.template Contains<bool>(WPASupplicant::kPropertyScanAllowRoam)) { |
| return false; |
| } |
| |
| bool allow_roam_actual = |
| arg.template Get<bool>(WPASupplicant::kPropertyScanAllowRoam); |
| return allow_roam_expected == allow_roam_actual; |
| } |
| |
| TEST_F(WiFiMainTest, ScanAllowRoam) { |
| StartWiFi(); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(AllowRoam(true))); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| StopWiFi(); |
| |
| StartWiFi(); |
| manager()->props_.scan_allow_roam = false; |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(AllowRoam(false))); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| MATCHER_P3(RequestScanType, |
| scan_type_expected, |
| scan_non_coloc_6ghz_expected, |
| scan_6ghz_only_expected, |
| "") { |
| if (!arg.template Contains<std::string>(WPASupplicant::kPropertyScanType)) { |
| return false; |
| } |
| if (!arg.template Contains<bool>(WPASupplicant::kPropertyScanNonColoc6GHz)) { |
| return false; |
| } |
| if (!arg.template Contains<bool>(WPASupplicant::kPropertyScan6GHzOnly)) { |
| return false; |
| } |
| |
| std::string scan_type_actual = |
| arg.template Get<std::string>(WPASupplicant::kPropertyScanType); |
| bool scan_non_coloc_6ghz_actual = |
| arg.template Get<bool>(WPASupplicant::kPropertyScanNonColoc6GHz); |
| bool scan_6ghz_only_actual = |
| arg.template Get<bool>(WPASupplicant::kPropertyScan6GHzOnly); |
| return scan_type_expected == scan_type_actual && |
| scan_non_coloc_6ghz_expected == scan_non_coloc_6ghz_actual && |
| scan_6ghz_only_expected == scan_6ghz_only_actual; |
| } |
| |
| TEST_F(WiFiMainTest, WiFiRequestScanTypeDefault) { |
| Error error; |
| StartWiFi(); |
| // Dispatch any scan tasks that may have been called previously. |
| test_event_dispatcher_->DispatchPendingEvents(); |
| manager()->props_.request_scan_type = kWiFiRequestScanTypeDefault; |
| |
| EXPECT_CALL( |
| *GetSupplicantInterfaceProxy(), |
| Scan(RequestScanType(WPASupplicant::kScanTypeActive, false, false))) |
| .Times(WiFi::kRequestScanCycle - 1); |
| EXPECT_CALL( |
| *GetSupplicantInterfaceProxy(), |
| Scan(RequestScanType(WPASupplicant::kScanTypePassive, true, true))); |
| SetScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone, |
| __func__); |
| for (int i = 0; i < WiFi::kRequestScanCycle; i++) { |
| Scan(&error, "RequestScan", true); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| ReportScanDone(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| StopWiFi(); |
| } |
| |
| TEST_F(WiFiMainTest, WiFiRequestScanTypeActive) { |
| Error error; |
| StartWiFi(); |
| // Dispatch any scan tasks that may have been called previously. |
| test_event_dispatcher_->DispatchPendingEvents(); |
| EXPECT_CALL( |
| *GetSupplicantInterfaceProxy(), |
| Scan(RequestScanType(WPASupplicant::kScanTypeActive, false, false))); |
| manager()->props_.request_scan_type = kWiFiRequestScanTypeActive; |
| SetScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone, |
| __func__); |
| Scan(&error, "RequestScan", true); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| StopWiFi(); |
| } |
| |
| TEST_F(WiFiMainTest, WiFiRequestScanTypePassive) { |
| Error error; |
| StartWiFi(); |
| // Dispatch any scan tasks that may have been called previously. |
| test_event_dispatcher_->DispatchPendingEvents(); |
| EXPECT_CALL( |
| *GetSupplicantInterfaceProxy(), |
| Scan(RequestScanType(WPASupplicant::kScanTypePassive, true, true))); |
| manager()->props_.request_scan_type = kWiFiRequestScanTypePassive; |
| SetScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone, |
| __func__); |
| Scan(&error, "RequestScan", true); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| StopWiFi(); |
| } |
| |
| TEST_F(WiFiMainTest, WiFiRequestScanTypePassiveNonDBus) { |
| Error error; |
| StartWiFi(); |
| // Dispatch any scan tasks that may have been called previously. |
| test_event_dispatcher_->DispatchPendingEvents(); |
| EXPECT_CALL( |
| *GetSupplicantInterfaceProxy(), |
| Scan(RequestScanType(WPASupplicant::kScanTypeActive, false, false))); |
| manager()->props_.request_scan_type = kWiFiRequestScanTypePassive; |
| SetScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone, |
| __func__); |
| Scan(&error, "NotRequestScan", false); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| StopWiFi(); |
| } |
| |
| TEST_F(WiFiMainTest, WEPSupported) { |
| // Connection attempt to service with WEP security should succeed when WEP is |
| // supported. |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kWep); |
| SetWEPSupport(true); |
| ExpectConnecting(); |
| InitiateConnect(service); |
| } |
| |
| TEST_F(WiFiMainTest, WEPUnsupported) { |
| // Connection attempt to service with WEP security should fail when WEP is |
| // unsupported. |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kWep); |
| SetWEPSupport(false); |
| ExpectNotConnecting(); |
| InitiateConnect(service); |
| } |
| |
| TEST_F(WiFiMainTest, InitialSupplicantState) { |
| EXPECT_EQ(WiFi::kInterfaceStateUnknown, GetSupplicantState()); |
| } |
| |
| TEST_F(WiFiMainTest, StateChangeNoService) { |
| // State change should succeed even if there is no pending Service. |
| ReportStateChanged(WPASupplicant::kInterfaceStateScanning); |
| EXPECT_EQ(WPASupplicant::kInterfaceStateScanning, GetSupplicantState()); |
| } |
| |
| TEST_F(WiFiMainTest, StateChangeWithService) { |
| // Forward transition should trigger a Service state change. |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| InitiateConnect(service); |
| EXPECT_EQ(service->state(), Service::kStateAssociating); |
| ReportStateChanged(WPASupplicant::kInterfaceStateAssociated); |
| EXPECT_EQ(service->state(), Service::kStateAssociating); |
| } |
| |
| TEST_F(WiFiMainTest, StateChangeBackwardsWithService) { |
| // Some backwards transitions should not trigger a Service state change. |
| // Supplicant state should still be updated, however. |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| MockWiFiServiceRefPtr service; |
| RpcIdentifier bss_path = MakeNewEndpointAndService(-90, 0, nullptr, &service); |
| EXPECT_CALL(*service, ResetSuspectedCredentialFailures()); |
| InitiateConnect(service); |
| ReportCurrentBSSChanged(bss_path); |
| EXPECT_EQ(service->state(), Service::kStateAssociating); |
| ReportStateChanged(WPASupplicant::kInterfaceStateCompleted); |
| EXPECT_EQ(service->state(), Service::kStateConfiguring); |
| SetIsRoamingInProgress(true); |
| ReportStateChanged(WPASupplicant::kInterfaceStateAuthenticating); |
| EXPECT_EQ(WPASupplicant::kInterfaceStateAuthenticating, GetSupplicantState()); |
| ReportStateChanged(WPASupplicant::kInterfaceStateAssociating); |
| EXPECT_EQ(WPASupplicant::kInterfaceStateAssociating, GetSupplicantState()); |
| } |
| |
| TEST_F(WiFiMainTest, RoamStateChange) { |
| // Forward transition should trigger a Service state change. |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| MockWiFiServiceRefPtr service; |
| RpcIdentifier bss_path = MakeNewEndpointAndService(-90, 0, nullptr, &service); |
| InitiateConnect(service); |
| ReportCurrentBSSChanged(bss_path); |
| ReportStateChanged(WPASupplicant::kInterfaceStateCompleted); |
| SetIsRoamingInProgress(true); |
| EXPECT_CALL(*service, SetState(_)).Times(0); |
| EXPECT_EQ(Service::kRoamStateIdle, service->roam_state()); |
| ReportStateChanged(WPASupplicant::kInterfaceStateAuthenticating); |
| EXPECT_EQ(Service::kRoamStateAssociating, service->roam_state()); |
| ReportStateChanged(WPASupplicant::kInterfaceStateAssociating); |
| EXPECT_EQ(Service::kRoamStateAssociating, service->roam_state()); |
| EXPECT_CALL(*service, IsConnected(nullptr)).WillOnce(Return(true)); |
| EXPECT_CALL(*network(), TimeToNextDHCPLeaseRenewal()) |
| .WillOnce(Return(base::Minutes(1))); |
| ReportStateChanged(WPASupplicant::kInterfaceStateCompleted); |
| EXPECT_EQ(Service::kRoamStateConfiguring, service->roam_state()); |
| // Verify expectations now, because WiFi may report other state changes |
| // when WiFi is Stop()-ed (during TearDown()). |
| Mock::VerifyAndClearExpectations(service.get()); |
| } |
| |
| TEST_F(WiFiMainTest, ConnectToServiceWithoutRecentIssues) { |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| EXPECT_CALL(*service, HasRecentConnectionIssues()).WillOnce(Return(false)); |
| InitiateConnect(service); |
| EXPECT_EQ(wifi()->is_debugging_connection_, false); |
| } |
| |
| TEST_F(WiFiMainTest, ConnectToServiceWithRecentIssues) { |
| // Turn of WiFi debugging, so the only reason we will turn on supplicant |
| // debugging will be to debug a problematic connection. |
| ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); |
| |
| MockSupplicantProcessProxy* process_proxy = supplicant_process_proxy_; |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| EXPECT_CALL(*process_proxy, GetDebugLevel(_)) |
| .WillOnce( |
| DoAll(SetArgPointee<0>(std::string(WPASupplicant::kDebugLevelInfo)), |
| Return(true))); |
| EXPECT_CALL(*process_proxy, SetDebugLevel(WPASupplicant::kDebugLevelDebug)) |
| .Times(1); |
| EXPECT_CALL(*service, HasRecentConnectionIssues()).WillOnce(Return(true)); |
| InitiateConnect(service); |
| Mock::VerifyAndClearExpectations(process_proxy); |
| |
| SetPendingService(nullptr); |
| SetCurrentService(service); |
| |
| // When we disconnect from the troubled service, we should reduce the |
| // level of supplicant debugging. |
| EXPECT_CALL(*process_proxy, GetDebugLevel(_)) |
| .WillOnce( |
| DoAll(SetArgPointee<0>(std::string(WPASupplicant::kDebugLevelDebug)), |
| Return(true))); |
| EXPECT_CALL(*process_proxy, SetDebugLevel(WPASupplicant::kDebugLevelInfo)) |
| .Times(1); |
| ReportCurrentBSSChanged(RpcIdentifier(WPASupplicant::kCurrentBSSNull)); |
| } |
| |
| TEST_F(WiFiMainTest, CurrentBSSChangeConnectedToDisconnected) { |
| StartWiFi(); |
| WiFiEndpointRefPtr endpoint; |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), &endpoint, nullptr); |
| |
| ReportCurrentBSSChanged(RpcIdentifier(WPASupplicant::kCurrentBSSNull)); |
| EXPECT_EQ(service->state(), Service::kStateIdle); |
| EXPECT_EQ(nullptr, GetCurrentService()); |
| EXPECT_EQ(nullptr, GetPendingService()); |
| EXPECT_FALSE(GetIsRoamingInProgress()); |
| } |
| |
| TEST_F(WiFiMainTest, BSSIDChangeInvokesNotifyBSSIDChange) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service0 = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| MockWiFiServiceRefPtr service1; |
| RpcIdentifier bss_path1(MakeNewEndpointAndService(0, 0, nullptr, &service1)); |
| EXPECT_EQ(service0, GetCurrentService()); |
| |
| // Ensure call to NotifyBSSIDChanged is called on BSSIDChanged. |
| EXPECT_CALL(*metrics(), NotifyBSSIDChanged()); |
| ReportCurrentBSSChanged(bss_path1); |
| Mock::VerifyAndClearExpectations(service0.get()); |
| Mock::VerifyAndClearExpectations(service1.get()); |
| } |
| |
| TEST_F(WiFiMainTest, RekeyInvokesNotifyRekeyStart) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service0 = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| EXPECT_EQ(service0, GetCurrentService()); |
| EXPECT_CALL(*metrics(), NotifyRekeyStart()); |
| ReportStateChanged(WPASupplicant::kInterfaceState4WayHandshake); |
| Mock::VerifyAndClearExpectations(service0.get()); |
| } |
| |
| TEST_F(WiFiMainTest, |
| UnreliableConnectionInvokesNotifyWiFiConnectionUnreliable) { |
| StartWiFi(); |
| |
| const std::string kGatewayIPAddressString = "192.168.1.1"; |
| const auto kGatewayIPAddress = |
| *net_base::IPAddress::CreateFromString(kGatewayIPAddressString); |
| |
| // Sets up Service. |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| SetCurrentService(service); |
| |
| // Gateway has been found. |
| ON_CALL(*network(), ipv4_gateway_found()).WillByDefault(Return(true)); |
| // Service is unreliable. |
| service->set_unreliable(true); |
| // If gateway is found, service is unreliable, and supplicant is active, |
| // OnLinkMonitorFailure should invoke NotifyWiFiConnectionUnreliable. |
| EXPECT_CALL(*metrics(), NotifyWiFiConnectionUnreliable()); |
| OnLinkMonitorFailure(kGatewayIPAddress.GetFamily()); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| } |
| |
| TEST_F(WiFiMainTest, CurrentBSSChangeConnectedToConnectedNewService) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service0 = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| MockWiFiServiceRefPtr service1; |
| RpcIdentifier bss_path1(MakeNewEndpointAndService(0, 0, nullptr, &service1)); |
| EXPECT_EQ(service0, GetCurrentService()); |
| |
| // Note that we deliberately omit intermediate supplicant states |
| // (e.g. kInterfaceStateAssociating), on the theory that they are |
| // unreliable. Specifically, they may be quashed if the association |
| // completes before supplicant flushes its changed properties. |
| ReportCurrentBSSChanged(bss_path1); |
| EXPECT_EQ(service0->state(), Service::kStateIdle); |
| EXPECT_CALL(*service1, ResetSuspectedCredentialFailures()); |
| ReportStateChanged(WPASupplicant::kInterfaceStateCompleted); |
| EXPECT_EQ(service1->state(), Service::kStateConfiguring); |
| EXPECT_EQ(service1, GetCurrentService()); |
| EXPECT_FALSE(GetIsRoamingInProgress()); |
| } |
| |
| TEST_F(WiFiMainTest, CurrentBSSChangedUpdateServiceEndpoint) { |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| VerifyScanState(WiFiState::PhyState::kScanning, WiFiState::ScanMethod::kFull); |
| |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| WiFiEndpointRefPtr endpoint; |
| RpcIdentifier bss_path = AddEndpointToService(service, 0, 0, &endpoint); |
| EXPECT_CALL(*service, NotifyCurrentEndpoint(EndpointMatch(endpoint))); |
| ReportCurrentBSSChanged(bss_path); |
| EXPECT_TRUE(GetIsRoamingInProgress()); |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| |
| // If we report a "completed" state change on a connected service after |
| // wpa_supplicant has roamed, we should renew our DHCP lease. |
| EXPECT_CALL(*service, IsConnected(nullptr)).WillRepeatedly(Return(true)); |
| EXPECT_CALL(*network(), TimeToNextDHCPLeaseRenewal()) |
| .WillOnce(Return(base::Minutes(1))); |
| EXPECT_CALL(*network(), RenewDHCPLease()); |
| ReportStateChanged(WPASupplicant::kInterfaceStateCompleted); |
| EXPECT_FALSE(GetIsRoamingInProgress()); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectReasonUpdated) { |
| ScopedMockLog log; |
| // Don't error if there are extra logs on top of the ones we're testing for. |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| IEEE_80211::WiFiReasonCode test_reason = IEEE_80211::kReasonCodeInactivity; |
| EXPECT_CALL(*adaptor_, EmitBoolChanged(kPoweredProperty, _)) |
| .Times(AnyNumber()); |
| EXPECT_EQ(GetSupplicantDisconnectReason(), IEEE_80211::kReasonCodeInvalid); |
| EXPECT_CALL( |
| log, |
| Log(logging::LOGGING_INFO, _, |
| EndsWith( |
| " DisconnectReason to 4 (Disassociated due to inactivity)"))); |
| ReportDisconnectReasonChanged(test_reason); |
| EXPECT_EQ(GetSupplicantDisconnectReason(), test_reason); |
| |
| test_reason = IEEE_80211::kReasonCodeReserved0; |
| EXPECT_CALL(log, Log(logging::LOGGING_INFO, _, |
| EndsWith("Reason from 4 to 0 (Success)"))); |
| ReportDisconnectReasonChanged(test_reason); |
| EXPECT_EQ(GetSupplicantDisconnectReason(), test_reason); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectReasonCleared) { |
| IEEE_80211::WiFiReasonCode test_reason = IEEE_80211::kReasonCodeInactivity; |
| // Clearing the value for supplicant_disconnect_reason_ is done prior to any |
| // early exits in the WiFi::StateChanged method. This allows the value to be |
| // checked without a mock pending or current service. |
| ReportDisconnectReasonChanged(test_reason); |
| EXPECT_EQ(wifi().get()->supplicant_disconnect_reason_, test_reason); |
| ReportStateChanged(WPASupplicant::kInterfaceStateDisconnected); |
| ReportStateChanged(WPASupplicant::kInterfaceStateAssociated); |
| EXPECT_EQ(wifi().get()->supplicant_disconnect_reason_, |
| IEEE_80211::kReasonCodeInvalid); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectReasonGenerateWiFiFirmwareDump) { |
| constexpr auto kExpectedDisconnection = |
| base::MakeFixedFlatSet<int32_t>({-IEEE_80211::kReasonCodeSenderHasLeft}); |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| MockFunction<void(std::string)> check; |
| { |
| InSequence s; |
| for (int32_t reason = -IEEE_80211::kReasonCodeMax + 1; |
| reason < IEEE_80211::kReasonCodeMax; reason++) { |
| EXPECT_CALL(*manager(), |
| GenerateFirmwareDumpForTechnology(Technology::kWiFi)) |
| .Times(base::Contains(kExpectedDisconnection, reason) ? 0 : 1); |
| EXPECT_CALL( |
| check, Call("Check point for reason code:" + std::to_string(reason))); |
| } |
| } |
| for (int32_t reason = -IEEE_80211::kReasonCodeMax + 1; |
| reason < IEEE_80211::kReasonCodeMax; reason++) { |
| ReportDisconnectReasonChanged(reason); |
| check.Call("Check point for reason code:" + std::to_string(reason)); |
| } |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectReasonEmitEventOnUserDisconnection) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| int32_t reason = -IEEE_80211::kReasonCodeNonAssociated; |
| // If the disconnection is user-initiated, we report that the disconnection |
| // is expected. |
| Error error; |
| service->UserInitiatedDisconnect("", &error); |
| EXPECT_CALL(*service, EmitDisconnectionEvent( |
| Metrics::kWiFiDisconnectionTypeExpectedUserAction, |
| IEEE_80211::kReasonCodeNonAssociated)); |
| ReportDisconnectReasonChanged(reason); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectReasonEmitEventOnExpectedSTA) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| int32_t reason = -IEEE_80211::kReasonCodeSenderHasLeft; |
| service->set_expecting_disconnect(true); |
| // If supplicant reports a < 0 disconnection reason it means the station |
| // decided to disconnect. If the service was expecting a disconnection, we |
| // report that the disconnection is expected. |
| EXPECT_CALL(*service, EmitDisconnectionEvent( |
| Metrics::kWiFiDisconnectionTypeExpectedUserAction, |
| IEEE_80211::kReasonCodeSenderHasLeft)); |
| ReportDisconnectReasonChanged(reason); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectReasonEmitEventOnSSIDSwitch) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service0 = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| MockWiFiServiceRefPtr service1; |
| RpcIdentifier bss_path1(MakeNewEndpointAndService(0, 0, nullptr, &service1)); |
| int32_t reason = -IEEE_80211::kReasonCodeSenderHasLeft; |
| // When we're already connected to |service0| and we attempt to connect to |
| // another service, we expect |service0| to report that the disconnection was |
| // expected. |
| EXPECT_CALL(*service0, EmitDisconnectionEvent( |
| Metrics::kWiFiDisconnectionTypeExpectedUserAction, |
| IEEE_80211::kReasonCodeSenderHasLeft)); |
| InitiateConnect(service1); |
| ReportDisconnectReasonChanged(reason); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectReasonEmitEventOnUnexpectedSTA) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| int32_t reason = -IEEE_80211::kReasonCodeInactivity; |
| service->set_expecting_disconnect(false); |
| // If supplicant reports a < 0 disconnection reason it means the station |
| // decided to disconnect. If the service wasn't expecting a disconnection, we |
| // report that the disconnection is unexpected. |
| EXPECT_CALL(*service, |
| EmitDisconnectionEvent( |
| Metrics::kWiFiDisconnectionTypeUnexpectedSTADisconnect, |
| IEEE_80211::kReasonCodeInactivity)); |
| ReportDisconnectReasonChanged(reason); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectReasonEmitEventOnUnexpectedAP) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| int32_t reason = IEEE_80211::kReasonCodeInactivity; |
| // If supplicant reports a > 0 disconnection reason it means the AP decided to |
| // disconnect. |
| EXPECT_CALL(*service, |
| EmitDisconnectionEvent( |
| Metrics::kWiFiDisconnectionTypeUnexpectedAPDisconnect, |
| IEEE_80211::kReasonCodeInactivity)); |
| ReportDisconnectReasonChanged(reason); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectReasonEmitEventOnAttemptFailureInAssoc) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectingService(RpcIdentifier(""), nullptr, nullptr); |
| EXPECT_EQ(service, GetPendingService()); |
| EXPECT_EQ(nullptr, GetCurrentService()); |
| // For the failure during a connection attempt, shill should not emit the |
| // disconnection event. During a connection attempt, |pending_service_| could |
| // be valid or set to nullptr, depending on the stage. Association failure |
| // reflects the case when |pending_service_| is still valid. |
| int32_t reason = IEEE_80211::kReasonCodeNonAssociated; |
| EXPECT_CALL(*service, |
| EmitDisconnectionEvent( |
| Metrics::kWiFiDisconnectionTypeUnexpectedAPDisconnect, |
| IEEE_80211::kReasonCodeNonAssociated)) |
| .Times(0); |
| ReportDisconnectReasonChanged(reason); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectReasonEmitEventOnAttemptFailureIn4WayHandshake) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectingService(RpcIdentifier(""), nullptr, nullptr); |
| ReportStateChanged(WPASupplicant::kInterfaceState4WayHandshake); |
| EXPECT_EQ(service, GetPendingService()); |
| EXPECT_EQ(nullptr, GetCurrentService()); |
| // For the failure during a connection attempt, shill should not emit the |
| // disconnection event. During a connection attempt, |pending_service_| could |
| // be valid or set to nullptr, depending on the stage. 4-way handshake timeout |
| // reflects the case when |pending_service_| is set to nullptr. In addition, |
| // some connection failure reason code is shared by both attempt failure and |
| // disconnection, and 4-way handshake timeout is one of the examples. Failure |
| // in a connection attempt accompanied by 4-way handshake timeout reason code |
| // should not trigger a Disconnection event. |
| int32_t reason = IEEE_80211::kReasonCode4WayTimeout; |
| EXPECT_CALL(*service, |
| EmitDisconnectionEvent( |
| Metrics::kWiFiDisconnectionTypeUnexpectedAPDisconnect, |
| IEEE_80211::kReasonCode4WayTimeout)) |
| .Times(0); |
| ReportDisconnectReasonChanged(reason); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectReasonEmitEventOnDisconnectionInRekey) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| ReportStateChanged(WPASupplicant::kInterfaceState4WayHandshake); |
| EXPECT_EQ(nullptr, GetPendingService()); |
| // Some connection failure reason code is shared by both attempt failure and |
| // disconnection, and 4-way handshake timeout is one of the examples. Failure |
| // during rekey process accompanied by 4-way handshake timeout reason code |
| // should trigger a Disconnection event. |
| int32_t reason = IEEE_80211::kReasonCode4WayTimeout; |
| EXPECT_CALL(*service, |
| EmitDisconnectionEvent( |
| Metrics::kWiFiDisconnectionTypeUnexpectedAPDisconnect, |
| IEEE_80211::kReasonCode4WayTimeout)) |
| .Times(1); |
| ReportDisconnectReasonChanged(reason); |
| } |
| |
| TEST_F(WiFiMainTest, GetSuffixFromAuthMode) { |
| EXPECT_EQ("PSK", wifi()->GetSuffixFromAuthMode("WPA-PSK")); |
| EXPECT_EQ("PSK", wifi()->GetSuffixFromAuthMode("WPA2-PSK")); |
| EXPECT_EQ("PSK", wifi()->GetSuffixFromAuthMode("WPA2-PSK+WPA-PSK")); |
| EXPECT_EQ("FTPSK", wifi()->GetSuffixFromAuthMode("FT-PSK")); |
| EXPECT_EQ("FTEAP", wifi()->GetSuffixFromAuthMode("FT-EAP")); |
| EXPECT_EQ("EAP", wifi()->GetSuffixFromAuthMode("EAP-TLS")); |
| EXPECT_EQ("", wifi()->GetSuffixFromAuthMode("INVALID-PSK")); |
| } |
| |
| TEST_F(WiFiMainTest, CurrentAuthModeChanged) { |
| const std::string auth_mode0 = "FT-PSK"; |
| ReportCurrentAuthModeChanged(auth_mode0); |
| EXPECT_EQ(wifi().get()->supplicant_auth_mode_, auth_mode0); |
| |
| const std::string auth_mode1 = "EAP-TLS"; |
| ReportCurrentAuthModeChanged(auth_mode1); |
| EXPECT_EQ(wifi().get()->supplicant_auth_mode_, auth_mode1); |
| } |
| |
| TEST_F(WiFiMainTest, NewConnectPreemptsPending) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service0( |
| SetupConnectingService(RpcIdentifier(""), nullptr, nullptr)); |
| EXPECT_EQ(service0, GetPendingService()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()); |
| MockWiFiServiceRefPtr service1( |
| SetupConnectingService(RpcIdentifier(""), nullptr, nullptr)); |
| EXPECT_EQ(service1, GetPendingService()); |
| EXPECT_EQ(nullptr, GetCurrentService()); |
| } |
| |
| TEST_F(WiFiMainTest, ConnectedToUnintendedPreemptsPending) { |
| StartWiFi(); |
| RpcIdentifier bss_path; |
| // Connecting two different services back-to-back. |
| MockWiFiServiceRefPtr unintended_service( |
| SetupConnectingService(RpcIdentifier(""), nullptr, &bss_path)); |
| MockWiFiServiceRefPtr intended_service( |
| SetupConnectingService(RpcIdentifier(""), nullptr, nullptr)); |
| |
| // Verify the pending service. |
| EXPECT_EQ(intended_service, GetPendingService()); |
| |
| // Connected to the unintended service (service0). |
| ReportCurrentBSSChanged(bss_path); |
| |
| // Expect the pending service to go back to idle, so it is connectable again. |
| EXPECT_EQ(intended_service->state(), Service::kStateIdle); |
| // Verify the pending service is disconnected |
| EXPECT_EQ(nullptr, GetPendingService()); |
| EXPECT_EQ(nullptr, GetCurrentService()); |
| } |
| |
| TEST_F(WiFiMainTest, IsIdle) { |
| StartWiFi(); |
| EXPECT_TRUE(wifi()->IsIdle()); |
| MockWiFiServiceRefPtr service( |
| SetupConnectingService(RpcIdentifier(""), nullptr, nullptr)); |
| EXPECT_FALSE(wifi()->IsIdle()); |
| } |
| |
| MATCHER_P(WiFiAddedArgs, bgscan, "") { |
| return arg.template Contains<uint32_t>( |
| WPASupplicant::kNetworkPropertyScanSSID) && |
| arg.template Contains<uint32_t>( |
| WPASupplicant::kNetworkPropertyDisableVHT) && |
| arg.template Contains<std::string>( |
| WPASupplicant::kNetworkPropertyBgscan) && |
| arg.template Get<std::string>(WPASupplicant::kNetworkPropertyBgscan) |
| .empty() != bgscan; |
| } |
| |
| TEST_F(WiFiMainTest, AddNetworkArgs) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service; |
| MakeNewEndpointAndService(0, 0, nullptr, &service); |
| EXPECT_CALL(*service, GetSupplicantConfigurationParameters()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), |
| AddNetwork(WiFiAddedArgs(true), _)); |
| EXPECT_TRUE(SetBgscanMethod(WPASupplicant::kNetworkBgscanMethodSimple)); |
| InitiateConnect(service); |
| } |
| |
| TEST_F(WiFiMainTest, AddNetworkArgsNoBgscan) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service; |
| MakeNewEndpointAndService(0, 0, nullptr, &service); |
| EXPECT_CALL(*service, GetSupplicantConfigurationParameters()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), |
| AddNetwork(WiFiAddedArgs(false), _)); |
| EXPECT_TRUE(SetBgscanMethod(WPASupplicant::kNetworkBgscanMethodNone)); |
| InitiateConnect(service); |
| } |
| |
| TEST_F(WiFiMainTest, AppendBgscan) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| { |
| // 1 endpoint, default bgscan method -- background scan frequency very |
| // reduced. |
| KeyValueStore params; |
| EXPECT_CALL(*service, GetBSSIDConnectableEndpointCount()) |
| .WillOnce(Return(1)); |
| AppendBgscan(service.get(), ¶ms); |
| Mock::VerifyAndClearExpectations(service.get()); |
| std::string config_string; |
| EXPECT_TRUE( |
| params.Contains<std::string>(WPASupplicant::kNetworkPropertyBgscan)); |
| config_string = |
| params.Get<std::string>(WPASupplicant::kNetworkPropertyBgscan); |
| std::vector<std::string> elements = base::SplitString( |
| config_string, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
| EXPECT_EQ(WiFi::kDefaultBgscanMethod, elements[0]); |
| EXPECT_EQ( |
| base::StringPrintf("%d", WiFi::kSingleEndpointBgscanIntervalSeconds), |
| elements[3]); |
| } |
| { |
| // 2 endpoints, default bgscan method -- background scan frequency reduced. |
| KeyValueStore params; |
| EXPECT_CALL(*service, GetBSSIDConnectableEndpointCount()) |
| .WillOnce(Return(2)); |
| AppendBgscan(service.get(), ¶ms); |
| Mock::VerifyAndClearExpectations(service.get()); |
| std::string config_string; |
| EXPECT_TRUE( |
| params.Contains<std::string>(WPASupplicant::kNetworkPropertyBgscan)); |
| config_string = |
| params.Get<std::string>(WPASupplicant::kNetworkPropertyBgscan); |
| std::vector<std::string> elements = base::SplitString( |
| config_string, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
| ASSERT_EQ(4, elements.size()); |
| EXPECT_EQ(WiFi::kDefaultBgscanMethod, elements[0]); |
| EXPECT_EQ(base::StringPrintf("%d", WiFi::kBackgroundScanIntervalSeconds), |
| elements[3]); |
| } |
| { |
| // Explicit bgscan method -- regular background scan frequency. |
| EXPECT_TRUE(SetBgscanMethod(WPASupplicant::kNetworkBgscanMethodSimple)); |
| KeyValueStore params; |
| EXPECT_CALL(*service, GetBSSIDConnectableEndpointCount()).Times(0); |
| AppendBgscan(service.get(), ¶ms); |
| Mock::VerifyAndClearExpectations(service.get()); |
| EXPECT_TRUE( |
| params.Contains<std::string>(WPASupplicant::kNetworkPropertyBgscan)); |
| std::string config_string = |
| params.Get<std::string>(WPASupplicant::kNetworkPropertyBgscan); |
| std::vector<std::string> elements = base::SplitString( |
| config_string, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
| ASSERT_EQ(4, elements.size()); |
| EXPECT_EQ(base::StringPrintf("%d", WiFi::kDefaultScanIntervalSeconds), |
| elements[3]); |
| } |
| { |
| // No scan method, simply returns without appending properties |
| EXPECT_TRUE(SetBgscanMethod(WPASupplicant::kNetworkBgscanMethodNone)); |
| KeyValueStore params; |
| EXPECT_CALL(*service, GetBSSIDConnectableEndpointCount()).Times(0); |
| AppendBgscan(service.get(), ¶ms); |
| Mock::VerifyAndClearExpectations(service.get()); |
| std::string config_string; |
| EXPECT_TRUE( |
| params.Contains<std::string>(WPASupplicant::kNetworkPropertyBgscan)); |
| EXPECT_TRUE( |
| params.Get<std::string>(WPASupplicant::kNetworkPropertyBgscan).empty()); |
| } |
| } |
| |
| TEST_F(WiFiMainTest, StateAndIPIgnoreLinkEvent) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service( |
| SetupConnectingService(RpcIdentifier(""), nullptr, nullptr)); |
| EXPECT_CALL(*service, SetState(_)).Times(0); |
| ReportLinkUp(); |
| |
| // Verify expectations now, because WiFi may cause |service| state |
| // changes during TearDown(). |
| Mock::VerifyAndClearExpectations(service.get()); |
| } |
| |
| TEST_F(WiFiMainTest, SupplicantCompletedAlreadyConnected) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service( |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr)); |
| // Simulate a rekeying event from the AP. These show as transitions from |
| // completed->completed from wpa_supplicant. |
| ReportStateChanged(WPASupplicant::kInterfaceStateCompleted); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| ReportGetDHCPLease(); |
| // Similarly, rekeying events after we have an IP don't trigger L3 |
| // configuration. However, we treat all transitions to completed as potential |
| // reassociations, so we will reenable high rates again here. |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| EXPECT_CALL(*service, IsConnected(nullptr)).WillRepeatedly(Return(true)); |
| ReportStateChanged(WPASupplicant::kInterfaceStateCompleted); |
| } |
| |
| TEST_F(WiFiMainTest, BSSAddedCreatesBSSProxy) { |
| // TODO(quiche): Consider using a factory for WiFiEndpoints, so that |
| // we can test the interaction between WiFi and WiFiEndpoint. (Right |
| // now, we're testing across multiple layers.) |
| EXPECT_CALL(*supplicant_bss_proxy_, Die()).Times(AnyNumber()); |
| EXPECT_CALL(*control_interface(), CreateSupplicantBSSProxy(_, _)); |
| StartWiFi(); |
| ReportBSS(RpcIdentifier("bss0"), "ssid0", |
| net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 0, 0, |
| kNetworkModeInfrastructure, 0); |
| } |
| |
| TEST_F(WiFiMainTest, BSSRemovedDestroysBSSProxy) { |
| // TODO(quiche): As for BSSAddedCreatesBSSProxy, consider using a |
| // factory for WiFiEndpoints. |
| // Get the pointer before we transfer ownership. |
| MockSupplicantBSSProxy* proxy = supplicant_bss_proxy_.get(); |
| EXPECT_CALL(*proxy, Die()); |
| StartWiFi(); |
| RpcIdentifier bss_path(MakeNewEndpointAndService(0, 0, nullptr, nullptr)); |
| EXPECT_CALL(*wifi_provider(), OnEndpointRemoved(_)).WillOnce(Return(nullptr)); |
| RemoveBSS(bss_path); |
| // Check this now, to make sure RemoveBSS killed the proxy (rather |
| // than TearDown). |
| Mock::VerifyAndClearExpectations(proxy); |
| } |
| |
| TEST_F(WiFiMainTest, FlushBSSOnResume) { |
| const struct timeval resume_time = {1, 0}; |
| const struct timeval scan_done_time = {6, 0}; |
| |
| StartWiFi(); |
| |
| EXPECT_CALL(time_, GetTimeMonotonic(_)) |
| .WillOnce(DoAll(SetArgPointee<0>(resume_time), Return(0))) |
| .WillOnce(DoAll(SetArgPointee<0>(scan_done_time), Return(0))); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), |
| FlushBSS(WiFi::kMaxBSSResumeAgeSeconds + 5)); |
| OnAfterResume(); |
| ReportScanDone(); |
| } |
| |
| TEST_F(WiFiMainTest, CallWakeOnWiFi_OnScanDone) { |
| StartWiFi(); |
| |
| // Call WakeOnWiFi::OnNoAutoConnectableServicesAfterScan if we find 0 auto- |
| // connectable services. |
| EXPECT_CALL(*wifi_provider(), NumAutoConnectableServices()) |
| .WillOnce(Return(0)); |
| EXPECT_TRUE(wifi()->IsIdle()); |
| EXPECT_CALL(*wake_on_wifi_, OnNoAutoConnectableServicesAfterScan(_, _, _)); |
| ReportScanDone(); |
| |
| // If we have 1 or more auto-connectable services, do not call |
| // WakeOnWiFi::OnNoAutoConnectableServicesAfterScan. |
| EXPECT_CALL(*wifi_provider(), NumAutoConnectableServices()) |
| .WillOnce(Return(1)); |
| EXPECT_TRUE(wifi()->IsIdle()); |
| EXPECT_CALL(*wake_on_wifi_, OnNoAutoConnectableServicesAfterScan(_, _, _)) |
| .Times(0); |
| ReportScanDone(); |
| |
| // If the WiFi device is not Idle, do not call |
| // WakeOnWiFi::OnNoAutoConnectableServicesAfterScan. |
| SetCurrentService(MakeMockService(WiFiSecurity::kWep)); |
| EXPECT_FALSE(wifi()->IsIdle()); |
| EXPECT_CALL(*wifi_provider(), NumAutoConnectableServices()) |
| .WillOnce(Return(0)); |
| EXPECT_CALL(*wake_on_wifi_, OnNoAutoConnectableServicesAfterScan(_, _, _)) |
| .Times(0); |
| ReportScanDone(); |
| } |
| |
| TEST_F(WiFiMainTest, ScanTimerIdle) { |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| ReportScanDone(); |
| CancelScanTimer(); |
| EXPECT_TRUE(GetScanTimer().IsCancelled()); |
| |
| EXPECT_CALL(*manager(), OnDeviceGeolocationInfoUpdated(_)); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)); |
| FireScanTimer(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| EXPECT_FALSE(GetScanTimer().IsCancelled()); // Automatically re-armed. |
| } |
| |
| TEST_F(WiFiMainTest, ScanTimerScanning) { |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| CancelScanTimer(); |
| EXPECT_TRUE(GetScanTimer().IsCancelled()); |
| |
| // Should not call Scan, since we're already scanning. |
| // (Scanning is triggered by StartWiFi.) |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)).Times(0); |
| FireScanTimer(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| EXPECT_FALSE(GetScanTimer().IsCancelled()); // Automatically re-armed. |
| } |
| |
| TEST_F(WiFiMainTest, ScanTimerConnecting) { |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectingService(RpcIdentifier(""), nullptr, nullptr); |
| CancelScanTimer(); |
| EXPECT_TRUE(GetScanTimer().IsCancelled()); |
| |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)).Times(0); |
| FireScanTimer(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| EXPECT_FALSE(GetScanTimer().IsCancelled()); // Automatically re-armed. |
| } |
| |
| TEST_F(WiFiMainTest, ScanTimerSuspending) { |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| ReportScanDone(); |
| CancelScanTimer(); |
| EXPECT_TRUE(GetScanTimer().IsCancelled()); |
| |
| EXPECT_CALL(*manager(), OnDeviceGeolocationInfoUpdated(_)); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| EXPECT_CALL(*manager(), IsSuspending()).WillOnce(Return(true)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)).Times(0); |
| FireScanTimer(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| EXPECT_TRUE(GetScanTimer().IsCancelled()); // Do not re-arm. |
| } |
| |
| TEST_F(WiFiMainTest, ScanTimerReconfigured) { |
| StartWiFi(); |
| CancelScanTimer(); |
| EXPECT_TRUE(GetScanTimer().IsCancelled()); |
| |
| SetScanInterval(1, nullptr); |
| EXPECT_FALSE(GetScanTimer().IsCancelled()); |
| } |
| |
| TEST_F(WiFiMainTest, ScanTimerResetOnScanDone) { |
| StartWiFi(); |
| CancelScanTimer(); |
| EXPECT_TRUE(GetScanTimer().IsCancelled()); |
| |
| ReportScanDone(); |
| EXPECT_FALSE(GetScanTimer().IsCancelled()); |
| } |
| |
| TEST_F(WiFiMainTest, ScanTimerStopOnZeroInterval) { |
| StartWiFi(); |
| EXPECT_FALSE(GetScanTimer().IsCancelled()); |
| |
| SetScanInterval(0, nullptr); |
| EXPECT_TRUE(GetScanTimer().IsCancelled()); |
| } |
| |
| TEST_F(WiFiMainTest, ScanOnDisconnect) { |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| ExpectScanIdle(); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)); |
| EXPECT_CALL(*wifi_provider(), GetHiddenSSIDList()) |
| .WillRepeatedly(Return(ByteArrays())); |
| ReportCurrentBSSChanged(RpcIdentifier(WPASupplicant::kCurrentBSSNull)); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| TEST_F(WiFiMainTest, LinkMonitorFailure) { |
| ScopedMockLog log; |
| StartWiFi(); |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| |
| using Role = patchpanel::Client::NeighborRole; |
| using Status = patchpanel::Client::NeighborStatus; |
| |
| const std::string kGatewayIPAddressString = "192.168.1.1"; |
| const auto kGatewayIPAddress = |
| *net_base::IPAddress::CreateFromString(kGatewayIPAddressString); |
| |
| // Sets up Service. |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| SetCurrentService(service); |
| // Can be used to clear link status (last failure time, etc.), so that the |
| // following tests will not be affected by service->unreliable(). |
| auto reset_service = [&]() { |
| SelectService(nullptr); |
| SelectService(service); |
| }; |
| reset_service(); |
| |
| // We haven't heard the gateway is reachable, so we assume the problem is |
| // gateway, rather than link. |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Reattach()).Times(0); |
| OnNeighborReachabilityEvent(kGatewayIPAddress, Role::kGateway, |
| Status::kFailed); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| |
| // Gateway has been discovered now. |
| ON_CALL(*network(), ipv4_gateway_found()).WillByDefault(Return(true)); |
| |
| // No supplicant, so we can't Reattach. |
| reset_service(); |
| OnSupplicantVanish(); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Reattach()).Times(0); |
| OnNeighborReachabilityEvent(kGatewayIPAddress, Role::kGateway, |
| Status::kFailed); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| |
| // Normal case: call Reattach. |
| reset_service(); |
| OnSupplicantAppear(); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Reattach()) |
| .WillOnce(Return(true)); |
| OnNeighborReachabilityEvent(kGatewayIPAddress, Role::kGateway, |
| Status::kFailed); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| |
| // Service is unreliable, skip reassociate attempt. |
| reset_service(); |
| service->set_unreliable(true); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Reattach()).Times(0); |
| OnNeighborReachabilityEvent(kGatewayIPAddress, Role::kGateway, |
| Status::kFailed); |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| } |
| |
| TEST_F(WiFiMainTest, LinkStatusOnLinkMonitorFailure) { |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| SelectService(service); |
| |
| // To make the call lines shorter. |
| using Role = patchpanel::Client::NeighborRole; |
| using Status = patchpanel::Client::NeighborStatus; |
| |
| // Make the object ready to respond to link monitor failures. |
| const auto kGatewayIPAddress = |
| *net_base::IPAddress::CreateFromString("192.168.0.1"); |
| OnNeighborReachabilityEvent(kGatewayIPAddress, Role::kGateway, |
| Status::kReachable); |
| |
| time_t current_time = 1000; |
| EXPECT_CALL(time_, GetSecondsBoottime(_)) |
| .WillRepeatedly([&](time_t* seconds) { |
| *seconds = current_time; |
| return true; |
| }); |
| |
| // Initial link monitor failure. |
| EXPECT_CALL(*metrics(), |
| SendToUMA(Metrics::kMetricUnreliableLinkSignalStrength, _)) |
| .Times(0); |
| OnNeighborReachabilityEvent(kGatewayIPAddress, Role::kGateway, |
| Status::kFailed); |
| EXPECT_FALSE(service->unreliable()); |
| |
| // Another link monitor failure after 3 minutes, report signal strength. |
| current_time += 180; |
| EXPECT_CALL(*metrics(), |
| SendToUMA(Metrics::kMetricUnreliableLinkSignalStrength, _)) |
| .Times(1); |
| OnNeighborReachabilityEvent(kGatewayIPAddress, Role::kGateway, |
| Status::kFailed); |
| EXPECT_TRUE(service->unreliable()); |
| |
| // Device is connected with the reliable link callback setup, then |
| // another link monitor failure after 3 minutes, which implies link is |
| // still unreliable, reliable link callback should be cancelled. |
| current_time += 180; |
| SetReliableLinkCallback(); |
| EXPECT_CALL(*metrics(), |
| SendToUMA(Metrics::kMetricUnreliableLinkSignalStrength, _)) |
| .Times(1); |
| OnNeighborReachabilityEvent(kGatewayIPAddress, Role::kGateway, |
| Status::kFailed); |
| EXPECT_TRUE(service->unreliable()); |
| EXPECT_TRUE(ReliableLinkCallbackIsCancelled()); |
| |
| // Another link monitor failure after an hour, link is still reliable, signal |
| // strength not reported. |
| current_time += 3600; |
| service->set_unreliable(false); |
| EXPECT_CALL(*metrics(), |
| SendToUMA(Metrics::kMetricUnreliableLinkSignalStrength, _)) |
| .Times(0); |
| OnNeighborReachabilityEvent(kGatewayIPAddress, Role::kGateway, |
| Status::kFailed); |
| EXPECT_FALSE(service->unreliable()); |
| } |
| |
| TEST_F(WiFiMainTest, LinkStatusResetOnSelectService) { |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| SelectService(service); |
| service->set_unreliable(true); |
| SetReliableLinkCallback(); |
| EXPECT_FALSE(ReliableLinkCallbackIsCancelled()); |
| |
| // Service is deselected, link status of the service should be reset. |
| ReportSelectedServiceChanged(service); |
| EXPECT_FALSE(service->unreliable()); |
| EXPECT_TRUE(ReliableLinkCallbackIsCancelled()); |
| } |
| |
| TEST_F(WiFiMainTest, LinkStatusOnConnected) { |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| SelectService(service); |
| |
| // Link is reliable, no need to post delayed task to reset link status. |
| ReportConnected(); |
| EXPECT_TRUE(ReliableLinkCallbackIsCancelled()); |
| |
| // Link is unreliable when connected, delayed task is posted to reset the |
| // link state. |
| service->set_unreliable(true); |
| ReportConnected(); |
| EXPECT_FALSE(ReliableLinkCallbackIsCancelled()); |
| } |
| |
| TEST_F(WiFiMainTest, ResumeWithUnreliableLink) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| SelectService(service); |
| service->set_unreliable(true); |
| SetReliableLinkCallback(); |
| |
| // Link status should be reset upon resume. |
| OnAfterResume(); |
| EXPECT_FALSE(service->unreliable()); |
| EXPECT_TRUE(ReliableLinkCallbackIsCancelled()); |
| } |
| |
| TEST_F(WiFiMainTest, PskMismatchSignalOnReceive) { |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kWpa2); |
| SetPendingService(service); |
| EXPECT_CALL(*service, AddSuspectedCredentialFailure()).Times(1); |
| ReportPskMismatch(); |
| } |
| |
| TEST_F(WiFiMainTest, SuspectCredentialsOpen) { |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| EXPECT_CALL(*service, AddAndCheckSuspectedCredentialFailure()).Times(0); |
| EXPECT_FALSE(SuspectCredentials(service, nullptr)); |
| } |
| |
| TEST_F(WiFiMainTest, SuspectCredentialsWPA) { |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kWpa2); |
| SetPendingService(service); |
| ReportStateChanged(WPASupplicant::kInterfaceState4WayHandshake); |
| ReportPskMismatch(); |
| EXPECT_CALL(*service, CheckSuspectedCredentialFailure()) |
| .WillOnce(Return(false)) |
| .WillOnce(Return(true)); |
| EXPECT_FALSE(SuspectCredentials(service, nullptr)); |
| Service::ConnectFailure failure; |
| EXPECT_TRUE(SuspectCredentials(service, &failure)); |
| EXPECT_EQ(Service::kFailureBadPassphrase, failure); |
| } |
| |
| TEST_F(WiFiMainTest, SuspectCredentialsWEP) { |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kWep); |
| RpcIdentifier bss_path = AddEndpointToService(service, -90, 0, nullptr); |
| |
| SetWEPSupport(true); |
| ExpectConnecting(); |
| InitiateConnect(service); |
| ReportCurrentBSSChanged(bss_path); |
| SetCurrentService(service); |
| |
| // These expectations are very much like SetupConnectedService except |
| // that we verify that ResetSupsectCredentialFailures() is not called |
| // on the service just because supplicant entered the Completed state. |
| EXPECT_CALL(*service, ResetSuspectedCredentialFailures()).Times(0); |
| EXPECT_CALL(*device_info(), GetByteCounts(_, _, _)) |
| .WillOnce(DoAll(SetArgPointee<2>(0LL), Return(true))); |
| ReportStateChanged(WPASupplicant::kInterfaceStateCompleted); |
| EXPECT_EQ(service->state(), Service::kStateConfiguring); |
| |
| Mock::VerifyAndClearExpectations(device_info()); |
| Mock::VerifyAndClearExpectations(service.get()); |
| |
| // Successful connect. |
| EXPECT_CALL(*service, ResetSuspectedCredentialFailures()); |
| ReportConnected(); |
| |
| EXPECT_CALL(*device_info(), GetByteCounts(_, _, _)) |
| .WillOnce(DoAll(SetArgPointee<2>(1LL), Return(true))) |
| .WillOnce(DoAll(SetArgPointee<2>(0LL), Return(true))) |
| .WillOnce(DoAll(SetArgPointee<2>(0LL), Return(true))); |
| |
| // If there was an increased byte-count while we were timing out DHCP, |
| // this should be considered a DHCP failure and not a credential failure. |
| EXPECT_CALL(*service, ResetSuspectedCredentialFailures()).Times(0); |
| EXPECT_CALL(*service, DisconnectWithFailure(Service::kFailureDHCP, _, |
| HasSubstr("OnIPConfigFailure"))); |
| ReportIPConfigFailure(); |
| Mock::VerifyAndClearExpectations(service.get()); |
| |
| // Connection failed during DHCP but service does not (yet) believe this is |
| // due to a passphrase issue. |
| EXPECT_CALL(*service, AddAndCheckSuspectedCredentialFailure()) |
| .WillOnce(Return(false)); |
| EXPECT_CALL(*service, DisconnectWithFailure(Service::kFailureDHCP, _, |
| HasSubstr("OnIPConfigFailure"))); |
| ReportIPConfigFailure(); |
| Mock::VerifyAndClearExpectations(service.get()); |
| |
| // Connection failed during DHCP and service believes this is due to a |
| // passphrase issue. |
| EXPECT_CALL(*service, AddAndCheckSuspectedCredentialFailure()) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*service, DisconnectWithFailure(Service::kFailureBadPassphrase, _, |
| HasSubstr("OnIPConfigFailure"))); |
| ReportIPConfigFailure(); |
| } |
| |
| TEST_F(WiFiMainTest, SuspectCredentialsEAPInProgress) { |
| MockWiFiServiceRefPtr service = |
| MakeMockService(WiFiSecurity::kWpa2Enterprise); |
| EXPECT_CALL(*eap_state_handler_, is_eap_in_progress()) |
| .WillOnce(Return(false)) |
| .WillOnce(Return(true)) |
| .WillOnce(Return(false)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*service, AddAndCheckSuspectedCredentialFailure()).Times(0); |
| EXPECT_FALSE(SuspectCredentials(service, nullptr)); |
| Mock::VerifyAndClearExpectations(service.get()); |
| |
| EXPECT_CALL(*service, AddAndCheckSuspectedCredentialFailure()) |
| .WillOnce(Return(true)); |
| Service::ConnectFailure failure; |
| EXPECT_TRUE(SuspectCredentials(service, &failure)); |
| EXPECT_EQ(Service::kFailureEAPAuthentication, failure); |
| Mock::VerifyAndClearExpectations(service.get()); |
| |
| EXPECT_CALL(*service, AddAndCheckSuspectedCredentialFailure()).Times(0); |
| EXPECT_FALSE(SuspectCredentials(service, nullptr)); |
| Mock::VerifyAndClearExpectations(service.get()); |
| |
| EXPECT_CALL(*service, AddAndCheckSuspectedCredentialFailure()) |
| .WillOnce(Return(false)); |
| EXPECT_FALSE(SuspectCredentials(service, nullptr)); |
| } |
| |
| TEST_F(WiFiMainTest, SuspectCredentialsYieldFailurePSK) { |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kWpa2); |
| SetPendingService(service); |
| ReportStateChanged(WPASupplicant::kInterfaceState4WayHandshake); |
| ReportPskMismatch(); |
| |
| ExpectScanIdle(); |
| EXPECT_CALL(*service, CheckSuspectedCredentialFailure()) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*service, SetFailure(Service::kFailureBadPassphrase)); |
| ScopedMockLog log; |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| EXPECT_CALL(log, |
| Log(logging::LOGGING_ERROR, _, EndsWith(kErrorBadPassphrase))); |
| ReportCurrentBSSChanged(RpcIdentifier(WPASupplicant::kCurrentBSSNull)); |
| EXPECT_EQ(service->state(), Service::kStateIdle); |
| } |
| |
| TEST_F(WiFiMainTest, SuspectCredentialsYieldFailureEAP) { |
| MockWiFiServiceRefPtr service = |
| MakeMockService(WiFiSecurity::kWpa2Enterprise); |
| SetCurrentService(service); |
| |
| ScopedMockLog log; |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| // Ensure that we retrieve is_eap_in_progress() before resetting the |
| // EAP handler's state. |
| InSequence seq; |
| EXPECT_CALL(*eap_state_handler_, is_eap_in_progress()).WillOnce(Return(true)); |
| EXPECT_CALL(*service, AddAndCheckSuspectedCredentialFailure()) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*service, SetFailure(Service::kFailureEAPAuthentication)); |
| EXPECT_CALL(log, Log(logging::LOGGING_ERROR, _, |
| EndsWith(kErrorEapAuthenticationFailed))); |
| EXPECT_CALL(*eap_state_handler_, Reset()); |
| ReportCurrentBSSChanged(RpcIdentifier(WPASupplicant::kCurrentBSSNull)); |
| EXPECT_EQ(service->state(), Service::kStateIdle); |
| } |
| |
| TEST_F(WiFiMainTest, ReportConnectedToServiceAfterWake_CallsWakeOnWiFi) { |
| EXPECT_CALL(*wake_on_wifi_, ReportConnectedToServiceAfterWake( |
| IsConnectedToCurrentService(), _)); |
| ReportConnectedToServiceAfterWake(); |
| } |
| |
| // Scanning tests will use a mock of the event dispatcher instead of a real |
| // one. |
| class WiFiTimerTest : public WiFiObjectTest { |
| public: |
| WiFiTimerTest() |
| : WiFiObjectTest(std::make_unique<StrictMock<MockEventDispatcher>>()), |
| mock_dispatcher_(static_cast<StrictMock<MockEventDispatcher>*>( |
| event_dispatcher_.get())) {} |
| |
| void TearDown() override { |
| Mock::VerifyAndClearExpectations(&*mock_dispatcher_); |
| |
| // Loose the expectation on EventDispatcher to allow it being used in |
| // cleanup. |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, _)).Times(AnyNumber()); |
| WiFiObjectTest::TearDown(); |
| } |
| |
| protected: |
| void ExpectInitialScanSequence(); |
| |
| StrictMock<MockEventDispatcher>* mock_dispatcher_; |
| }; |
| |
| void WiFiTimerTest::ExpectInitialScanSequence() { |
| // Choose a number of iterations some multiple higher than the fast scan |
| // count. |
| const int kScanTimes = WiFi::kNumFastScanAttempts * 4; |
| |
| // Each time we call FireScanTimer() below, WiFi will post a task to actually |
| // run Scan() on the wpa_supplicant proxy. |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, base::TimeDelta())) |
| .Times(kScanTimes); |
| { |
| InSequence seq; |
| // The scans immediately after the initial scan should happen at the short |
| // interval. If we add the initial scan (not invoked in this function) to |
| // the ones in the expectation below, we get WiFi::kNumFastScanAttempts at |
| // the fast scan interval. |
| EXPECT_CALL(*mock_dispatcher_, |
| PostDelayedTask(_, _, WiFi::kFastScanInterval)) |
| .Times(WiFi::kNumFastScanAttempts - 1); |
| |
| // After this, the WiFi device should use the normal scan interval. |
| EXPECT_CALL(*mock_dispatcher_, |
| PostDelayedTask(_, _, base::Seconds(GetScanInterval()))) |
| .Times(kScanTimes - WiFi::kNumFastScanAttempts + 1); |
| |
| for (int i = 0; i < kScanTimes; i++) { |
| FireScanTimer(); |
| } |
| } |
| } |
| |
| TEST_F(WiFiTimerTest, FastRescan) { |
| // This is to cover calls to PostDelayedTask by WakeOnWiFi::StartMetricsTimer. |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, _)).Times(AnyNumber()); |
| // This PostTask is a result of the call to Scan(nullptr), and is meant to |
| // post a task to call Scan() on the wpa_supplicant proxy immediately. |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, base::TimeDelta())); |
| EXPECT_CALL(*mock_dispatcher_, |
| PostDelayedTask(_, _, WiFi::kFastScanInterval)); |
| StartWiFi(); |
| |
| ExpectInitialScanSequence(); |
| |
| // If we end up disconnecting, the sequence should repeat. |
| EXPECT_CALL(*mock_dispatcher_, |
| PostDelayedTask(_, _, WiFi::kFastScanInterval)); |
| RestartFastScanAttempts(); |
| |
| ExpectInitialScanSequence(); |
| } |
| |
| TEST_F(WiFiTimerTest, FastScanBSSLost) { |
| // Test for RestartFastScanAttempts() is called when current and pending |
| // services are set to nullptr which is an edge case that happens sometimes |
| // when the device disconnects due to BSS is lost. |
| |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, base::TimeDelta())) |
| .Times(AnyNumber()); |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, _)).Times(AnyNumber()); |
| |
| StartWiFi(); |
| |
| SetPendingService(nullptr); |
| SetCurrentService(nullptr); |
| |
| // This PostTask is a result of the call to Scan(nullptr), and is meant to |
| // post a task to call Scan() on the wpa_supplicant proxy immediately. |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, base::TimeDelta())); |
| |
| // This PostTask is a result of the call to RestartFastScanAttempts(), and |
| // is meant to post a task to call Scan() on the wpa_supplicant proxy with |
| // short delay. |
| EXPECT_CALL(*mock_dispatcher_, |
| PostDelayedTask(_, _, WiFi::kFastScanInterval)); |
| |
| ReportCurrentBSSChanged(RpcIdentifier(WPASupplicant::kCurrentBSSNull)); |
| } |
| |
| TEST_F(WiFiTimerTest, ReconnectTimer) { |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, base::TimeDelta())) |
| .Times(AnyNumber()); |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, _)).Times(AnyNumber()); |
| StartWiFi(); |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| Mock::VerifyAndClearExpectations(&*mock_dispatcher_); |
| |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, GetReconnectTimeout())) |
| .Times(1); |
| StartReconnectTimer(); |
| Mock::VerifyAndClearExpectations(&*mock_dispatcher_); |
| StopReconnectTimer(); |
| |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, GetReconnectTimeout())) |
| .Times(1); |
| StartReconnectTimer(); |
| Mock::VerifyAndClearExpectations(&*mock_dispatcher_); |
| GetReconnectTimeoutCallback().callback().Run(); |
| |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, GetReconnectTimeout())) |
| .Times(1); |
| StartReconnectTimer(); |
| Mock::VerifyAndClearExpectations(&*mock_dispatcher_); |
| |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, GetReconnectTimeout())) |
| .Times(0); |
| StartReconnectTimer(); |
| } |
| |
| TEST_F(WiFiTimerTest, RequestStationInfo) { |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, base::TimeDelta())) |
| .Times(AnyNumber()); |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, _)).Times(AnyNumber()); |
| |
| // Setup a connected service here while we have the expectations above set. |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| RpcIdentifier connected_bss = GetSupplicantBSS(); |
| Mock::VerifyAndClearExpectations(&*mock_dispatcher_); |
| |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, _)).Times(0); |
| NiceScopedMockLog log; |
| |
| // It is not L2 connected. |
| EXPECT_CALL(log, Log(_, _, HasSubstr("we are not connected"))); |
| ReportStateChanged(WPASupplicant::kInterfaceStateAuthenticating); |
| RequestStationInfo(WiFiLinkStatistics::Trigger::kUnknown); |
| |
| // Endpoint does not exist in endpoint_by_rpcid_. |
| SetSupplicantBSS( |
| RpcIdentifier("/some/path/that/does/not/exist/in/endpoint_by_rpcid")); |
| ReportStateChanged(WPASupplicant::kInterfaceStateCompleted); |
| EXPECT_CALL( |
| log, |
| Log(_, _, HasSubstr("Can't get endpoint for current supplicant BSS"))); |
| RequestStationInfo(WiFiLinkStatistics::Trigger::kUnknown); |
| Mock::VerifyAndClearExpectations(&*mock_dispatcher_); |
| |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), SignalPoll(_)) |
| .WillOnce(Return(false)); |
| // Scan is triggered due to RSSI drop |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, _)).Times(1); |
| EXPECT_CALL(*mock_dispatcher_, |
| PostDelayedTask(_, _, WiFi::kRequestStationInfoPeriod)) |
| .Times(1); |
| SetSupplicantBSS(connected_bss); |
| |
| RequestStationInfo(WiFiLinkStatistics::Trigger::kBackground); |
| StopRequestingStationInfo(); |
| |
| // Confirm that up until now no link statistics exist. |
| KeyValueStore link_statistics = GetLinkStatistics(); |
| EXPECT_TRUE(link_statistics.IsEmpty()); |
| |
| // Use a reference to the endpoint instance in the WiFi device instead of |
| // the copy returned by SetupConnectedService(). |
| WiFiEndpointRefPtr endpoint = GetEndpointMap().begin()->second; |
| |
| // Create the properties object. |
| KeyValueStore properties; |
| const int32_t kSignalValue = -20; |
| properties.Set<int32_t>(WPASupplicant::kSignalChangePropertyRSSI, |
| kSignalValue); |
| const int32_t kSignalAvgValue = -40; |
| properties.Set<int32_t>(WPASupplicant::kSignalChangePropertyAverageRSSI, |
| kSignalAvgValue); |
| const uint32_t kReceiveSuccesses = 200U; |
| properties.Set<uint32_t>(WPASupplicant::kSignalChangePropertyRxPackets, |
| kReceiveSuccesses); |
| const uint32_t kTransmitFailed = 300U; |
| properties.Set<uint32_t>(WPASupplicant::kSignalChangePropertyRetriesFailed, |
| kTransmitFailed); |
| const uint32_t kTransmitSuccesses = 400U; |
| properties.Set<uint32_t>(WPASupplicant::kSignalChangePropertyTxPackets, |
| kTransmitSuccesses); |
| const uint32_t kTransmitRetries = 500U; |
| properties.Set<uint32_t>(WPASupplicant::kSignalChangePropertyRetries, |
| kTransmitRetries); |
| const uint32_t kBitrate = 6005U; |
| properties.Set<uint32_t>(WPASupplicant::kSignalChangePropertyTxSpeed, |
| kBitrate * 100); |
| const uint32_t kMCS = 7U; |
| properties.Set<uint32_t>(WPASupplicant::kSignalChangePropertyTxMCS, kMCS); |
| properties.Set<std::string>(WPASupplicant::kSignalChangePropertyChannelWidth, |
| "40 MHz"); |
| |
| EXPECT_NE(kSignalAvgValue, endpoint->signal_strength()); |
| EXPECT_CALL(*wifi_provider(), OnEndpointUpdated(EndpointMatch(endpoint))); |
| EXPECT_CALL(*metrics(), |
| SendToUMA(Metrics::kMetricWifiTxBitrate, kBitrate / 10)); |
| SignalChanged(properties); |
| EXPECT_EQ(kSignalAvgValue, endpoint->signal_strength()); |
| |
| link_statistics = GetLinkStatistics(); |
| ASSERT_FALSE(link_statistics.IsEmpty()); |
| ASSERT_TRUE(link_statistics.Contains<int32_t>(kLastReceiveSignalDbmProperty)); |
| EXPECT_EQ(kSignalValue, |
| link_statistics.Get<int32_t>(kLastReceiveSignalDbmProperty)); |
| ASSERT_TRUE( |
| link_statistics.Contains<int32_t>(kAverageReceiveSignalDbmProperty)); |
| EXPECT_EQ(kSignalAvgValue, |
| link_statistics.Get<int32_t>(kAverageReceiveSignalDbmProperty)); |
| ASSERT_TRUE( |
| link_statistics.Contains<uint32_t>(kPacketReceiveSuccessesProperty)); |
| EXPECT_EQ(kReceiveSuccesses, |
| link_statistics.Get<uint32_t>(kPacketReceiveSuccessesProperty)); |
| ASSERT_TRUE( |
| link_statistics.Contains<uint32_t>(kPacketTransmitFailuresProperty)); |
| EXPECT_EQ(kTransmitFailed, |
| link_statistics.Get<uint32_t>(kPacketTransmitFailuresProperty)); |
| ASSERT_TRUE( |
| link_statistics.Contains<uint32_t>(kPacketTransmitSuccessesProperty)); |
| EXPECT_EQ(kTransmitSuccesses, |
| link_statistics.Get<uint32_t>(kPacketTransmitSuccessesProperty)); |
| ASSERT_TRUE(link_statistics.Contains<uint32_t>(kTransmitRetriesProperty)); |
| EXPECT_EQ(kTransmitRetries, |
| link_statistics.Get<uint32_t>(kTransmitRetriesProperty)); |
| EXPECT_EQ(base::StringPrintf("%d.%d MBit/s MCS %d 40MHz", kBitrate / 10, |
| kBitrate % 10, kMCS), |
| link_statistics.Lookup<std::string>(kTransmitBitrateProperty, "")); |
| EXPECT_EQ("", |
| link_statistics.Lookup<std::string>(kReceiveBitrateProperty, "")); |
| } |
| |
| TEST_F(WiFiMainTest, EmitStationInfoRequestEvery30thPeriod) { |
| // Setup a connected service. |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| constexpr int iterations = 90; |
| // For every 30 calls to RequestStationInfo() for background monitoring |
| // we emit 1 "periodic check" event. |
| EXPECT_CALL(*service, EmitLinkQualityTriggerEvent( |
| Metrics::kWiFiLinkQualityTriggerBackgroundCheck)) |
| .Times(iterations / 30); |
| for (int i = 0; i < iterations; ++i) { |
| RequestStationInfo(WiFiLinkStatistics::Trigger::kBackground); |
| } |
| } |
| |
| TEST_F(WiFiMainTest, EmitStationInfoRequestEventOnLinkStatsRequest) { |
| // Setup a connected service. |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| WiFiLinkStatistics::Trigger trigger = |
| WiFiLinkStatistics::Trigger::kCQMBeaconLoss; |
| EXPECT_CALL(*service, EmitLinkQualityTriggerEvent( |
| Metrics::kWiFiLinkQualityTriggerCQMBeaconLoss)) |
| .Times(1); |
| RetrieveLinkStatistics(trigger); |
| } |
| |
| TEST_F(WiFiMainTest, EmitStationInfoReportOnInfoReceived) { |
| // Setup a connected service. |
| StartWiFi(); |
| WiFiEndpointRefPtr endpoint; |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), &endpoint, nullptr); |
| |
| // Create a KeyValueStore. The message must contain the signal property. |
| KeyValueStore properties; |
| properties.Set<int32_t>(WPASupplicant::kSignalChangePropertyRSSI, -20); |
| |
| RetrieveLinkStatistics(WiFiLinkStatistics::Trigger::kConnected); |
| EXPECT_CALL(*service, EmitLinkQualityReportEvent(_)).Times(1); |
| SignalChanged(properties); |
| } |
| |
| TEST_F(WiFiMainTest, EmitStationInfoRequest) { |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| |
| // If we're connected to a service, we emit a trigger event. |
| SetCurrentService(service); |
| WiFiLinkStatistics::Trigger trigger = |
| WiFiLinkStatistics::Trigger::kCQMBeaconLoss; |
| EXPECT_CALL(*service, EmitLinkQualityTriggerEvent( |
| Metrics::kWiFiLinkQualityTriggerCQMBeaconLoss)) |
| .Times(1); |
| EmitStationInfoRequest(trigger); |
| } |
| |
| TEST_F(WiFiMainTest, EmitStationInfoRequestNotConnected) { |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| // We never connected to a service, we do not emit an event. |
| EXPECT_CALL(*service, EmitLinkQualityTriggerEvent(_)).Times(0); |
| EmitStationInfoRequest(WiFiLinkStatistics::Trigger::kCQMBeaconLoss); |
| } |
| |
| TEST_F(WiFiMainTest, EmitStationInfoRequestDisconnected) { |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| // We're connected to a service. |
| SetCurrentService(service); |
| // We disconnect from the service. |
| SetCurrentService(nullptr); |
| // If we're disconnected from the service, we do not emit an event. |
| EXPECT_CALL(*service, EmitLinkQualityTriggerEvent(_)).Times(0); |
| EmitStationInfoRequest(WiFiLinkStatistics::Trigger::kCQMBeaconLoss); |
| } |
| |
| TEST_F(WiFiMainTest, EmitStationInfoReceivedEvent) { |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| // If we're connected to a service, we emit a report event. |
| SetCurrentService(service); |
| EXPECT_CALL(*service, EmitLinkQualityReportEvent(_)).Times(1); |
| WiFiLinkStatistics::StationStats stats; |
| EmitStationInfoReceivedEvent(stats); |
| } |
| |
| TEST_F(WiFiMainTest, EmitStationInfoReceivedEventNotConnected) { |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| // We never connected to a service, we do not emit an event. |
| EXPECT_CALL(*service, EmitLinkQualityReportEvent(_)).Times(0); |
| WiFiLinkStatistics::StationStats stats; |
| EmitStationInfoReceivedEvent(stats); |
| } |
| |
| TEST_F(WiFiMainTest, EmitStationInfoReceivedEventDisconnected) { |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| // We're connected to a service. |
| SetCurrentService(service); |
| // We disconnect from the service. |
| SetCurrentService(nullptr); |
| // If we're disconnected from the service, we do not emit an event. |
| EXPECT_CALL(*service, EmitLinkQualityReportEvent(_)).Times(0); |
| WiFiLinkStatistics::StationStats stats; |
| EmitStationInfoReceivedEvent(stats); |
| } |
| |
| TEST_F(WiFiTimerTest, ResumeDispatchesConnectivityReportTask) { |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, base::TimeDelta())) |
| .Times(AnyNumber()); |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, _)).Times(AnyNumber()); |
| StartWiFi(); |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| EXPECT_CALL(*mock_dispatcher_, |
| PostDelayedTask(_, _, WiFi::kPostWakeConnectivityReportDelay)); |
| OnAfterResume(); |
| } |
| |
| TEST_F(WiFiTimerTest, StartScanTimer_ReturnsImmediately) { |
| Error e; |
| // Return immediately if scan interval is 0. |
| SetScanInterval(0, &e); |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, _)).Times(0); |
| StartScanTimer(); |
| } |
| |
| TEST_F(WiFiTimerTest, StartScanTimer_HaveFastScansRemaining) { |
| Error e; |
| const int scan_interval = 10; |
| SetScanInterval(scan_interval, &e); |
| SetFastScansRemaining(1); |
| EXPECT_CALL(*mock_dispatcher_, |
| PostDelayedTask(_, _, WiFi::kFastScanInterval)); |
| StartScanTimer(); |
| } |
| |
| TEST_F(WiFiTimerTest, StartScanTimer_NoFastScansRemaining) { |
| Error e; |
| const int scan_interval = 10; |
| SetScanInterval(scan_interval, &e); |
| SetFastScansRemaining(0); |
| EXPECT_CALL(*mock_dispatcher_, |
| PostDelayedTask(_, _, base::Seconds(scan_interval))); |
| StartScanTimer(); |
| } |
| |
| TEST_F(WiFiMainTest, EAPCertification) { |
| StartWiFi(); |
| |
| MockWiFiServiceRefPtr service = |
| MakeMockService(WiFiSecurity::kWpa2Enterprise); |
| EXPECT_CALL(*service, AddEAPCertification(_, _)).Times(0); |
| |
| ScopedMockLog log; |
| EXPECT_CALL(log, |
| Log(logging::LOGGING_ERROR, _, EndsWith("no current service."))); |
| KeyValueStore args; |
| ReportCertification(args); |
| Mock::VerifyAndClearExpectations(&log); |
| |
| SetCurrentService(service); |
| EXPECT_CALL(log, |
| Log(logging::LOGGING_ERROR, _, EndsWith("no depth parameter."))); |
| ReportCertification(args); |
| Mock::VerifyAndClearExpectations(&log); |
| |
| const uint32_t kDepth = 123; |
| args.Set<uint32_t>(WPASupplicant::kInterfacePropertyDepth, kDepth); |
| |
| EXPECT_CALL( |
| log, Log(logging::LOGGING_ERROR, _, EndsWith("no subject parameter."))); |
| ReportCertification(args); |
| Mock::VerifyAndClearExpectations(&log); |
| |
| const std::string kSubject("subject"); |
| args.Set<std::string>(WPASupplicant::kInterfacePropertySubject, kSubject); |
| EXPECT_CALL(*service, AddEAPCertification(kSubject, kDepth)).Times(1); |
| ReportCertification(args); |
| } |
| |
| TEST_F(WiFiTimerTest, ScanDoneDispatchesTasks) { |
| SetWiFiEnabled(true); |
| |
| // Dispatch WiFi::ScanFailedTask if scan failed. |
| EXPECT_TRUE(ScanFailedCallbackIsCancelled()); |
| EXPECT_CALL(*mock_dispatcher_, |
| PostDelayedTask(_, _, WiFi::kPostScanFailedDelay)); |
| ScanDone(false); |
| EXPECT_FALSE(ScanFailedCallbackIsCancelled()); |
| |
| // Dispatch WiFi::ScanDoneTask if scan succeeded, and cancel the scan failed |
| // callback if has been dispatched. |
| EXPECT_CALL(*mock_dispatcher_, PostDelayedTask(_, _, base::TimeDelta())); |
| ScanDone(true); |
| EXPECT_TRUE(ScanFailedCallbackIsCancelled()); |
| } |
| |
| TEST_F(WiFiMainTest, EAPEvent) { |
| StartWiFi(); |
| ScopedMockLog log; |
| EXPECT_CALL(log, |
| Log(logging::LOGGING_ERROR, _, EndsWith("no current service."))); |
| EXPECT_CALL(*eap_state_handler_, ParseStatus(_, _, _)).Times(0); |
| const std::string kEAPStatus("eap-status"); |
| const std::string kEAPParameter("eap-parameter"); |
| ReportEAPEvent(kEAPStatus, kEAPParameter); |
| Mock::VerifyAndClearExpectations(&log); |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| |
| MockWiFiServiceRefPtr service = |
| MakeMockService(WiFiSecurity::kWpa2Enterprise); |
| EXPECT_CALL(*service, SetFailure(_)).Times(0); |
| EXPECT_CALL(*eap_state_handler_, ParseStatus(kEAPStatus, kEAPParameter, _)); |
| SetCurrentService(service); |
| ReportEAPEvent(kEAPStatus, kEAPParameter); |
| Mock::VerifyAndClearExpectations(service.get()); |
| Mock::VerifyAndClearExpectations(eap_state_handler_); |
| |
| EXPECT_CALL(*eap_state_handler_, ParseStatus(kEAPStatus, kEAPParameter, _)) |
| .WillOnce( |
| DoAll(SetArgPointee<2>(Service::kFailureOutOfRange), Return(false))); |
| ReportEAPEvent(kEAPStatus, kEAPParameter); |
| |
| MockEapCredentials* eap = new MockEapCredentials(); |
| service->eap_.reset(eap); // Passes ownership. |
| const RpcIdentifier kNetworkRpcId("/service/network/rpcid"); |
| SetServiceNetworkRpcId(service, kNetworkRpcId); |
| EXPECT_CALL(*eap_state_handler_, ParseStatus(kEAPStatus, kEAPParameter, _)) |
| .WillOnce( |
| DoAll(SetArgPointee<2>(Service::kFailurePinMissing), Return(false))); |
| // We need a real string object since it will be returned by reference below. |
| const std::string kEmptyPin; |
| EXPECT_CALL(*eap, pin()).WillOnce(ReturnRef(kEmptyPin)); |
| ReportEAPEvent(kEAPStatus, kEAPParameter); |
| |
| EXPECT_CALL(*eap_state_handler_, ParseStatus(kEAPStatus, kEAPParameter, _)) |
| .WillOnce( |
| DoAll(SetArgPointee<2>(Service::kFailurePinMissing), Return(false))); |
| // We need a real string object since it will be returned by reference below. |
| const std::string kPin("000000"); |
| EXPECT_CALL(*eap, pin()).WillOnce(ReturnRef(kPin)); |
| EXPECT_CALL(*service, DisconnectWithFailure(_, _, _)).Times(0); |
| EXPECT_CALL( |
| *GetSupplicantInterfaceProxy(), |
| NetworkReply(kNetworkRpcId, |
| StrEq(WPASupplicant::kEAPRequestedParameterPin), Ref(kPin))); |
| ReportEAPEvent(kEAPStatus, kEAPParameter); |
| } |
| |
| TEST_F(WiFiMainTest, RekeyDoesNotTriggerStateChange) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| EXPECT_CALL(*service, IsConnected(nullptr)).WillRepeatedly(Return(true)); |
| EXPECT_CALL(*service, SetState(_)).Times(0); |
| ReportStateChanged(WPASupplicant::kInterfaceState4WayHandshake); |
| ASSERT_TRUE(GetCurrentService()->is_rekey_in_progress()); |
| ReportStateChanged(WPASupplicant::kInterfaceStateGroupHandshake); |
| ASSERT_TRUE(GetCurrentService()->is_rekey_in_progress()); |
| ReportStateChanged(WPASupplicant::kInterfaceStateCompleted); |
| ASSERT_FALSE(GetCurrentService()->is_rekey_in_progress()); |
| Mock::VerifyAndClearExpectations(service.get()); |
| } |
| |
| TEST_F(WiFiMainTest, PendingScanDoesNotCrashAfterStop) { |
| // Scan is one task that should be skipped after Stop. Others are |
| // skipped by the same mechanism (invalidating weak pointers), so we |
| // don't test them individually. |
| // |
| // Note that we can't test behavior by setting expectations on the |
| // supplicant_interface_proxy_, since that is destroyed when we StopWiFi(). |
| StartWiFi(); |
| StopWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| } |
| |
| struct BSS { |
| RpcIdentifier bsspath; |
| std::string ssid; |
| net_base::MacAddress bssid; |
| int16_t signal_strength; |
| uint16_t frequency; |
| const char* mode; |
| uint32_t age; |
| }; |
| |
| TEST_F(WiFiMainTest, UpdateGeolocationObjects) { |
| BSS bsses[] = { |
| {RpcIdentifier("bssid1"), "ssid1", |
| net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 5, |
| Metrics::kWiFiFrequency2412, kNetworkModeInfrastructure, 0}, |
| {RpcIdentifier("bssid2"), "ssid2", |
| net_base::MacAddress(0x01, 0x00, 0x00, 0x00, 0x00, 0x00), 30, |
| Metrics::kWiFiFrequency5170, kNetworkModeInfrastructure, |
| WiFi::kWiFiGeolocationInfoExpiration.InSeconds() + 1}, |
| // Same SSID but different BSSID is an additional geolocation object. |
| {RpcIdentifier("bssid3"), "ssid1", |
| net_base::MacAddress(0x02, 0x00, 0x00, 0x00, 0x00, 0x00), 100, 0, |
| kNetworkModeInfrastructure, 0}}; |
| StartWiFi(); |
| auto objects = &(manager()->device_geolocation_info_[wifi()]); |
| EXPECT_EQ(objects->size(), 0); |
| |
| for (size_t i = 0; i < std::size(bsses); ++i) { |
| ReportBSS(bsses[i].bsspath, bsses[i].ssid, bsses[i].bssid, |
| bsses[i].signal_strength, bsses[i].frequency, bsses[i].mode, |
| bsses[i].age); |
| wifi()->UpdateGeolocationObjects(objects); |
| EXPECT_EQ(objects->size(), i + 1); |
| EXPECT_EQ((*objects)[i][kGeoMacAddressProperty], bsses[i].bssid.ToString()); |
| EXPECT_EQ((*objects)[i][kGeoSignalStrengthProperty], |
| base::StringPrintf("%d", bsses[i].signal_strength)); |
| EXPECT_EQ((*objects)[i][kGeoChannelProperty], |
| base::StringPrintf( |
| "%d", Metrics::WiFiFrequencyToChannel(bsses[i].frequency))); |
| } |
| // Update the geolocation cache using new scan results |
| for (const auto& bss : bsses) { |
| RemoveBSS(bss.bsspath); |
| } |
| // bsses_in_scan are the BSSes reported in the latest scan result |
| BSS bsses_in_scan[] = { |
| {RpcIdentifier("bssid1"), "ssid1", |
| net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 6, |
| Metrics::kWiFiFrequency2412, kNetworkModeInfrastructure, 0}, |
| {RpcIdentifier("bssid4"), "ssid4", |
| net_base::MacAddress(0x03, 0x00, 0x00, 0x00, 0x00, 0x00), 100, |
| Metrics::kWiFiFrequency5170, kNetworkModeInfrastructure, 0}}; |
| for (const auto& bss : bsses_in_scan) { |
| ReportBSS(bss.bsspath, bss.ssid, bss.bssid, bss.signal_strength, |
| bss.frequency, bss.mode, bss.age); |
| } |
| // bsses_after_update are the BSSes remained in the geolocation cache after |
| // the update using the latest scan result, where |
| // 1. bssid1 is in the latest scan result, it replaces the one in the |
| // current geolocation cache |
| // 2. bssid2 is not shown in the latest scan result and has reached |
| // expiration, so it is evicted from the geolocation cache |
| // 3. bssid3 is not shown in the latest scan result but has not reached |
| // expiration yet, so it is put back to the geolocation cache |
| // 4. bssid4 is a new BSS discovered in the latest scan, it is inserted |
| // into the geolocation cache |
| BSS bsses_after_update[] = {bsses_in_scan[0], bsses_in_scan[1], bsses[2]}; |
| wifi()->UpdateGeolocationObjects(objects); |
| EXPECT_EQ(objects->size(), std::size(bsses_after_update)); |
| for (size_t i = 0; i < std::size(bsses_after_update); ++i) { |
| EXPECT_EQ((*objects)[i][kGeoMacAddressProperty], |
| bsses_after_update[i].bssid.ToString()); |
| EXPECT_EQ((*objects)[i][kGeoSignalStrengthProperty], |
| base::StringPrintf("%d", bsses_after_update[i].signal_strength)); |
| EXPECT_EQ((*objects)[i][kGeoChannelProperty], |
| base::StringPrintf( |
| "%d", Metrics::WiFiFrequencyToChannel(bsses[i].frequency))); |
| } |
| } |
| |
| TEST_F(WiFiMainTest, SetSupplicantDebugLevel) { |
| MockSupplicantProcessProxy* process_proxy = supplicant_process_proxy_; |
| |
| // With WiFi not yet started, nothing interesting (including a crash) should |
| // happen. |
| EXPECT_CALL(*process_proxy, GetDebugLevel(_)).Times(0); |
| EXPECT_CALL(*process_proxy, SetDebugLevel(_)).Times(0); |
| ReportWiFiDebugScopeChanged(true); |
| |
| // This unit test turns on WiFi debugging, so when we start WiFi, we should |
| // check but not set the debug level if we return the "debug" level. |
| EXPECT_CALL(*process_proxy, GetDebugLevel(_)) |
| .WillOnce( |
| DoAll(SetArgPointee<0>(std::string(WPASupplicant::kDebugLevelDebug)), |
| Return(true))); |
| EXPECT_CALL(*process_proxy, SetDebugLevel(_)).Times(0); |
| StartWiFi(); |
| Mock::VerifyAndClearExpectations(process_proxy); |
| |
| // If WiFi debugging is toggled and wpa_supplicant reports debugging |
| // is set to some unmanaged level, WiFi should leave it alone. |
| EXPECT_CALL(*process_proxy, GetDebugLevel(_)) |
| .WillOnce( |
| DoAll(SetArgPointee<0>(std::string(WPASupplicant::kDebugLevelError)), |
| Return(true))) |
| .WillOnce( |
| DoAll(SetArgPointee<0>(std::string(WPASupplicant::kDebugLevelError)), |
| Return(true))) |
| .WillOnce(DoAll( |
| SetArgPointee<0>(std::string(WPASupplicant::kDebugLevelExcessive)), |
| Return(true))) |
| .WillOnce(DoAll( |
| SetArgPointee<0>(std::string(WPASupplicant::kDebugLevelExcessive)), |
| Return(true))) |
| .WillOnce(DoAll( |
| SetArgPointee<0>(std::string(WPASupplicant::kDebugLevelMsgDump)), |
| Return(true))) |
| .WillOnce(DoAll( |
| SetArgPointee<0>(std::string(WPASupplicant::kDebugLevelMsgDump)), |
| Return(true))) |
| .WillOnce(DoAll( |
| SetArgPointee<0>(std::string(WPASupplicant::kDebugLevelWarning)), |
| Return(true))) |
| .WillOnce(DoAll( |
| SetArgPointee<0>(std::string(WPASupplicant::kDebugLevelWarning)), |
| Return(true))); |
| EXPECT_CALL(*process_proxy, SetDebugLevel(_)).Times(0); |
| ReportWiFiDebugScopeChanged(true); |
| ReportWiFiDebugScopeChanged(false); |
| ReportWiFiDebugScopeChanged(true); |
| ReportWiFiDebugScopeChanged(false); |
| ReportWiFiDebugScopeChanged(true); |
| ReportWiFiDebugScopeChanged(false); |
| ReportWiFiDebugScopeChanged(true); |
| ReportWiFiDebugScopeChanged(false); |
| Mock::VerifyAndClearExpectations(process_proxy); |
| |
| // If WiFi debugging is turned off and wpa_supplicant reports debugging |
| // is turned on, WiFi should turn supplicant debugging off. |
| EXPECT_CALL(*process_proxy, GetDebugLevel(_)) |
| .WillOnce( |
| DoAll(SetArgPointee<0>(std::string(WPASupplicant::kDebugLevelDebug)), |
| Return(true))); |
| EXPECT_CALL(*process_proxy, SetDebugLevel(WPASupplicant::kDebugLevelInfo)) |
| .Times(1); |
| ReportWiFiDebugScopeChanged(false); |
| Mock::VerifyAndClearExpectations(process_proxy); |
| |
| // If WiFi debugging is turned on and wpa_supplicant reports debugging |
| // is turned off, WiFi should turn supplicant debugging on. |
| EXPECT_CALL(*process_proxy, GetDebugLevel(_)) |
| .WillOnce( |
| DoAll(SetArgPointee<0>(std::string(WPASupplicant::kDebugLevelInfo)), |
| Return(true))); |
| EXPECT_CALL(*process_proxy, SetDebugLevel(WPASupplicant::kDebugLevelDebug)) |
| .Times(1); |
| ReportWiFiDebugScopeChanged(true); |
| Mock::VerifyAndClearExpectations(process_proxy); |
| |
| // If WiFi debugging is already in the correct state, it should not be |
| // changed. |
| EXPECT_CALL(*process_proxy, GetDebugLevel(_)) |
| .WillOnce( |
| DoAll(SetArgPointee<0>(std::string(WPASupplicant::kDebugLevelDebug)), |
| Return(true))) |
| .WillOnce( |
| DoAll(SetArgPointee<0>(std::string(WPASupplicant::kDebugLevelInfo)), |
| Return(true))); |
| EXPECT_CALL(*process_proxy, SetDebugLevel(_)).Times(0); |
| ReportWiFiDebugScopeChanged(true); |
| ReportWiFiDebugScopeChanged(false); |
| Mock::VerifyAndClearExpectations(process_proxy); |
| |
| // After WiFi is stopped, we may still call the proxy if it hasn't vanished. |
| // Make sure we don't crash. |
| StopWiFi(); |
| ReportWiFiDebugScopeChanged(true); |
| ReportWiFiDebugScopeChanged(false); |
| } |
| |
| TEST_F(WiFiMainTest, LogLevelOnSupplicantVanish) { |
| MockSupplicantProcessProxy* process_proxy = supplicant_process_proxy_; |
| StartWiFi(); |
| |
| // After supplicant vanishes, we shouldn't be calling the proxy. |
| EXPECT_CALL(*process_proxy, GetDebugLevel(_)).Times(0); |
| EXPECT_CALL(*process_proxy, SetDebugLevel(_)).Times(0); |
| OnSupplicantVanish(); |
| ReportWiFiDebugScopeChanged(true); |
| ReportWiFiDebugScopeChanged(false); |
| } |
| |
| TEST_F(WiFiMainTest, LogSSID) { |
| EXPECT_EQ("[SSID=]", WiFi::LogSSID("")); |
| EXPECT_EQ("[SSID=foo\\x5b\\x09\\x5dbar]", WiFi::LogSSID("foo[\t]bar")); |
| } |
| |
| // Custom property setters should return false, and make no changes, if |
| // the new value is the same as the old value. |
| TEST_F(WiFiMainTest, CustomSetterNoopChange) { |
| // SetBgscanShortInterval |
| { |
| Error error; |
| static const uint16_t kKnownScanInterval = 4; |
| // Set to known value. |
| EXPECT_TRUE(SetBgscanShortInterval(kKnownScanInterval, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| // Set to same value. |
| EXPECT_FALSE(SetBgscanShortInterval(kKnownScanInterval, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| } |
| |
| // SetBgscanSignalThreshold |
| { |
| Error error; |
| static const int32_t kKnownSignalThreshold = 4; |
| // Set to known value. |
| EXPECT_TRUE(SetBgscanSignalThreshold(kKnownSignalThreshold, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| // Set to same value. |
| EXPECT_FALSE(SetBgscanSignalThreshold(kKnownSignalThreshold, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| } |
| |
| // SetScanInterval |
| { |
| Error error; |
| EXPECT_FALSE(SetScanInterval(GetScanInterval(), &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| } |
| } |
| |
| // The following tests check the scan_state_ / scan_method_ state machine. |
| |
| TEST_F(WiFiMainTest, FullScanFindsNothing) { |
| StartScan(WiFiState::ScanMethod::kFull); |
| ReportScanDone(); |
| ExpectScanStop(); |
| ExpectFoundNothing(); |
| NiceScopedMockLog log; |
| ScopeLogger::GetInstance()->EnableScopesByName("wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(10); |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| EXPECT_CALL(log, Log(_, _, HasSubstr("FULL_NOCONNECTION ->"))); |
| EXPECT_CALL(*manager(), OnDeviceGeolocationInfoUpdated(_)); |
| test_event_dispatcher_ |
| ->DispatchPendingEvents(); // Launch UpdateScanStateAfterScanDone |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| |
| ScopeLogger::GetInstance()->set_verbose_level(0); |
| ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); |
| } |
| |
| TEST_F(WiFiMainTest, FullScanConnectingToConnected) { |
| StartScan(WiFiState::ScanMethod::kFull); |
| WiFiEndpointRefPtr endpoint; |
| RpcIdentifier bss_path; |
| MockWiFiServiceRefPtr service = |
| AttemptConnection(WiFiState::ScanMethod::kFull, &endpoint, &bss_path); |
| |
| // Complete the connection. |
| ExpectConnected(); |
| EXPECT_CALL(*service, NotifyCurrentEndpoint(EndpointMatch(endpoint))); |
| NiceScopedMockLog log; |
| ScopeLogger::GetInstance()->EnableScopesByName("wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(10); |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| EXPECT_CALL(log, Log(_, _, HasSubstr("-> FULL_CONNECTED"))); |
| ReportCurrentBSSChanged(bss_path); |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| |
| ScopeLogger::GetInstance()->set_verbose_level(0); |
| ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); |
| } |
| |
| TEST_F(WiFiMainTest, ScanStateUma) { |
| EXPECT_CALL(*metrics(), ReportDeviceScanResultToUma(_)).Times(0); |
| EXPECT_CALL(*metrics(), NotifyDeviceScanStarted(_)); |
| SetScanState(WiFiState::PhyState::kScanning, WiFiState::ScanMethod::kFull, |
| __func__); |
| |
| EXPECT_CALL(*metrics(), NotifyDeviceScanFinished(_)); |
| EXPECT_CALL(*metrics(), NotifyDeviceConnectStarted(_)); |
| SetScanState(WiFiState::PhyState::kConnecting, WiFiState::ScanMethod::kFull, |
| __func__); |
| |
| ExpectScanIdle(); // After connected. |
| EXPECT_CALL(*metrics(), NotifyDeviceConnectFinished(_)); |
| EXPECT_CALL(*metrics(), ReportDeviceScanResultToUma(_)); |
| SetScanState(WiFiState::PhyState::kConnected, WiFiState::ScanMethod::kFull, |
| __func__); |
| } |
| |
| TEST_F(WiFiMainTest, ScanStateNotScanningNoUma) { |
| EXPECT_CALL(*metrics(), NotifyDeviceScanStarted(_)).Times(0); |
| EXPECT_CALL(*metrics(), NotifyDeviceConnectStarted(_)); |
| SetScanState(WiFiState::PhyState::kConnecting, WiFiState::ScanMethod::kNone, |
| __func__); |
| |
| ExpectScanIdle(); // After connected. |
| EXPECT_CALL(*metrics(), NotifyDeviceConnectFinished(_)); |
| EXPECT_CALL(*metrics(), ReportDeviceScanResultToUma(_)).Times(0); |
| SetScanState(WiFiState::PhyState::kConnected, WiFiState::ScanMethod::kNone, |
| __func__); |
| } |
| |
| TEST_F(WiFiMainTest, ConnectToServiceNotPending) { |
| // Test for SetPendingService(nullptr), condition a) |
| // |ConnectTo|->|DisconnectFrom|. |
| StartScan(WiFiState::ScanMethod::kFull); |
| |
| // Setup pending service. |
| ExpectScanStop(); |
| ExpectConnecting(); |
| MockWiFiServiceRefPtr service_pending( |
| SetupConnectingService(RpcIdentifier(""), nullptr, nullptr)); |
| EXPECT_EQ(service_pending, GetPendingService()); |
| |
| // ConnectTo a different service than the pending one. |
| ExpectConnecting(); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Disconnect()); |
| NiceScopedMockLog log; |
| ScopeLogger::GetInstance()->EnableScopesByName("wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(10); |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| EXPECT_CALL(log, Log(_, _, HasSubstr("-> TRANSITION_TO_CONNECTING"))); |
| EXPECT_CALL(log, Log(_, _, HasSubstr("-> FULL_CONNECTING"))); |
| MockWiFiServiceRefPtr service_connecting( |
| SetupConnectingService(RpcIdentifier(""), nullptr, nullptr)); |
| ScopeLogger::GetInstance()->set_verbose_level(0); |
| ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); |
| EXPECT_EQ(service_connecting, GetPendingService()); |
| EXPECT_EQ(nullptr, GetCurrentService()); |
| VerifyScanState(WiFiState::PhyState::kConnecting, |
| WiFiState::ScanMethod::kFull); |
| |
| ExpectScanIdle(); // To silence messages from the destructor. |
| } |
| |
| TEST_F(WiFiMainTest, ConnectToWithError) { |
| StartScan(WiFiState::ScanMethod::kFull); |
| |
| ExpectScanIdle(); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), AddNetwork(_, _)) |
| .WillOnce(Return(false)); |
| EXPECT_CALL(*metrics(), NotifyDeviceScanFinished(_)).Times(0); |
| EXPECT_CALL(*metrics(), ReportDeviceScanResultToUma(_)).Times(0); |
| EXPECT_CALL(*adaptor_, EmitBoolChanged(kScanningProperty, false)); |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| EXPECT_CALL(*service, GetSupplicantConfigurationParameters()); |
| InitiateConnect(service); |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| } |
| |
| TEST_F(WiFiMainTest, ScanStateHandleDisconnect) { |
| // Test for SetPendingService(nullptr), condition d) Disconnect while |
| // scanning. |
| |
| // Start scanning. |
| StartScan(WiFiState::ScanMethod::kFull); |
| |
| // Set the pending service. |
| ReportScanDone(); |
| ExpectScanStop(); |
| ExpectConnecting(); |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| SetPendingService(service); |
| VerifyScanState(WiFiState::PhyState::kConnecting, |
| WiFiState::ScanMethod::kFull); |
| |
| // Disconnect from the pending service. |
| ExpectScanIdle(); |
| EXPECT_CALL(*metrics(), NotifyDeviceScanFinished(_)).Times(0); |
| EXPECT_CALL(*metrics(), ReportDeviceScanResultToUma(_)).Times(0); |
| ReportCurrentBSSChanged(RpcIdentifier(WPASupplicant::kCurrentBSSNull)); |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| } |
| |
| TEST_F(WiFiMainTest, ConnectWhileNotScanning) { |
| // Setup WiFi but terminate scan. |
| EXPECT_CALL(*adaptor_, EmitBoolChanged(kPoweredProperty, _)) |
| .Times(AnyNumber()); |
| |
| ExpectScanStart(WiFiState::ScanMethod::kFull, false); |
| StartWiFi(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| |
| ExpectScanStop(); |
| ExpectFoundNothing(); |
| ReportScanDone(); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| |
| // Connecting. |
| ExpectConnecting(); |
| EXPECT_CALL(*metrics(), NotifyDeviceScanStarted(_)).Times(0); |
| WiFiEndpointRefPtr endpoint; |
| RpcIdentifier bss_path; |
| NiceScopedMockLog log; |
| ScopeLogger::GetInstance()->EnableScopesByName("wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(10); |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| EXPECT_CALL(log, Log(_, _, HasSubstr("-> TRANSITION_TO_CONNECTING"))) |
| .Times(0); |
| EXPECT_CALL(log, Log(_, _, HasSubstr("-> CONNECTING (not scan related)"))); |
| MockWiFiServiceRefPtr service = |
| SetupConnectingService(RpcIdentifier(""), &endpoint, &bss_path); |
| |
| // Connected. |
| ExpectConnected(); |
| EXPECT_CALL(log, Log(_, _, HasSubstr("-> CONNECTED (not scan related"))); |
| ReportCurrentBSSChanged(bss_path); |
| ScopeLogger::GetInstance()->set_verbose_level(0); |
| ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| } |
| |
| TEST_F(WiFiMainTest, BackgroundScan) { |
| StartWiFi(); |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), Scan(_)).Times(1); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| VerifyScanState(WiFiState::PhyState::kBackgroundScanning, |
| WiFiState::ScanMethod::kFull); |
| |
| ReportScanDone(); |
| EXPECT_CALL(*manager(), OnDeviceGeolocationInfoUpdated(_)); |
| test_event_dispatcher_ |
| ->DispatchPendingEvents(); // Launch UpdateScanStateAfterScanDone |
| VerifyScanState(WiFiState::PhyState::kIdle, WiFiState::ScanMethod::kNone); |
| } |
| |
| TEST_F(WiFiMainTest, OnNewWiphy) { |
| SetPhyIndex(kNewWiphyNlMsg_PhyIndex); |
| NewWiphyMessage new_wiphy_message; |
| net_base::NetlinkPacket packet(kNewWiphyNlMsg); |
| new_wiphy_message.InitFromPacketWithContext(&packet, |
| Nl80211Message::Context()); |
| EXPECT_CALL(*wake_on_wifi_, ParseWakeOnWiFiCapabilities(_)); |
| EXPECT_CALL(*wake_on_wifi_, OnWiphyIndexReceived(kNewWiphyNlMsg_PhyIndex)); |
| EXPECT_CALL(*wifi_provider(), |
| RegisterDeviceToPhy(wifi(), kNewWiphyNlMsg_PhyIndex)); |
| OnNewWiphy(new_wiphy_message); |
| } |
| |
| TEST_F(WiFiMainTest, OnNewWiphy_IndexChanged) { |
| SetPhyIndex(kNewWiphyNlMsg_PhyIndex); |
| NewWiphyMessage new_wiphy_message; |
| net_base::NetlinkPacket packet(kNewWiphyNlMsg); |
| new_wiphy_message.InitFromPacketWithContext(&packet, |
| Nl80211Message::Context()); |
| EXPECT_CALL(*wifi_provider(), |
| RegisterDeviceToPhy(wifi(), kNewWiphyNlMsg_PhyIndex)); |
| EXPECT_CALL(*wifi_provider(), OnNewWiphy(_)); |
| OnNewWiphy(new_wiphy_message); |
| EXPECT_EQ(GetPhyIndex(), kNewWiphyNlMsg_PhyIndex); |
| |
| // A second call to OnNewWiphy with a new index should cause the device to |
| // deregister from the previous phy and register to a new one. The phy_index |
| // should also change. |
| new_wiphy_message.attributes()->SetU32AttributeValue( |
| NL80211_ATTR_WIPHY, kNewWiphyNlMsg_ChangedPhyIndex); |
| EXPECT_CALL( |
| *wifi_provider(), |
| DeregisterDeviceFromPhy(wifi()->link_name(), kNewWiphyNlMsg_PhyIndex)); |
| EXPECT_CALL(*wifi_provider(), |
| RegisterDeviceToPhy(wifi(), kNewWiphyNlMsg_ChangedPhyIndex)); |
| EXPECT_CALL(*wifi_provider(), OnNewWiphy(_)); |
| OnNewWiphy(new_wiphy_message); |
| EXPECT_EQ(GetPhyIndex(), kNewWiphyNlMsg_ChangedPhyIndex); |
| } |
| |
| TEST_F(WiFiMainTest, OnGetDHCPLease_InvokesOnConnectedAndReachable) { |
| ScopedMockLog log; |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| ScopeLogger::GetInstance()->EnableScopesByName("wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(3); |
| EXPECT_CALL(log, Log(_, _, HasSubstr("IPv4 DHCP lease obtained"))); |
| EXPECT_CALL(*wake_on_wifi_, OnConnectedAndReachable(_)); |
| ReportIPv4ConfiguredWithDHCPLease(); |
| |
| // We should not call WakeOnWiFi::OnConnectedAndReachable if we are not |
| // actually connected to a service. |
| SetCurrentService(nullptr); |
| EXPECT_CALL(*wake_on_wifi_, OnConnectedAndReachable(_)).Times(0); |
| ReportIPv6ConfiguredWithSLAACAddress(); |
| |
| // If we are actually connected to a service when our IPv6 configuration is |
| // updated, we should call WakeOnWiFi::OnConnectedAndReachable. |
| MockWiFiServiceRefPtr service = |
| MakeMockService(WiFiSecurity::kWpa2Enterprise); |
| EXPECT_CALL(*service, IsConnected(nullptr)).WillOnce(Return(true)); |
| SetCurrentService(service); |
| EXPECT_CALL(log, Log(_, _, HasSubstr("IPv6 configuration obtained"))); |
| EXPECT_CALL(*wake_on_wifi_, OnConnectedAndReachable(_)); |
| ReportIPv6ConfiguredWithSLAACAddress(); |
| |
| ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(0); |
| } |
| |
| TEST_F(WiFiMainTest, OnBeforeSuspend_CallsWakeOnWiFi) { |
| SetWiFiEnabled(true); |
| EXPECT_CALL(*wake_on_wifi_, |
| OnBeforeSuspend(IsConnectedToCurrentService(), _, _, _, _, _)); |
| EXPECT_CALL(*this, SuspendCallback(_)).Times(0); |
| OnBeforeSuspend(); |
| |
| SetWiFiEnabled(false); |
| EXPECT_CALL(*wake_on_wifi_, |
| OnBeforeSuspend(IsConnectedToCurrentService(), _, _, _, _, _)) |
| .Times(0); |
| EXPECT_CALL(*this, SuspendCallback(ErrorTypeIs(Error::kSuccess))); |
| OnBeforeSuspend(); |
| } |
| |
| TEST_F(WiFiMainTest, OnDarkResume_CallsWakeOnWiFi) { |
| SetWiFiEnabled(true); |
| EXPECT_CALL(*wake_on_wifi_, |
| OnDarkResume(IsConnectedToCurrentService(), _, _, _, _, _)); |
| EXPECT_CALL(*this, SuspendCallback(_)).Times(0); |
| OnDarkResume(); |
| |
| SetWiFiEnabled(false); |
| EXPECT_CALL(*wake_on_wifi_, |
| OnDarkResume(IsConnectedToCurrentService(), _, _, _, _, _)) |
| .Times(0); |
| EXPECT_CALL(*this, SuspendCallback(ErrorTypeIs(Error::kSuccess))); |
| OnDarkResume(); |
| } |
| |
| TEST_F(WiFiMainTest, RemoveSupplicantNetworks) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service1 = |
| MakeMockService(WiFiSecurity::kWpaEnterprise); |
| MockWiFiServiceRefPtr service2 = |
| MakeMockService(WiFiSecurity::kWpa2Enterprise); |
| const RpcIdentifier kNetworkRpcId1("/service/network/rpcid1"); |
| const RpcIdentifier kNetworkRpcId2("/service/network/rpcid2"); |
| SetServiceNetworkRpcId(service1, kNetworkRpcId1); |
| SetServiceNetworkRpcId(service2, kNetworkRpcId2); |
| ASSERT_FALSE(RpcIdByServiceIsEmpty()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveNetwork(kNetworkRpcId1)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveNetwork(kNetworkRpcId2)); |
| RemoveSupplicantNetworks(); |
| ASSERT_TRUE(RpcIdByServiceIsEmpty()); |
| } |
| |
| TEST_F(WiFiMainTest, InitiateScan_Idle) { |
| ScopedMockLog log; |
| ASSERT_TRUE(wifi()->IsIdle()); |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| EXPECT_CALL(log, Log(_, _, ContainsRegex("Scan"))).Times(AtLeast(1)); |
| InitiateScan(); |
| } |
| |
| TEST_F(WiFiMainTest, InitiateScan_NotIdle) { |
| ScopedMockLog log; |
| ScopeLogger::GetInstance()->EnableScopesByName("wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(1); |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kWpa2); |
| SetPendingService(service); |
| EXPECT_FALSE(wifi()->IsIdle()); |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| EXPECT_CALL( |
| log, |
| Log(_, _, HasSubstr("skipping scan, already connecting or connected."))); |
| InitiateScan(); |
| ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(0); |
| } |
| |
| TEST_F(WiFiMainTest, InitiateScanInDarkResume_Idle) { |
| const WiFi::FreqSet freqs; |
| StartWiFi(); |
| manager()->set_suppress_autoconnect(false); |
| ASSERT_TRUE(wifi()->IsIdle()); |
| EXPECT_CALL( |
| netlink_manager_, |
| SendOrPostMessage( |
| IsNl80211Command(kNl80211FamilyId, TriggerScanMessage::kCommand), _)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), FlushBSS(0)); |
| InitiateScanInDarkResume(freqs); |
| EXPECT_TRUE(manager()->suppress_autoconnect()); |
| } |
| |
| TEST_F(WiFiMainTest, InitiateScanInDarkResume_NotIdle) { |
| const WiFi::FreqSet freqs; |
| ScopedMockLog log; |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kWpa2); |
| SetPendingService(service); |
| manager()->set_suppress_autoconnect(false); |
| EXPECT_FALSE(wifi()->IsIdle()); |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| EXPECT_CALL( |
| log, |
| Log(_, _, HasSubstr("skipping scan, already connecting or connected."))); |
| EXPECT_CALL( |
| netlink_manager_, |
| SendOrPostMessage( |
| IsNl80211Command(kNl80211FamilyId, TriggerScanMessage::kCommand), _)) |
| .Times(0); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), FlushBSS(_)).Times(0); |
| InitiateScanInDarkResume(freqs); |
| EXPECT_FALSE(manager()->suppress_autoconnect()); |
| } |
| |
| TEST_F(WiFiMainTest, TriggerPassiveScan_NoResults) { |
| ScopedMockLog log; |
| ScopeLogger::GetInstance()->EnableScopesByName("wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(3); |
| const WiFi::FreqSet freqs; |
| EXPECT_CALL( |
| netlink_manager_, |
| SendOrPostMessage( |
| IsNl80211Command(kNl80211FamilyId, TriggerScanMessage::kCommand), _)); |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| EXPECT_CALL(log, Log(_, _, HasSubstr("Scanning on specific channels"))) |
| .Times(0); |
| TriggerPassiveScan(freqs); |
| ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(0); |
| } |
| |
| TEST_F(WiFiMainTest, TriggerPassiveScan_HasResults) { |
| ScopedMockLog log; |
| ScopeLogger::GetInstance()->EnableScopesByName("wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(3); |
| const WiFi::FreqSet freqs = {1}; |
| EXPECT_CALL( |
| netlink_manager_, |
| SendOrPostMessage( |
| IsNl80211Command(kNl80211FamilyId, TriggerScanMessage::kCommand), _)); |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| EXPECT_CALL(log, Log(_, _, HasSubstr("Scanning on specific channels"))) |
| .Times(1); |
| TriggerPassiveScan(freqs); |
| ScopeLogger::GetInstance()->EnableScopesByName("-wifi"); |
| ScopeLogger::GetInstance()->set_verbose_level(0); |
| } |
| |
| TEST_F(WiFiMainTest, PendingScanEvents) { |
| // This test essentially performs ReportBSS(), but ensures that the |
| // WiFi object successfully dispatches events in order. |
| StartWiFi(); |
| BSSAdded( |
| RpcIdentifier("bss0"), |
| CreateBSSProperties( |
| "ssid0", net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 0, |
| 0, kNetworkModeInfrastructure, 0)); |
| BSSAdded( |
| RpcIdentifier("bss1"), |
| CreateBSSProperties( |
| "ssid1", net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x01), 0, |
| 0, kNetworkModeInfrastructure, 0)); |
| BSSRemoved(RpcIdentifier("bss0")); |
| BSSAdded( |
| RpcIdentifier("bss2"), |
| CreateBSSProperties( |
| "ssid2", net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x02), 0, |
| 0, kNetworkModeInfrastructure, 0)); |
| |
| WiFiEndpointRefPtr ap0 = MakeEndpoint( |
| "ssid0", net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); |
| WiFiEndpointRefPtr ap1 = MakeEndpoint( |
| "ssid1", net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x01)); |
| WiFiEndpointRefPtr ap2 = MakeEndpoint( |
| "ssid2", net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x02)); |
| |
| InSequence seq; |
| EXPECT_CALL(*wifi_provider(), OnEndpointAdded(EndpointMatch(ap0))); |
| EXPECT_CALL(*wifi_provider(), OnEndpointAdded(EndpointMatch(ap1))); |
| WiFiServiceRefPtr null_service; |
| EXPECT_CALL(*wifi_provider(), OnEndpointRemoved(EndpointMatch(ap0))) |
| .WillOnce(Return(null_service)); |
| EXPECT_CALL(*wifi_provider(), OnEndpointAdded(EndpointMatch(ap2))); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(wifi_provider()); |
| |
| const WiFi::EndpointMap& endpoints_by_rpcid = GetEndpointMap(); |
| EXPECT_EQ(2, endpoints_by_rpcid.size()); |
| } |
| |
| TEST_F(WiFiMainTest, PendingScanEventsModifyPath) { |
| StartWiFi(); |
| BSSAdded( |
| RpcIdentifier("bss0"), |
| CreateBSSProperties( |
| "ssid0", net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 0, |
| 0, kNetworkModeInfrastructure, 0)); |
| WiFiEndpointRefPtr ap0 = MakeEndpoint( |
| "ssid0", net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); |
| |
| EXPECT_CALL(*wifi_provider(), OnEndpointAdded(EndpointMatch(ap0))); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(wifi_provider()); |
| |
| BSSRemoved(RpcIdentifier("bss0")); |
| int16_t signal_strength = 10; |
| BSSAdded( |
| RpcIdentifier("bss1"), |
| CreateBSSProperties( |
| "ssid0", net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x00), |
| signal_strength, 0, kNetworkModeInfrastructure, 0)); |
| |
| // The bssid 00:00:00:00:00:02 was removed then added back with a new path, |
| // so we don't expect its endpoint to get removed, rather we expect a change |
| // in its path/properties. |
| WiFiServiceRefPtr null_service; |
| EXPECT_CALL(*wifi_provider(), OnEndpointRemoved(EndpointMatch(ap0))).Times(0); |
| test_event_dispatcher_->DispatchPendingEvents(); |
| WiFiEndpointRefPtr endpoint = GetEndpointMap().at(RpcIdentifier("bss1")); |
| EXPECT_EQ(signal_strength, endpoint->signal_strength()); |
| Mock::VerifyAndClearExpectations(wifi_provider()); |
| |
| const WiFi::EndpointMap& endpoints_by_rpcid = GetEndpointMap(); |
| EXPECT_EQ(1, endpoints_by_rpcid.size()); |
| } |
| |
| TEST_F(WiFiMainTest, OnNewWiphy_ExcludesIndex) { |
| ScopedMockLog log; |
| // Change the NL80211_ATTR_WIPHY U32 attribute to the NL80211_ATTR_WIPHY_FREQ |
| // U32 attribute, so that this message no longer contains a phy_index to be |
| // parsed. |
| NewWiphyMessage msg; |
| net_base::MutableNetlinkPacket packet(kNewWiphyNlMsg); |
| struct nlattr* nl80211_attr_wiphy = |
| reinterpret_cast<struct nlattr*>(packet.GetMutablePayload()->data() + |
| kNewWiphyNlMsg_Nl80211AttrWiphyOffset); |
| nl80211_attr_wiphy->nla_type = NL80211_ATTR_WIPHY_FREQ; |
| msg.InitFromPacketWithContext(&packet, Nl80211Message::Context()); |
| EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); |
| EXPECT_CALL(log, Log(logging::LOGGING_ERROR, _, |
| "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY")); |
| EXPECT_CALL(*wifi_provider(), RegisterDeviceToPhy(_, _)).Times(0); |
| OnNewWiphy(msg); |
| EXPECT_CALL(*wake_on_wifi_, OnWiphyIndexReceived(_)).Times(0); |
| } |
| |
| TEST_F(WiFiMainTest, ParseFeatureFlags_RandomMacSupport) { |
| NewWiphyMessage msg; |
| net_base::NetlinkPacket packet(kNewWiphyNlMsg); |
| msg.InitFromPacketWithContext(&packet, Nl80211Message::Context()); |
| // Make sure the feature is marked unsupported |
| uint32_t flags; |
| msg.const_attributes()->GetU32AttributeValue(NL80211_ATTR_FEATURE_FLAGS, |
| &flags); |
| flags &= ~(NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR | |
| NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR); |
| msg.attributes()->SetU32AttributeValue(NL80211_ATTR_FEATURE_FLAGS, flags); |
| ParseFeatureFlags(msg); |
| EXPECT_FALSE(GetRandomMacSupported()); |
| |
| // Make sure the feature is marked supported |
| msg.const_attributes()->GetU32AttributeValue(NL80211_ATTR_FEATURE_FLAGS, |
| &flags); |
| flags |= (NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR | |
| NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR); |
| msg.attributes()->SetU32AttributeValue(NL80211_ATTR_FEATURE_FLAGS, flags); |
| ParseFeatureFlags(msg); |
| EXPECT_TRUE(GetRandomMacSupported()); |
| } |
| |
| TEST_F(WiFiMainTest, ParseCipherSuites) { |
| NewWiphyMessage msg; |
| net_base::NetlinkPacket packet(kNewWiphyNlMsg); |
| msg.InitFromPacketWithContext(&packet, Nl80211Message::Context()); |
| |
| constexpr uint8_t ciphers[] = {0x01, 0xac, 0x0f, 0x00, 0x05, 0xac, 0x0f, |
| 0x00, 0x02, 0xac, 0x0f, 0x00, 0x04, 0xac, |
| 0x0f, 0x00, 0x06, 0xac, 0x0f, 0x00}; |
| msg.attributes()->SetRawAttributeValue(NL80211_ATTR_CIPHER_SUITES, ciphers); |
| ParseCipherSuites(msg); |
| |
| EXPECT_TRUE(CipherSuiteSupported(0x000fac01)); |
| EXPECT_TRUE(CipherSuiteSupported(0x000fac05)); |
| EXPECT_TRUE(CipherSuiteSupported(0x000fac02)); |
| EXPECT_TRUE(CipherSuiteSupported(0x000fac06)); |
| EXPECT_FALSE(CipherSuiteSupported(0x000fac07)); |
| |
| // This is an empty bytes. |
| msg.attributes()->SetRawAttributeValue(NL80211_ATTR_CIPHER_SUITES, {}); |
| ParseCipherSuites(msg); |
| EXPECT_FALSE(CipherSuiteSupported(0x000fac01)); |
| EXPECT_FALSE(CipherSuiteSupported(0x000fac05)); |
| } |
| |
| TEST_F(WiFiMainTest, WEPInCipherSuites_Unsupported) { |
| NewWiphyMessage msg; |
| net_base::NetlinkPacket packet(kNewWiphyNlMsg); |
| msg.InitFromPacketWithContext(&packet, Nl80211Message::Context()); |
| EXPECT_FALSE(GetWEPSupport()); |
| // This bytes indicates support for WEP40 (0x01, 0xac, 0x0f, 0x00), but |
| // not WEP104 (0x05, 0xac, 0x0f, 0x00). |
| constexpr uint8_t ciphers_no_wep40[] = { |
| 0x01, 0xac, 0x0f, 0x00, 0x07, 0xac, 0x0f, 0x00, 0x02, 0xac, |
| 0x0f, 0x00, 0x04, 0xac, 0x0f, 0x00, 0x06, 0xac, 0x0f, 0x00}; |
| msg.attributes()->SetRawAttributeValue(NL80211_ATTR_CIPHER_SUITES, |
| ciphers_no_wep40); |
| ParseCipherSuites(msg); |
| EXPECT_FALSE(GetWEPSupport()); |
| |
| msg.InitFromPacketWithContext(&packet, Nl80211Message::Context()); |
| // This bytes indicates support for WEP104 (0x05, 0xac, 0x0f, 0x00), but |
| // not WEP40 (0x01, 0xac, 0x0f, 0x00). |
| constexpr uint8_t ciphers_no_wep104[] = { |
| 0x05, 0xac, 0x0f, 0x00, 0x07, 0xac, 0x0f, 0x00, 0x02, 0xac, |
| 0x0f, 0x00, 0x04, 0xac, 0x0f, 0x00, 0x06, 0xac, 0x0f, 0x00}; |
| msg.attributes()->SetRawAttributeValue(NL80211_ATTR_CIPHER_SUITES, |
| ciphers_no_wep104); |
| ParseCipherSuites(msg); |
| EXPECT_FALSE(GetWEPSupport()); |
| |
| msg.InitFromPacketWithContext(&packet, Nl80211Message::Context()); |
| // This bytes indicates no support for WEP40 (0x01, 0xac, 0x0f, 0x00) or |
| // WEP104 (0x05, 0xac, 0x0f, 0x00). |
| constexpr uint8_t ciphers_no_wep[] = { |
| 0x09, 0xac, 0x0f, 0x00, 0x07, 0xac, 0x0f, 0x00, 0x02, 0xac, |
| 0x0f, 0x00, 0x04, 0xac, 0x0f, 0x00, 0x06, 0xac, 0x0f, 0x00}; |
| msg.attributes()->SetRawAttributeValue(NL80211_ATTR_CIPHER_SUITES, |
| ciphers_no_wep); |
| ParseCipherSuites(msg); |
| EXPECT_FALSE(GetWEPSupport()); |
| } |
| |
| TEST_F(WiFiMainTest, WEPInCipherSuites_Supported) { |
| NewWiphyMessage msg; |
| net_base::NetlinkPacket packet(kNewWiphyNlMsg); |
| msg.InitFromPacketWithContext(&packet, Nl80211Message::Context()); |
| |
| // This bytes indicates support for WEP40 (0x01, 0xac, 0x0f, 0x00), and |
| // WEP104 (0x05, 0xac, 0x0f, 0x00). |
| constexpr uint8_t ciphers_with_wep[] = { |
| 0x01, 0xac, 0x0f, 0x00, 0x05, 0xac, 0x0f, 0x00, 0x02, 0xac, |
| 0x0f, 0x00, 0x04, 0xac, 0x0f, 0x00, 0x06, 0xac, 0x0f, 0x00}; |
| msg.attributes()->SetRawAttributeValue(NL80211_ATTR_CIPHER_SUITES, |
| ciphers_with_wep); |
| ParseCipherSuites(msg); |
| EXPECT_TRUE(GetWEPSupport()); |
| } |
| |
| TEST_F(WiFiMainTest, RandomMacProperty_Unsupported) { |
| StartWiFi(); |
| SetRandomMacSupported(false); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), |
| EnableMacAddressRandomization(_, _)) |
| .Times(0); |
| SetRandomMacEnabled(true); |
| EXPECT_FALSE(GetRandomMacEnabled()); |
| } |
| |
| TEST_F(WiFiMainTest, RandomMacProperty_Supported) { |
| StartWiFi(); |
| SetRandomMacSupported(true); |
| |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), |
| EnableMacAddressRandomization(GetRandomMacMask(), _)) |
| .Times(1); |
| SetRandomMacEnabled(true); |
| EXPECT_TRUE(GetRandomMacEnabled()); |
| |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), DisableMacAddressRandomization()) |
| .Times(1); |
| SetRandomMacEnabled(false); |
| EXPECT_FALSE(GetRandomMacEnabled()); |
| } |
| |
| TEST_F(WiFiMainTest, RandomMacProperty_SupplicantFailed) { |
| StartWiFi(); |
| SetRandomMacSupported(true); |
| |
| // Test wpa_supplicant failing to enable random MAC. |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), |
| EnableMacAddressRandomization(GetRandomMacMask(), _)) |
| .WillOnce(Return(false)); |
| SetRandomMacEnabled(true); |
| EXPECT_FALSE(GetRandomMacEnabled()); |
| |
| // Enable random MAC. |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| SetRandomMacEnabled(true); |
| |
| // Test wpa_supplicant failing to disable random MAC. |
| Mock::VerifyAndClearExpectations(GetSupplicantInterfaceProxy()); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), DisableMacAddressRandomization()) |
| .WillOnce(Return(false)); |
| SetRandomMacEnabled(false); |
| EXPECT_TRUE(GetRandomMacEnabled()); |
| } |
| |
| TEST_F(WiFiMainTest, OnScanStarted_ActiveScan) { |
| SetPhyIndex(kScanTriggerMsgPhyIndex); |
| SetWiFiPhy(new NiceMock<WiFiPhy>(kScanTriggerMsgPhyIndex)); |
| TriggerScanMessage msg; |
| net_base::NetlinkPacket packet(kActiveScanTriggerNlMsg); |
| msg.InitFromPacketWithContext(&packet, Nl80211Message::Context()); |
| EXPECT_CALL(*wake_on_wifi_, OnScanStarted(true)); |
| HandleNetlinkBroadcast(msg); |
| } |
| |
| TEST_F(WiFiMainTest, OnScanStarted_PassiveScan) { |
| SetPhyIndex(kScanTriggerMsgPhyIndex); |
| SetWiFiPhy(new NiceMock<WiFiPhy>(kScanTriggerMsgPhyIndex)); |
| TriggerScanMessage msg; |
| net_base::NetlinkPacket packet(kPassiveScanTriggerNlMsg); |
| msg.InitFromPacketWithContext(&packet, Nl80211Message::Context()); |
| EXPECT_CALL(*wake_on_wifi_, OnScanStarted(false)); |
| HandleNetlinkBroadcast(msg); |
| } |
| |
| TEST_F(WiFiMainTest, RemoveNetlinkHandler) { |
| StartWiFi(); |
| StopWiFi(); |
| // WiFi is deleted when we go out of scope. |
| EXPECT_CALL(netlink_manager_, RemoveBroadcastHandler(_)).Times(1); |
| } |
| |
| TEST_F(WiFiMainTest, OnRegChange) { |
| WiphyRegChangeMessage msg; |
| // Verify Metrics collection for the changes initiated not by the user. |
| msg.attributes()->CreateU32Attribute(NL80211_ATTR_REG_INITIATOR, "initiator"); |
| msg.attributes()->SetU32AttributeValue(NL80211_ATTR_REG_INITIATOR, |
| NL80211_REGDOM_SET_BY_DRIVER); |
| |
| msg.attributes()->CreateU8Attribute(NL80211_ATTR_REG_TYPE, "reg-type"); |
| msg.attributes()->SetU8AttributeValue(NL80211_ATTR_REG_TYPE, |
| NL80211_REGDOM_TYPE_WORLD); |
| EXPECT_CALL(*metrics(), |
| SendEnumToUMA(Metrics::kMetricRegulatoryDomain, |
| Metrics::RegulatoryDomain::kRegDom00, _)) |
| .Times(1); |
| OnRegChange(msg); |
| |
| msg.attributes()->SetU8AttributeValue(NL80211_ATTR_REG_TYPE, |
| NL80211_REGDOM_TYPE_CUSTOM_WORLD); |
| EXPECT_CALL(*metrics(), |
| SendEnumToUMA(Metrics::kMetricRegulatoryDomain, |
| Metrics::RegulatoryDomain::kRegDom99, _)) |
| .Times(1); |
| OnRegChange(msg); |
| |
| msg.attributes()->SetU8AttributeValue(NL80211_ATTR_REG_TYPE, |
| NL80211_REGDOM_TYPE_INTERSECTION); |
| EXPECT_CALL(*metrics(), |
| SendEnumToUMA(Metrics::kMetricRegulatoryDomain, |
| Metrics::RegulatoryDomain::kRegDom98, _)) |
| .Times(1); |
| OnRegChange(msg); |
| |
| msg.attributes()->SetU8AttributeValue(NL80211_ATTR_REG_TYPE, |
| NL80211_REGDOM_TYPE_COUNTRY); |
| msg.attributes()->CreateStringAttribute(NL80211_ATTR_REG_ALPHA2, "alpha2"); |
| // First valid alpha2 country code Andorra = 5. |
| msg.attributes()->SetStringAttributeValue(NL80211_ATTR_REG_ALPHA2, "AD"); |
| EXPECT_CALL(*metrics(), SendEnumToUMA(Metrics::kMetricRegulatoryDomain, 5, _)) |
| .Times(1); |
| OnRegChange(msg); |
| |
| // Lower case valid country code. United States = 540. |
| msg.attributes()->SetStringAttributeValue(NL80211_ATTR_REG_ALPHA2, "us"); |
| EXPECT_CALL(*metrics(), |
| SendEnumToUMA(Metrics::kMetricRegulatoryDomain, 540, _)) |
| .Times(1); |
| OnRegChange(msg); |
| |
| // Invalid country code. |
| msg.attributes()->SetStringAttributeValue(NL80211_ATTR_REG_ALPHA2, "err"); |
| EXPECT_CALL(*metrics(), |
| SendEnumToUMA(Metrics::kMetricRegulatoryDomain, |
| Metrics::RegulatoryDomain::kCountryCodeInvalid, _)) |
| .Times(1); |
| OnRegChange(msg); |
| |
| // Last Regulatory Domain enum entry. Zimbabwe = 674. |
| msg.attributes()->SetStringAttributeValue(NL80211_ATTR_REG_ALPHA2, "ZW"); |
| EXPECT_CALL(*metrics(), |
| SendEnumToUMA(Metrics::kMetricRegulatoryDomain, 674, _)) |
| .Times(1); |
| OnRegChange(msg); |
| // Second call with same country code should not trigger SendEnumToUMA() call. |
| EXPECT_CALL(*metrics(), SendEnumToUMA(Metrics::kMetricRegulatoryDomain, _, _)) |
| .Times(0); |
| OnRegChange(msg); |
| |
| // Now some messages that should not trigger metrics collection. |
| EXPECT_CALL(*metrics(), SendEnumToUMA(Metrics::kMetricRegulatoryDomain, _, _)) |
| .Times(0); |
| // No initiator. |
| WiphyRegChangeMessage no_metrics_msg; |
| OnRegChange(no_metrics_msg); |
| // User initiated. |
| no_metrics_msg.attributes()->CreateU32Attribute(NL80211_ATTR_REG_INITIATOR, |
| "initiator"); |
| no_metrics_msg.attributes()->SetU32AttributeValue(NL80211_ATTR_REG_INITIATOR, |
| NL80211_REGDOM_SET_BY_USER); |
| OnRegChange(no_metrics_msg); |
| |
| // Missing country. |
| no_metrics_msg.attributes()->SetU32AttributeValue( |
| NL80211_ATTR_REG_INITIATOR, NL80211_REGDOM_SET_BY_DRIVER); |
| no_metrics_msg.attributes()->CreateU8Attribute(NL80211_ATTR_REG_TYPE, |
| "reg-type"); |
| no_metrics_msg.attributes()->SetU8AttributeValue(NL80211_ATTR_REG_TYPE, |
| NL80211_REGDOM_TYPE_COUNTRY); |
| OnRegChange(no_metrics_msg); |
| |
| // Invalid country. |
| no_metrics_msg.attributes()->SetStringAttributeValue(NL80211_ATTR_REG_ALPHA2, |
| "err"); |
| OnRegChange(no_metrics_msg); |
| } |
| |
| TEST_F(WiFiMainTest, OnGetReg) { |
| GetRegMessage msg; |
| msg.attributes()->CreateStringAttribute(NL80211_ATTR_REG_ALPHA2, "alpha2"); |
| msg.attributes()->CreateU8Attribute(NL80211_ATTR_DFS_REGION, "dfs-region"); |
| |
| // First Regulatory Domain enum entry. |
| msg.attributes()->SetStringAttributeValue(NL80211_ATTR_REG_ALPHA2, "00"); |
| // Should call ChangeRegDomain with region UNSET when no dfs_region present. |
| EXPECT_CALL(*power_manager(), ChangeRegDomain(NL80211_DFS_UNSET)).Times(1); |
| OnGetReg(msg); |
| msg.attributes()->SetU8AttributeValue(NL80211_ATTR_DFS_REGION, |
| NL80211_DFS_FCC); |
| // Subsequent calls should all call ChangeRegDomain() with the current region. |
| EXPECT_CALL(*power_manager(), ChangeRegDomain(NL80211_DFS_FCC)).Times(2); |
| OnGetReg(msg); |
| OnGetReg(msg); |
| |
| msg.attributes()->SetU8AttributeValue(NL80211_ATTR_DFS_REGION, |
| NL80211_DFS_ETSI); |
| EXPECT_CALL(*power_manager(), ChangeRegDomain(NL80211_DFS_ETSI)).Times(2); |
| OnGetReg(msg); |
| OnGetReg(msg); |
| EXPECT_CALL(*power_manager(), ChangeRegDomain(NL80211_DFS_JP)).Times(1); |
| msg.attributes()->SetU8AttributeValue(NL80211_ATTR_DFS_REGION, |
| NL80211_DFS_JP); |
| OnGetReg(msg); |
| } |
| |
| TEST_F(WiFiMainTest, AddCred) { |
| MockPasspointCredentialsRefPtr creds = new MockPasspointCredentials("an_id"); |
| |
| // Supplicant not started yet: device should fail. |
| EXPECT_FALSE(AddCred(creds)); |
| EXPECT_EQ(DBusControl::NullRpcIdentifier(), creds->supplicant_id()); |
| |
| StartWiFi(); |
| |
| // Failure to convert credentials to supplicant properties. |
| EXPECT_CALL(*creds, ToSupplicantProperties(_)).WillOnce(Return(false)); |
| EXPECT_FALSE(AddCred(creds)); |
| |
| // Supplicant fails to add credentials: device should fail. |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), AddCred(_, _)) |
| .WillOnce(Return(false)); |
| EXPECT_CALL(*creds, ToSupplicantProperties(_)).WillOnce(Return(true)); |
| EXPECT_FALSE(AddCred(creds)); |
| EXPECT_EQ(DBusControl::NullRpcIdentifier(), creds->supplicant_id()); |
| |
| // Credentials added successfully. |
| RpcIdentifier path("/credentials/0"); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), AddCred(_, _)) |
| .WillOnce(DoAll(SetArgPointee<1>(path), Return(true))); |
| EXPECT_CALL(*creds, ToSupplicantProperties(_)).WillOnce(Return(true)); |
| EXPECT_TRUE(AddCred(creds)); |
| EXPECT_EQ(path, creds->supplicant_id()); |
| } |
| |
| TEST_F(WiFiMainTest, RemoveCred) { |
| RpcIdentifier path("/credentials/1"); |
| PasspointCredentialsRefPtr creds = new PasspointCredentials("an_id"); |
| |
| // Supplicant not started |
| creds->SetSupplicantId(path); |
| EXPECT_FALSE(RemoveCred(creds)); |
| EXPECT_EQ(DBusControl::NullRpcIdentifier(), creds->supplicant_id()); |
| |
| StartWiFi(); |
| |
| // Credentials with null path cannot be removed |
| creds->SetSupplicantId(DBusControl::NullRpcIdentifier()); |
| EXPECT_FALSE(RemoveCred(creds)); |
| |
| // Supplicant refuses to remove the credentials. |
| creds->SetSupplicantId(path); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveCred(path)) |
| .WillOnce(Return(false)); |
| EXPECT_FALSE(RemoveCred(creds)); |
| EXPECT_EQ(DBusControl::NullRpcIdentifier(), creds->supplicant_id()); |
| |
| // Removal is done correctly |
| creds->SetSupplicantId(path); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveCred(path)) |
| .WillOnce(Return(true)); |
| EXPECT_TRUE(RemoveCred(creds)); |
| EXPECT_EQ(DBusControl::NullRpcIdentifier(), creds->supplicant_id()); |
| } |
| |
| TEST_F(WiFiMainTest, ClearsAndRestoresCredentials) { |
| MockPasspointCredentialsRefPtr cred1 = new MockPasspointCredentials("id1"); |
| MockPasspointCredentialsRefPtr cred2 = new MockPasspointCredentials("id2"); |
| std::vector<PasspointCredentialsRefPtr> credentials{cred1, cred2}; |
| |
| // Supplicant state is cleared and the credentials we own are added. |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveAllCreds()); |
| EXPECT_CALL(*wifi_provider(), GetCredentials()).WillOnce(Return(credentials)); |
| EXPECT_CALL(*cred1, ToSupplicantProperties(_)).WillOnce(Return(true)); |
| EXPECT_CALL(*cred2, ToSupplicantProperties(_)).WillOnce(Return(true)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), AddCred(_, _)) |
| .Times(2) |
| .WillRepeatedly(Return(true)); |
| |
| StartWiFi(); |
| |
| // When supplicant is stopped, we remove our credentials. |
| EXPECT_CALL(*wifi_provider(), GetCredentials()).WillOnce(Return(credentials)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), RemoveCred(_)) |
| .Times(2) |
| .WillRepeatedly(Return(true)); |
| } |
| |
| TEST_F(WiFiMainTest, InterworkingSelectSimpleMatch) { |
| // A simple credentials set |
| MockPasspointCredentialsRefPtr cred0 = new MockPasspointCredentials("cred0"); |
| std::vector<PasspointCredentialsRefPtr> credentials{cred0}; |
| RpcIdentifier cred0_path("/creds/0"); |
| EXPECT_CALL(*cred0, ToSupplicantProperties(_)).WillRepeatedly(Return(true)); |
| EXPECT_CALL(*wifi_provider(), GetCredentials()) |
| .WillRepeatedly(Return(credentials)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), AddCred(_, _)) |
| .WillOnce(DoAll(SetArgPointee<1>(cred0_path), Return(true))); |
| |
| StartWiFi(); |
| |
| // Provide scan results |
| WiFiEndpointRefPtr ap0 = MakeEndpoint( |
| "ssid0", net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); |
| WiFiEndpointRefPtr ap1 = MakeEndpoint( |
| "ssid1", net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x01)); |
| RpcIdentifier bss0_path("bss0"), bss1_path("bss1"); |
| ReportBSS(bss0_path, ap0->ssid_string(), ap0->bssid(), 0, 0, |
| kNetworkModeInfrastructure, 0); |
| ReportBSS(bss1_path, ap1->ssid_string(), ap1->bssid(), 0, 0, |
| kNetworkModeInfrastructure, 0); |
| ReportScanDone(); |
| |
| // No credentials added, we must ignore false matches. |
| Mock::VerifyAndClearExpectations(wifi_provider()); |
| EXPECT_CALL(*wifi_provider(), GetCredentials()) |
| .WillRepeatedly(Return(credentials)); |
| EXPECT_CALL(*wifi_provider(), OnPasspointCredentialsMatches(_)).Times(0); |
| |
| KeyValueStore properties; |
| properties.Set<std::string>(WPASupplicant::kCredentialsMatchType, |
| WPASupplicant::kCredentialsMatchTypeHome); |
| ReportInterworkingAPAdded(bss0_path, RpcIdentifier("unknown_cred"), |
| properties); |
| ReportInterworkingSelectDone(); |
| |
| // Credentials set with wrong match |
| ReportInterworkingAPAdded(RpcIdentifier("unknown_bss"), cred0_path, |
| properties); |
| ReportInterworkingSelectDone(); |
| |
| // Match between credentials and BSS |
| Mock::VerifyAndClearExpectations(wifi_provider()); |
| EXPECT_CALL(*wifi_provider(), GetCredentials()) |
| .WillRepeatedly(Return(credentials)); |
| EXPECT_CALL(*wifi_provider(), OnPasspointCredentialsMatches(_)).Times(1); |
| |
| ReportInterworkingAPAdded(bss0_path, cred0_path, properties); |
| ReportInterworkingSelectDone(); |
| } |
| |
| TEST_F(WiFiMainTest, InterworkingSelectMultipleMatches) { |
| MockPasspointCredentialsRefPtr cred0 = new MockPasspointCredentials("cred0"); |
| RpcIdentifier cred0_path("/creds/0"); |
| EXPECT_CALL(*cred0, ToSupplicantProperties(_)).WillRepeatedly(Return(true)); |
| |
| MockPasspointCredentialsRefPtr cred1 = new MockPasspointCredentials("cred1"); |
| RpcIdentifier cred1_path("/creds/1"); |
| EXPECT_CALL(*cred1, ToSupplicantProperties(_)).WillRepeatedly(Return(true)); |
| |
| // The provider will provide both credentials |
| std::vector<PasspointCredentialsRefPtr> credentials{cred0, cred1}; |
| EXPECT_CALL(*wifi_provider(), GetCredentials()) |
| .WillRepeatedly(Return(credentials)); |
| EXPECT_CALL(*wifi_provider(), has_passpoint_credentials()) |
| .WillRepeatedly(Return(credentials.size())); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), AddCred(_, _)) |
| .WillOnce(DoAll(SetArgPointee<1>(cred0_path), Return(true))) |
| .WillOnce(DoAll(SetArgPointee<1>(cred1_path), Return(true))); |
| |
| StartWiFi(); |
| |
| // Provide scan results |
| WiFiEndpointRefPtr ap0 = MakeEndpoint( |
| "ssid0", net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); |
| WiFiEndpointRefPtr ap1 = MakeEndpoint( |
| "ssid1", net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x01)); |
| RpcIdentifier bss0_path("bss0"), bss1_path("bss1"); |
| ReportBSS(bss0_path, ap0->ssid_string(), ap0->bssid(), 0, 0, |
| kNetworkModeInfrastructure, 0); |
| ReportBSS(bss1_path, ap1->ssid_string(), ap1->bssid(), 0, 0, |
| kNetworkModeInfrastructure, 0); |
| ReportScanDone(); |
| |
| // Interworking select will find two matches and report them to the provider. |
| EXPECT_CALL(*wifi_provider(), OnPasspointCredentialsMatches(_)).Times(1); |
| KeyValueStore properties; |
| properties.Set<std::string>(WPASupplicant::kCredentialsMatchType, |
| WPASupplicant::kCredentialsMatchTypeHome); |
| ReportInterworkingAPAdded(bss0_path, cred0_path, properties); |
| ReportInterworkingAPAdded(bss1_path, cred1_path, properties); |
| ReportInterworkingSelectDone(); |
| } |
| |
| TEST_F(WiFiMainTest, ScanTriggersInterworkingSelect) { |
| // Ensure the provider contains credentials |
| MockPasspointCredentialsRefPtr cred0 = new MockPasspointCredentials("cred0"); |
| EXPECT_CALL(*cred0, ToSupplicantProperties(_)).WillRepeatedly(Return(true)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), AddCred(_, _)) |
| .WillOnce(Return(true)); |
| |
| std::vector<PasspointCredentialsRefPtr> credentials{cred0}; |
| EXPECT_CALL(*wifi_provider(), GetCredentials()) |
| .WillRepeatedly(Return(credentials)); |
| EXPECT_CALL(*wifi_provider(), has_passpoint_credentials()) |
| .WillRepeatedly(Return(credentials.size())); |
| |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), InterworkingSelect()); |
| |
| StartWiFi(); |
| |
| // Prepare a scan result compatible with Passpoint. |
| std::vector<uint8_t> ies; |
| std::vector<uint8_t> data = {0x20}; |
| AddVendorIE(IEEE_80211::kOUIVendorWiFiAlliance, |
| IEEE_80211::kOUITypeWiFiAllianceHS20Indicator, data, &ies); |
| RpcIdentifier bss0_path("bss0"); |
| ReportBSSWithIEs(RpcIdentifier("bss0"), "ssid0", |
| net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 0, |
| 0, kNetworkModeInfrastructure, ies); |
| |
| // When a Passpoint compatible AP is found, an interworking selection is |
| // scheduled. |
| EXPECT_TRUE(NeedInterworkingSelect()); |
| |
| ReportScanDone(); |
| } |
| |
| TEST_F(WiFiMainTest, BSSUpdateTriggersInterworkingSelect) { |
| // Ensure the provider contains credentials |
| MockPasspointCredentialsRefPtr cred0 = new MockPasspointCredentials("cred0"); |
| EXPECT_CALL(*cred0, ToSupplicantProperties(_)).WillRepeatedly(Return(true)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), AddCred(_, _)) |
| .WillOnce(Return(true)); |
| |
| std::vector<PasspointCredentialsRefPtr> credentials{cred0}; |
| EXPECT_CALL(*wifi_provider(), GetCredentials()) |
| .WillRepeatedly(Return(credentials)); |
| EXPECT_CALL(*wifi_provider(), has_passpoint_credentials()) |
| .WillRepeatedly(Return(credentials.size())); |
| |
| StartWiFi(); |
| |
| // First BSS report should not trigger a interworking select. |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), InterworkingSelect()).Times(0); |
| |
| RpcIdentifier bss0_path("bss0"); |
| ReportBSS(bss0_path, "ssid0", |
| net_base::MacAddress(0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 0, 0, |
| kNetworkModeInfrastructure, 0); |
| ReportScanDone(); |
| |
| // Update the BSS with Passpoint support, check it triggers an interworking |
| // select. |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), InterworkingSelect()).Times(1); |
| |
| std::vector<uint8_t> ies; |
| std::vector<uint8_t> data = {0x20}; |
| AddVendorIE(IEEE_80211::kOUIVendorWiFiAlliance, |
| IEEE_80211::kOUITypeWiFiAllianceHS20Indicator, data, &ies); |
| KeyValueStore properties; |
| properties.Set<std::vector<uint8_t>>(WPASupplicant::kBSSPropertyIEs, ies); |
| WiFiEndpointRefPtr endpoint = GetEndpointMap().at(bss0_path); |
| endpoint->PropertiesChanged(properties); |
| ReportScanDone(); |
| } |
| |
| TEST_F(WiFiMainTest, AddCredTriggersInterworkingSelect) { |
| StartWiFi(); |
| |
| MockPasspointCredentialsRefPtr cred0 = new MockPasspointCredentials("cred0"); |
| EXPECT_CALL(*cred0, ToSupplicantProperties(_)).WillRepeatedly(Return(true)); |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), AddCred(_, _)) |
| .WillOnce(Return(true)); |
| |
| std::vector<PasspointCredentialsRefPtr> credentials{cred0}; |
| EXPECT_CALL(*wifi_provider(), GetCredentials()) |
| .WillRepeatedly(Return(credentials)); |
| |
| EXPECT_TRUE(AddCred(cred0)); |
| // The addition of a set of credentials schedules an interworking selection. |
| EXPECT_TRUE(NeedInterworkingSelect()); |
| } |
| |
| TEST_F(WiFiMainTest, NetworkEventTransition) { |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| SetCurrentService(service); |
| RpcIdentifier connected_bss = GetSupplicantBSS(); |
| SetSupplicantBSS(connected_bss); |
| |
| KeyValueStore properties; |
| properties.Set<int32_t>(WPASupplicant::kSignalChangePropertyRSSI, -70); |
| |
| rtnl_link_stats64 stats; |
| |
| // IP configuration starts |
| ReportStateChanged(WPASupplicant::kInterfaceStateCompleted); |
| // Catch all to avoid failing on calls triggered by other events |
| // (e.g. monitoring). |
| EXPECT_CALL(*wifi_link_statistics_, UpdateNl80211LinkStatistics(_, _)) |
| .Times(AnyNumber()); |
| // One of the call to |UpdateNl80211LinkStatistics()| must correspond to the |
| // IP configuration start. |
| EXPECT_CALL(*wifi_link_statistics_, |
| UpdateNl80211LinkStatistics( |
| WiFiLinkStatistics::Trigger::kIPConfigurationStart, _)) |
| .Times(1); |
| SignalChanged(properties); |
| EXPECT_CALL(*wifi_link_statistics_, |
| UpdateRtnlLinkStatistics( |
| WiFiLinkStatistics::Trigger::kIPConfigurationStart, _)) |
| .Times(1); |
| ReportReceivedRtnlLinkStatistics(stats); |
| |
| RetrieveLinkStatistics(WiFiLinkStatistics::Trigger::kDHCPFailure); |
| |
| EXPECT_CALL( |
| *wifi_link_statistics_, |
| UpdateNl80211LinkStatistics(WiFiLinkStatistics::Trigger::kDHCPFailure, _)) |
| .Times(1); |
| SignalChanged(properties); |
| EXPECT_CALL( |
| *wifi_link_statistics_, |
| UpdateRtnlLinkStatistics(WiFiLinkStatistics::Trigger::kDHCPFailure, _)) |
| .Times(1); |
| ReportReceivedRtnlLinkStatistics(stats); |
| |
| // Test network validation failure |
| RetrieveLinkStatistics(WiFiLinkStatistics::Trigger::kNetworkValidationStart); |
| |
| EXPECT_CALL(*wifi_link_statistics_, |
| UpdateNl80211LinkStatistics( |
| WiFiLinkStatistics::Trigger::kNetworkValidationStart, _)) |
| .Times(1); |
| SignalChanged(properties); |
| EXPECT_CALL(*wifi_link_statistics_, |
| UpdateRtnlLinkStatistics( |
| WiFiLinkStatistics::Trigger::kNetworkValidationStart, _)) |
| .Times(1); |
| ReportReceivedRtnlLinkStatistics(stats); |
| |
| // DHCP failure |
| RetrieveLinkStatistics(WiFiLinkStatistics::Trigger::kDHCPFailure); |
| EXPECT_CALL( |
| *wifi_link_statistics_, |
| UpdateNl80211LinkStatistics(WiFiLinkStatistics::Trigger::kDHCPFailure, _)) |
| .Times(1); |
| SignalChanged(properties); |
| EXPECT_CALL( |
| *wifi_link_statistics_, |
| UpdateRtnlLinkStatistics(WiFiLinkStatistics::Trigger::kDHCPFailure, _)) |
| .Times(1); |
| ReportReceivedRtnlLinkStatistics(stats); |
| // SLAAC success |
| RetrieveLinkStatistics(WiFiLinkStatistics::Trigger::kSlaacFinished); |
| EXPECT_CALL(*wifi_link_statistics_, |
| UpdateNl80211LinkStatistics( |
| WiFiLinkStatistics::Trigger::kSlaacFinished, _)) |
| .Times(1); |
| SignalChanged(properties); |
| EXPECT_CALL( |
| *wifi_link_statistics_, |
| UpdateRtnlLinkStatistics(WiFiLinkStatistics::Trigger::kSlaacFinished, _)) |
| .Times(1); |
| ReportReceivedRtnlLinkStatistics(stats); |
| |
| // Network validation failure |
| RetrieveLinkStatistics( |
| WiFiLinkStatistics::Trigger::kNetworkValidationFailure); |
| EXPECT_CALL(*wifi_link_statistics_, |
| UpdateNl80211LinkStatistics( |
| WiFiLinkStatistics::Trigger::kNetworkValidationFailure, _)) |
| .Times(1); |
| SignalChanged(properties); |
| EXPECT_CALL(*wifi_link_statistics_, |
| UpdateRtnlLinkStatistics( |
| WiFiLinkStatistics::Trigger::kNetworkValidationFailure, _)) |
| .Times(1); |
| ReportReceivedRtnlLinkStatistics(stats); |
| } |
| |
| TEST_F(WiFiMainTest, GetWiFiPhy) { |
| NiceMock<WiFiPhy>* phy = new NiceMock<WiFiPhy>(kPhyIndex); |
| SetWiFiPhy(phy); |
| EXPECT_EQ(phy, GetWiFiPhy()); |
| } |
| |
| TEST_F(WiFiMainTest, ConnectStopsNetwork) { |
| StartWiFi(); |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| EXPECT_CALL(*network(), Stop()); |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| InitiateConnect(service); |
| Mock::VerifyAndClearExpectations(network()); |
| } |
| |
| TEST_F(WiFiMainTest, DisconnectStopsNetwork) { |
| StartWiFi(); |
| SetupConnectedService(RpcIdentifier(""), nullptr, nullptr); |
| EXPECT_CALL(*network(), Stop()); |
| ReportCurrentBSSChanged(RpcIdentifier(WPASupplicant::kCurrentBSSNull)); |
| Mock::VerifyAndClearExpectations(network()); |
| } |
| |
| TEST_F(WiFiMainTest, UpdateSupplicantPropertiesSuccess) { |
| Error error; |
| StartWiFi(); |
| RpcIdentifier kPath("/test/path"); |
| MockWiFiServiceRefPtr service(SetupConnectedService(kPath, nullptr, nullptr)); |
| |
| KeyValueStore kv; |
| EXPECT_CALL(*GetSupplicantNetworkProxy(), SetProperties(kv)) |
| .WillOnce(Return(true)); |
| |
| EXPECT_TRUE(UpdateSupplicantProperties(service.get(), kv, &error)); |
| EXPECT_TRUE(error.IsSuccess()); |
| } |
| |
| TEST_F(WiFiMainTest, UpdateSupplicantPropertiesFail) { |
| Error error; |
| StartWiFi(); |
| RpcIdentifier kPath("/test/path"); |
| MockWiFiServiceRefPtr service(SetupConnectedService(kPath, nullptr, nullptr)); |
| |
| KeyValueStore kv; |
| EXPECT_CALL(*GetSupplicantNetworkProxy(), SetProperties(kv)) |
| .WillOnce(Return(false)); |
| |
| EXPECT_FALSE(UpdateSupplicantProperties(service.get(), kv, &error)); |
| EXPECT_EQ(error.type(), Error::kOperationFailed); |
| } |
| |
| TEST_F(WiFiMainTest, UpdateSupplicantPropertiesNotFound) { |
| Error error; |
| StartWiFi(); |
| MockWiFiServiceRefPtr service = MakeMockService(WiFiSecurity::kNone); |
| |
| KeyValueStore kv; |
| EXPECT_FALSE(UpdateSupplicantProperties(service.get(), kv, &error)); |
| EXPECT_EQ(error.type(), Error::kNotFound); |
| } |
| |
| TEST_F(WiFiMainTest, TermsAndConditions) { |
| const std::string url = "https://example.com/terms-and-conditions"; |
| auto http_url = net_base::HttpUrl::CreateFromString(url); |
| |
| StartWiFi(); |
| |
| EXPECT_CALL(*network(), OnTermsAndConditions(_)).Times(0); |
| TermsAndConditions(""); |
| TermsAndConditions("that's not a valid URL"); |
| |
| EXPECT_CALL(*network(), OnTermsAndConditions(http_url.value())).Times(1); |
| TermsAndConditions(url); |
| } |
| |
| TEST_F(WiFiMainTest, ANQPGet) { |
| StartWiFi(); |
| |
| // Create a service with and endpoint that supports ANQP. |
| std::vector<uint8_t> ies; |
| const std::vector<uint8_t> kAdvProt{0x7f, IEEE_80211::kAdvProtANQP}; |
| AddIEWithData(IEEE_80211::kElemIdAdvertisementProtocols, kAdvProt, &ies); |
| |
| std::string ssid; |
| RpcIdentifier path; |
| net_base::MacAddress bssid; |
| WiFiEndpointRefPtr endpoint = MakeNewEndpoint(false, &ssid, &path, &bssid); |
| MockWiFiServiceRefPtr service = |
| MakeMockServiceWithSSID(endpoint->ssid(), endpoint->security_mode()); |
| EXPECT_CALL(*wifi_provider(), FindServiceForEndpoint(EndpointMatch(endpoint))) |
| .WillRepeatedly(Return(service)); |
| ON_CALL(*service, GetBSSIDConnectableEndpointCount()) |
| .WillByDefault(Return(1)); |
| ReportBSSWithIEs(path, ssid, bssid, -90, 0, kNetworkModeInfrastructure, ies); |
| |
| InitiateConnect(service); |
| ReportCurrentBSSChanged(path); |
| |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), ANQPGet(_)); |
| TriggerNetworkStart(); |
| Mock::VerifyAndClearExpectations(service.get()); |
| } |
| |
| TEST_F(WiFiMainTest, EndpointWithANQPCapsNoANQPGet) { |
| StartWiFi(); |
| |
| MockWiFiServiceRefPtr service; |
| RpcIdentifier bss_path = MakeNewEndpointAndService(-90, 0, nullptr, &service); |
| |
| // Create properties with ANQP support and capability list. |
| KeyValueStore properties, anqp_properties; |
| std::vector<uint8_t> ies, caps; |
| const std::vector<uint8_t> kAdvProt{0x7f, IEEE_80211::kAdvProtANQP}; |
| AddIEWithData(IEEE_80211::kElemIdAdvertisementProtocols, kAdvProt, &ies); |
| properties.Set<std::vector<uint8_t>>(WPASupplicant::kBSSPropertyIEs, ies); |
| AddANQPCapability(IEEE_80211::kANQPCapabilityList, &caps); |
| anqp_properties.Set<std::vector<uint8_t>>( |
| WPASupplicant::kANQPChangePropertyCapabilityList, caps); |
| properties.Set<KeyValueStore>(WPASupplicant::kBSSPropertyANQP, |
| anqp_properties); |
| |
| WiFiEndpointRefPtr endpoint = GetEndpointMap().at(bss_path); |
| endpoint->PropertiesChanged(properties); |
| |
| InitiateConnect(service); |
| ReportCurrentBSSChanged(bss_path); |
| |
| EXPECT_CALL(*GetSupplicantInterfaceProxy(), ANQPGet(_)).Times(0); |
| TriggerNetworkStart(); |
| Mock::VerifyAndClearExpectations(service.get()); |
| } |
| |
| TEST_F(WiFiMainTest, ANQPQueryDone) { |
| EXPECT_CALL(*metrics(), SendEnumToUMA(Metrics::kMetricWiFiANQPQueryResult, |
| Metrics::kANQPQueryResultUnknown)) |
| .Times(1); |
| ANQPQueryDone("", "foo"); |
| EXPECT_CALL(*metrics(), SendEnumToUMA(Metrics::kMetricWiFiANQPQueryResult, |
| Metrics::kANQPQueryResultSuccess)) |
| .Times(1); |
| ANQPQueryDone("", WPASupplicant::kANQPResultSuccess); |
| EXPECT_CALL(*metrics(), SendEnumToUMA(Metrics::kMetricWiFiANQPQueryResult, |
| Metrics::kANQPQueryResultFailure)) |
| .Times(1); |
| ANQPQueryDone("", WPASupplicant::kANQPResultFailure); |
| EXPECT_CALL(*metrics(), SendEnumToUMA(Metrics::kMetricWiFiANQPQueryResult, |
| Metrics::kANQPQueryResultInvalidFrame)) |
| .Times(1); |
| ANQPQueryDone("", WPASupplicant::kANQPResultInvalidFrame); |
| } |
| |
| TEST_F(WiFiMainTest, NotifyANQPInformationChanged) { |
| MockWiFiServiceRefPtr service; |
| RpcIdentifier bss_path = MakeNewEndpointAndService(-90, 0, nullptr, &service); |
| WiFiEndpointRefPtr endpoint = GetEndpointMap().at(bss_path); |
| |
| // For an endpoint without capabilities, no metrics should be sent. |
| EXPECT_CALL(*metrics(), SendBoolToUMA(_, _)).Times(0); |
| NotifyANQPInformationChanged(endpoint); |
| |
| // Update the endpoing with ANQP capabilities |
| KeyValueStore properties, anqp_properties; |
| std::vector<uint8_t> caps; |
| AddANQPCapability(IEEE_80211::kANQPCapabilityList, &caps); |
| AddANQPCapability(IEEE_80211::kANQPVenueName, &caps); |
| AddANQPCapability(IEEE_80211::kANQPNetworkAuthenticationType, &caps); |
| AddANQPCapability(IEEE_80211::kANQPAddressTypeAvailability, &caps); |
| AddANQPCapability(IEEE_80211::kANQPVenueURL, &caps); |
| anqp_properties.Set<std::vector<uint8_t>>( |
| WPASupplicant::kANQPChangePropertyCapabilityList, caps); |
| properties.Set<KeyValueStore>(WPASupplicant::kBSSPropertyANQP, |
| anqp_properties); |
| |
| EXPECT_CALL(*metrics(), |
| SendBoolToUMA(Metrics::kMetricANQPVenueNameSupport, true)) |
| .Times(1); |
| EXPECT_CALL(*metrics(), |
| SendBoolToUMA(Metrics::kMetricANQPNetworkAuthTypeSupport, true)) |
| .Times(1); |
| EXPECT_CALL( |
| *metrics(), |
| SendBoolToUMA(Metrics::kMetricANQPAddressTypeAvailabilitySupport, true)) |
| .Times(1); |
| EXPECT_CALL(*metrics(), |
| SendBoolToUMA(Metrics::kMetricANQPVenueURLSupport, true)) |
| .Times(1); |
| endpoint->PropertiesChanged(properties); |
| } |
| |
| TEST_F(WiFiMainTest, Priority) { |
| EXPECT_EQ(GetPriority(), WiFi::kDefaultPriority); |
| EXPECT_FALSE(SetPriority(WiFiPhy::Priority(6))); |
| EXPECT_EQ(GetPriority(), WiFi::kDefaultPriority); |
| EXPECT_TRUE(SetPriority(WiFiPhy::Priority(2))); |
| EXPECT_EQ(GetPriority(), WiFiPhy::Priority(2)); |
| } |
| |
| } // namespace shill |