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.
442 lines
16 KiB
442 lines
16 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 <gtest/gtest.h>
|
|
|
|
#include "android/net/wifi/nl80211/IWifiScannerImpl.h"
|
|
#include "wificond/net/kernel-header-latest/nl80211.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 android::net::wifi::nl80211::IWifiScannerImpl;
|
|
using android::net::wifi::nl80211::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 kFake2gRssiThreshold = -80;
|
|
constexpr int32_t kFake5gRssiThreshold = -77;
|
|
constexpr int32_t kFake6gRssiThreshold = -77;
|
|
constexpr bool kFakeUseRandomMAC = true;
|
|
constexpr bool kFakeRequestLowPower = true;
|
|
constexpr bool kFakeRequestSchedScanRelativeRssi = true;
|
|
constexpr int kFakeScanType = IWifiScannerImpl::SCAN_TYPE_LOW_SPAN;
|
|
|
|
// 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);
|
|
}
|
|
|
|
MATCHER_P2(DoesNL80211PacketHaveAttributeWithUint32Value, attr, expected_value,
|
|
"Check if the netlink packet has atttribute |attr| with "
|
|
"|expected_value|") {
|
|
uint32_t actual_value;
|
|
if (!arg.GetAttributeValue(attr, &actual_value)) {
|
|
return false;
|
|
}
|
|
return actual_value == expected_value;
|
|
}
|
|
|
|
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,
|
|
kFakeScanType, false, {}, {}, &errno_ignored));
|
|
// TODO(b/34231420): Add validation of requested scan ssids, threshold,
|
|
// and frequencies.
|
|
}
|
|
|
|
TEST_F(ScanUtilsTest, CanSendScanRequestWithRandomAddr) {
|
|
NL80211Packet response = CreateControlMessageAck();
|
|
EXPECT_CALL(
|
|
netlink_manager_,
|
|
SendMessageAndGetResponses(
|
|
AllOf(
|
|
DoesNL80211PacketMatchCommand(NL80211_CMD_TRIGGER_SCAN),
|
|
DoesNL80211PacketHaveAttributeWithUint32Value(
|
|
NL80211_ATTR_SCAN_FLAGS, NL80211_SCAN_FLAG_RANDOM_ADDR)),
|
|
_)).
|
|
WillOnce(Invoke(bind(AppendMessageAndReturn, response, true, _1, _2)));
|
|
|
|
int errno_ignored;
|
|
EXPECT_TRUE(scan_utils_.Scan(kFakeInterfaceIndex, true,
|
|
IWifiScannerImpl::SCAN_TYPE_DEFAULT,
|
|
false, {}, {}, &errno_ignored));
|
|
}
|
|
|
|
TEST_F(ScanUtilsTest, CanSendScanRequestForLowSpanScan) {
|
|
NL80211Packet response = CreateControlMessageAck();
|
|
EXPECT_CALL(
|
|
netlink_manager_,
|
|
SendMessageAndGetResponses(
|
|
AllOf(
|
|
DoesNL80211PacketMatchCommand(NL80211_CMD_TRIGGER_SCAN),
|
|
DoesNL80211PacketHaveAttributeWithUint32Value(
|
|
NL80211_ATTR_SCAN_FLAGS,
|
|
static_cast<uint32_t>(NL80211_SCAN_FLAG_LOW_SPAN |
|
|
NL80211_SCAN_FLAG_COLOCATED_6GHZ))),
|
|
_)).
|
|
WillOnce(Invoke(bind(AppendMessageAndReturn, response, true, _1, _2)));
|
|
|
|
int errno_ignored;
|
|
EXPECT_TRUE(scan_utils_.Scan(kFakeInterfaceIndex, false,
|
|
IWifiScannerImpl::SCAN_TYPE_LOW_SPAN,
|
|
true, {}, {}, &errno_ignored));
|
|
}
|
|
|
|
TEST_F(ScanUtilsTest, CanSendScanRequestForLowPowerScan) {
|
|
NL80211Packet response = CreateControlMessageAck();
|
|
EXPECT_CALL(
|
|
netlink_manager_,
|
|
SendMessageAndGetResponses(
|
|
AllOf(
|
|
DoesNL80211PacketMatchCommand(NL80211_CMD_TRIGGER_SCAN),
|
|
DoesNL80211PacketHaveAttributeWithUint32Value(
|
|
NL80211_ATTR_SCAN_FLAGS, NL80211_SCAN_FLAG_LOW_POWER)),
|
|
_)).
|
|
WillOnce(Invoke(bind(AppendMessageAndReturn, response, true, _1, _2)));
|
|
|
|
int errno_ignored;
|
|
EXPECT_TRUE(scan_utils_.Scan(kFakeInterfaceIndex, false,
|
|
IWifiScannerImpl::SCAN_TYPE_LOW_POWER,
|
|
false, {}, {}, &errno_ignored));
|
|
}
|
|
|
|
TEST_F(ScanUtilsTest, CanSendScanRequestForHighAccuracyScan) {
|
|
NL80211Packet response = CreateControlMessageAck();
|
|
EXPECT_CALL(
|
|
netlink_manager_,
|
|
SendMessageAndGetResponses(
|
|
AllOf(
|
|
DoesNL80211PacketMatchCommand(NL80211_CMD_TRIGGER_SCAN),
|
|
DoesNL80211PacketHaveAttributeWithUint32Value(
|
|
NL80211_ATTR_SCAN_FLAGS, NL80211_SCAN_FLAG_HIGH_ACCURACY)),
|
|
_)).
|
|
WillOnce(Invoke(bind(AppendMessageAndReturn, response, true, _1, _2)));
|
|
|
|
int errno_ignored;
|
|
EXPECT_TRUE(scan_utils_.Scan(kFakeInterfaceIndex, false,
|
|
IWifiScannerImpl::SCAN_TYPE_HIGH_ACCURACY,
|
|
false, {}, {}, &errno_ignored));
|
|
}
|
|
|
|
TEST_F(ScanUtilsTest, CanSendScanRequestForHighAccuracyScanWithRandomAddr) {
|
|
NL80211Packet response = CreateControlMessageAck();
|
|
EXPECT_CALL(
|
|
netlink_manager_,
|
|
SendMessageAndGetResponses(
|
|
AllOf(
|
|
DoesNL80211PacketMatchCommand(NL80211_CMD_TRIGGER_SCAN),
|
|
DoesNL80211PacketHaveAttributeWithUint32Value(
|
|
NL80211_ATTR_SCAN_FLAGS,
|
|
static_cast<uint32_t>(NL80211_SCAN_FLAG_RANDOM_ADDR |
|
|
NL80211_SCAN_FLAG_HIGH_ACCURACY))),
|
|
_)).
|
|
WillOnce(Invoke(bind(AppendMessageAndReturn, response, true, _1, _2)));
|
|
|
|
int errno_ignored;
|
|
EXPECT_TRUE(scan_utils_.Scan(kFakeInterfaceIndex, true,
|
|
IWifiScannerImpl::SCAN_TYPE_HIGH_ACCURACY,
|
|
false, {}, {}, &errno_ignored));
|
|
}
|
|
|
|
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,
|
|
kFakeScanType, false, {}, {}, &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)));
|
|
|
|
const SchedScanReqFlags req_flags = {
|
|
kFakeUseRandomMAC, kFakeRequestLowPower, kFakeRequestSchedScanRelativeRssi
|
|
};
|
|
int errno_ignored;
|
|
EXPECT_TRUE(scan_utils_.StartScheduledScan(
|
|
kFakeInterfaceIndex,
|
|
SchedScanIntervalSetting(),
|
|
kFake2gRssiThreshold, kFake5gRssiThreshold, kFake6gRssiThreshold, req_flags, {}, {}, {},
|
|
&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)));
|
|
const SchedScanReqFlags req_flags = {
|
|
kFakeUseRandomMAC, kFakeRequestLowPower, kFakeRequestSchedScanRelativeRssi
|
|
};
|
|
int error_code;
|
|
EXPECT_FALSE(scan_utils_.StartScheduledScan(
|
|
kFakeInterfaceIndex,
|
|
SchedScanIntervalSetting(),
|
|
kFake2gRssiThreshold, kFake5gRssiThreshold, kFake6gRssiThreshold,
|
|
req_flags, {}, {}, {}, &error_code));
|
|
EXPECT_EQ(kFakeErrorCode, error_code);
|
|
}
|
|
|
|
TEST_F(ScanUtilsTest, CanSendSchedScanRequestForLowPowerScan) {
|
|
NL80211Packet response = CreateControlMessageAck();
|
|
EXPECT_CALL(
|
|
netlink_manager_,
|
|
SendMessageAndGetResponses(
|
|
AllOf(
|
|
DoesNL80211PacketMatchCommand(NL80211_CMD_START_SCHED_SCAN),
|
|
DoesNL80211PacketHaveAttributeWithUint32Value(
|
|
NL80211_ATTR_SCAN_FLAGS, NL80211_SCAN_FLAG_LOW_POWER)),
|
|
_));
|
|
int errno_ignored;
|
|
const SchedScanReqFlags req_flags = {
|
|
false, true, false
|
|
};
|
|
scan_utils_.StartScheduledScan(
|
|
kFakeInterfaceIndex,
|
|
SchedScanIntervalSetting(),
|
|
kFake2gRssiThreshold, kFake5gRssiThreshold, kFake6gRssiThreshold,
|
|
req_flags, {}, {}, {}, &errno_ignored);
|
|
}
|
|
|
|
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 */};
|
|
const SchedScanReqFlags req_flags = {
|
|
kFakeUseRandomMAC, kFakeRequestLowPower, kFakeRequestSchedScanRelativeRssi
|
|
};
|
|
scan_utils_.StartScheduledScan(
|
|
kFakeInterfaceIndex,
|
|
interval_setting,
|
|
kFake2gRssiThreshold, kFake5gRssiThreshold, kFake6gRssiThreshold,
|
|
req_flags, {}, {}, {}, &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};
|
|
const SchedScanReqFlags req_flags = {
|
|
kFakeUseRandomMAC, kFakeRequestLowPower, kFakeRequestSchedScanRelativeRssi
|
|
};
|
|
scan_utils_.StartScheduledScan(
|
|
kFakeInterfaceIndex,
|
|
interval_setting,
|
|
kFake2gRssiThreshold, kFake5gRssiThreshold, kFake6gRssiThreshold,
|
|
req_flags, {}, {}, {}, &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
|