You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
295 lines
11 KiB
295 lines
11 KiB
/* |
|
* Copyright (C) 2016, The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
#include <functional> |
|
#include <memory> |
|
#include <vector> |
|
|
|
#include <linux/netlink.h> |
|
#include <linux/nl80211.h> |
|
|
|
#include <gtest/gtest.h> |
|
|
|
#include "wificond/scanning/scan_result.h" |
|
#include "wificond/scanning/scan_utils.h" |
|
#include "wificond/tests/mock_netlink_manager.h" |
|
|
|
using std::bind; |
|
using std::placeholders::_1; |
|
using std::placeholders::_2; |
|
using std::unique_ptr; |
|
using std::vector; |
|
using testing::AllOf; |
|
using testing::Invoke; |
|
using testing::NiceMock; |
|
using testing::Not; |
|
using testing::Return; |
|
using testing::_; |
|
|
|
using com::android::server::wifi::wificond::NativeScanResult; |
|
|
|
namespace android { |
|
namespace wificond { |
|
|
|
namespace { |
|
|
|
constexpr uint32_t kFakeInterfaceIndex = 12; |
|
constexpr uint32_t kFakeScheduledScanIntervalMs = 20000; |
|
constexpr uint32_t kFakeSequenceNumber = 1984; |
|
constexpr int kFakeErrorCode = EIO; |
|
constexpr int32_t kFakeRssiThreshold = -80; |
|
constexpr bool kFakeUseRandomMAC = true; |
|
|
|
// Currently, control messages are only created by the kernel and sent to us. |
|
// Therefore NL80211Packet doesn't have corresponding constructor. |
|
// For test we manually create control messages using this helper function. |
|
NL80211Packet CreateControlMessageError(int error_code) { |
|
vector<uint8_t> data; |
|
data.resize(NLMSG_HDRLEN + NLA_ALIGN(sizeof(int)), 0); |
|
// Initialize length field. |
|
nlmsghdr* nl_header = reinterpret_cast<nlmsghdr*>(data.data()); |
|
nl_header->nlmsg_len = data.size(); |
|
nl_header->nlmsg_type = NLMSG_ERROR; |
|
nl_header->nlmsg_seq = kFakeSequenceNumber; |
|
nl_header->nlmsg_pid = getpid(); |
|
int* error_field = reinterpret_cast<int*>(data.data() + NLMSG_HDRLEN); |
|
*error_field = -error_code; |
|
|
|
return NL80211Packet(data); |
|
} |
|
|
|
NL80211Packet CreateControlMessageAck() { |
|
return CreateControlMessageError(0); |
|
} |
|
|
|
// This is a helper function to mock the behavior of NetlinkManager:: |
|
// SendMessageAndGetResponses() when we expect a single packet response. |
|
// |request_message| and |response| are mapped to existing parameters of |
|
// SendMessageAndGetResponses(). |
|
// |mock_response| and |mock_return value| are additional parameters used |
|
// for specifying expected results, |
|
bool AppendMessageAndReturn( |
|
NL80211Packet& mock_response, |
|
bool mock_return_value, |
|
const NL80211Packet& request_message, |
|
vector<std::unique_ptr<const NL80211Packet>>* response) { |
|
response->push_back(std::make_unique<NL80211Packet>(mock_response)); |
|
return mock_return_value; |
|
} |
|
|
|
} // namespace |
|
|
|
class ScanUtilsTest : public ::testing::Test { |
|
protected: |
|
virtual void SetUp() { |
|
ON_CALL(netlink_manager_, |
|
SendMessageAndGetResponses(_, _)).WillByDefault(Return(true)); |
|
} |
|
|
|
NiceMock<MockNetlinkManager> netlink_manager_; |
|
ScanUtils scan_utils_{&netlink_manager_}; |
|
}; |
|
|
|
MATCHER_P(DoesNL80211PacketMatchCommand, command, |
|
"Check if the netlink packet matches |command|") { |
|
return arg.GetCommand() == command; |
|
} |
|
|
|
MATCHER_P(DoesNL80211PacketHaveAttribute, attr, |
|
"Check if the netlink packet has atttribute |attr|") { |
|
return arg.HasAttribute(attr); |
|
} |
|
|
|
TEST_F(ScanUtilsTest, CanGetScanResult) { |
|
vector<NativeScanResult> scan_results; |
|
EXPECT_CALL( |
|
netlink_manager_, |
|
SendMessageAndGetResponses( |
|
DoesNL80211PacketMatchCommand(NL80211_CMD_GET_SCAN), _)); |
|
|
|
// We don't use EXPECT_TRUE here because we need to mock a complete |
|
// response for NL80211_CMD_GET_SCAN to satisfy the parsing code called |
|
// by GetScanResult. |
|
// TODO(b/34231002): Mock response for NL80211_CMD_GET_SCAN. |
|
// TODO(b/34231420): Add validation of interface index. |
|
scan_utils_.GetScanResult(kFakeInterfaceIndex, &scan_results); |
|
} |
|
|
|
TEST_F(ScanUtilsTest, CanSendScanRequest) { |
|
NL80211Packet response = CreateControlMessageAck(); |
|
EXPECT_CALL( |
|
netlink_manager_, |
|
SendMessageAndGetResponses( |
|
DoesNL80211PacketMatchCommand(NL80211_CMD_TRIGGER_SCAN), _)). |
|
WillOnce(Invoke(bind( |
|
AppendMessageAndReturn, response, true, _1, _2))); |
|
|
|
int errno_ignored; |
|
EXPECT_TRUE(scan_utils_.Scan(kFakeInterfaceIndex, kFakeUseRandomMAC, {}, {}, |
|
&errno_ignored)); |
|
// TODO(b/34231420): Add validation of requested scan ssids, threshold, |
|
// and frequencies. |
|
} |
|
|
|
TEST_F(ScanUtilsTest, CanHandleScanRequestFailure) { |
|
NL80211Packet response = CreateControlMessageError(kFakeErrorCode); |
|
EXPECT_CALL( |
|
netlink_manager_, |
|
SendMessageAndGetResponses( |
|
DoesNL80211PacketMatchCommand(NL80211_CMD_TRIGGER_SCAN), _)). |
|
WillOnce(Invoke(bind( |
|
AppendMessageAndReturn, response, true, _1, _2))); |
|
int error_code; |
|
EXPECT_FALSE(scan_utils_.Scan(kFakeInterfaceIndex, kFakeUseRandomMAC, {}, {}, |
|
&error_code)); |
|
EXPECT_EQ(kFakeErrorCode, error_code); |
|
} |
|
|
|
TEST_F(ScanUtilsTest, CanSendSchedScanRequest) { |
|
NL80211Packet response = CreateControlMessageAck(); |
|
EXPECT_CALL( |
|
netlink_manager_, |
|
SendMessageAndGetResponses( |
|
DoesNL80211PacketMatchCommand(NL80211_CMD_START_SCHED_SCAN), _)). |
|
WillOnce(Invoke(bind( |
|
AppendMessageAndReturn, response, true, _1, _2))); |
|
int errno_ignored; |
|
EXPECT_TRUE(scan_utils_.StartScheduledScan( |
|
kFakeInterfaceIndex, |
|
SchedScanIntervalSetting(), |
|
kFakeRssiThreshold, kFakeUseRandomMAC, {}, {}, {}, &errno_ignored)); |
|
// TODO(b/34231420): Add validation of requested scan ssids, threshold, |
|
// and frequencies. |
|
} |
|
|
|
TEST_F(ScanUtilsTest, CanHandleSchedScanRequestFailure) { |
|
NL80211Packet response = CreateControlMessageError(kFakeErrorCode); |
|
EXPECT_CALL( |
|
netlink_manager_, |
|
SendMessageAndGetResponses( |
|
DoesNL80211PacketMatchCommand(NL80211_CMD_START_SCHED_SCAN), _)). |
|
WillOnce(Invoke(bind( |
|
AppendMessageAndReturn, response, true, _1, _2))); |
|
int error_code; |
|
EXPECT_FALSE(scan_utils_.StartScheduledScan( |
|
kFakeInterfaceIndex, |
|
SchedScanIntervalSetting(), |
|
kFakeRssiThreshold, kFakeUseRandomMAC, {}, {}, {}, &error_code)); |
|
EXPECT_EQ(kFakeErrorCode, error_code); |
|
} |
|
|
|
TEST_F(ScanUtilsTest, CanSpecifyScanPlansForSchedScanRequest) { |
|
EXPECT_CALL( |
|
netlink_manager_, |
|
SendMessageAndGetResponses( |
|
AllOf( |
|
DoesNL80211PacketMatchCommand(NL80211_CMD_START_SCHED_SCAN), |
|
DoesNL80211PacketHaveAttribute(NL80211_ATTR_SCHED_SCAN_PLANS), |
|
Not(DoesNL80211PacketHaveAttribute( |
|
NL80211_ATTR_SCHED_SCAN_INTERVAL))), |
|
_)); |
|
int errno_ignored; |
|
SchedScanIntervalSetting interval_setting{ |
|
{{kFakeScheduledScanIntervalMs, 10 /* repeated times */}}, |
|
kFakeScheduledScanIntervalMs * 3 /* interval for infinite scans */}; |
|
|
|
scan_utils_.StartScheduledScan( |
|
kFakeInterfaceIndex, |
|
interval_setting, |
|
kFakeRssiThreshold, kFakeUseRandomMAC, {}, {}, {}, &errno_ignored); |
|
} |
|
|
|
TEST_F(ScanUtilsTest, CanSpecifySingleIntervalForSchedScanRequest) { |
|
EXPECT_CALL( |
|
netlink_manager_, |
|
SendMessageAndGetResponses( |
|
AllOf( |
|
DoesNL80211PacketMatchCommand(NL80211_CMD_START_SCHED_SCAN), |
|
DoesNL80211PacketHaveAttribute(NL80211_ATTR_SCHED_SCAN_INTERVAL), |
|
Not(DoesNL80211PacketHaveAttribute( |
|
NL80211_ATTR_SCHED_SCAN_PLANS))), |
|
_)); |
|
int errno_ignored; |
|
SchedScanIntervalSetting interval_setting{{}, kFakeScheduledScanIntervalMs}; |
|
|
|
scan_utils_.StartScheduledScan( |
|
kFakeInterfaceIndex, |
|
interval_setting, |
|
kFakeRssiThreshold, kFakeUseRandomMAC, {}, {}, {}, &errno_ignored); |
|
} |
|
|
|
TEST_F(ScanUtilsTest, CanPrioritizeLastSeenSinceBootNetlinkAttribute) { |
|
constexpr uint64_t kLastSeenTimestampNanoSeconds = 123456; |
|
constexpr uint64_t kBssTsfTimestampMicroSeconds = 654321; |
|
NL80211NestedAttr bss(NL80211_ATTR_BSS); |
|
bss.AddAttribute( |
|
NL80211Attr<uint64_t>(NL80211_BSS_LAST_SEEN_BOOTTIME, |
|
kLastSeenTimestampNanoSeconds)); |
|
bss.AddAttribute( |
|
NL80211Attr<uint64_t>(NL80211_BSS_TSF, kBssTsfTimestampMicroSeconds)); |
|
uint64_t timestamp_microseconds; |
|
EXPECT_TRUE(scan_utils_.GetBssTimestampForTesting( |
|
bss, ×tamp_microseconds)); |
|
EXPECT_EQ(kLastSeenTimestampNanoSeconds/1000, timestamp_microseconds); |
|
} |
|
|
|
TEST_F(ScanUtilsTest, CanHandleMissingLastSeenSinceBootNetlinkAttribute) { |
|
constexpr uint64_t kBssTsfTimestampMicroSeconds = 654321; |
|
NL80211NestedAttr bss(NL80211_ATTR_BSS); |
|
bss.AddAttribute( |
|
NL80211Attr<uint64_t>(NL80211_BSS_TSF, kBssTsfTimestampMicroSeconds)); |
|
uint64_t timestamp_microseconds; |
|
EXPECT_TRUE(scan_utils_.GetBssTimestampForTesting( |
|
bss, ×tamp_microseconds)); |
|
EXPECT_EQ(kBssTsfTimestampMicroSeconds, timestamp_microseconds); |
|
} |
|
|
|
// Probe TSF is newer. |
|
TEST_F(ScanUtilsTest, CanPickMostRecentTimestampBetweenBetweenProbeAndBeacon1) { |
|
constexpr uint64_t kBssBeaconTsfTimestampMicroSeconds = 654321; |
|
constexpr uint64_t kBssTsfTimestampMicroSeconds = |
|
kBssBeaconTsfTimestampMicroSeconds + 2000; |
|
NL80211NestedAttr bss(NL80211_ATTR_BSS); |
|
bss.AddAttribute( |
|
NL80211Attr<uint64_t>(NL80211_BSS_BEACON_TSF, |
|
kBssBeaconTsfTimestampMicroSeconds)); |
|
bss.AddAttribute( |
|
NL80211Attr<uint64_t>(NL80211_BSS_TSF, kBssTsfTimestampMicroSeconds)); |
|
uint64_t timestamp_microseconds; |
|
EXPECT_TRUE(scan_utils_.GetBssTimestampForTesting( |
|
bss, ×tamp_microseconds)); |
|
EXPECT_EQ(kBssTsfTimestampMicroSeconds, timestamp_microseconds); |
|
} |
|
|
|
// Beacon TSF is newer. |
|
TEST_F(ScanUtilsTest, CanPickMostRecentTimestampBetweenBetweenProbeAndBeacon2) { |
|
constexpr uint64_t kBssTsfTimestampMicroSeconds = 654321; |
|
constexpr uint64_t kBssBeaconTsfTimestampMicroSeconds = |
|
kBssTsfTimestampMicroSeconds + 2000; |
|
NL80211NestedAttr bss(NL80211_ATTR_BSS); |
|
bss.AddAttribute( |
|
NL80211Attr<uint64_t>(NL80211_BSS_BEACON_TSF, |
|
kBssBeaconTsfTimestampMicroSeconds)); |
|
bss.AddAttribute( |
|
NL80211Attr<uint64_t>(NL80211_BSS_TSF, kBssTsfTimestampMicroSeconds)); |
|
uint64_t timestamp_microseconds; |
|
EXPECT_TRUE(scan_utils_.GetBssTimestampForTesting( |
|
bss, ×tamp_microseconds)); |
|
EXPECT_EQ(kBssBeaconTsfTimestampMicroSeconds, timestamp_microseconds); |
|
} |
|
|
|
} // namespace wificond |
|
} // namespace android
|
|
|