blob: 4e1e2c0c95df62823be27152d65dec71699bb338 [file] [log] [blame]
//
// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "apmanager/config.h"
#include <string>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#if !defined(__ANDROID__)
#include <chromeos/dbus/service_constants.h>
#else
#include "dbus/apmanager/dbus-constants.h"
#endif
#include "apmanager/error.h"
#include "apmanager/fake_config_adaptor.h"
#include "apmanager/fake_device_adaptor.h"
#include "apmanager/mock_control.h"
#include "apmanager/mock_device.h"
#include "apmanager/mock_manager.h"
using ::testing::_;
using ::testing::Mock;
using ::testing::Return;
using ::testing::ReturnNew;
using ::testing::SetArgPointee;
namespace apmanager {
namespace {
const char kSsid[] = "TestSsid";
const char kInterface[] = "uap0";
const char kBridgeInterface[] = "br0";
const char kControlInterfacePath[] = "/run/apmanager/hostapd/ctrl_iface";
const char kPassphrase[] = "Passphrase";
const char k24GHzHTCapab[] = "[LDPC SMPS-STATIC GF SHORT-GI-20]";
const char k5GHzHTCapab[] =
"[LDPC HT40+ SMPS-STATIC GF SHORT-GI-20 SHORT-GI-40]";
const uint16_t k24GHzChannel = 6;
const uint16_t k5GHzChannel = 36;
const char kExpected80211gConfigContent[] = "ssid=TestSsid\n"
"channel=6\n"
"interface=uap0\n"
"hw_mode=g\n"
"driver=nl80211\n"
"fragm_threshold=2346\n"
"rts_threshold=2347\n";
const char kExpected80211gBridgeConfigContent[] = "ssid=TestSsid\n"
"bridge=br0\n"
"channel=6\n"
"interface=uap0\n"
"hw_mode=g\n"
"driver=nl80211\n"
"fragm_threshold=2346\n"
"rts_threshold=2347\n";
const char kExpected80211gCtrlIfaceConfigContent[] =
"ssid=TestSsid\n"
"channel=6\n"
"interface=uap0\n"
"hw_mode=g\n"
"ctrl_interface=/run/apmanager/hostapd/ctrl_iface\n"
#if !defined(__ANDROID__)
"ctrl_interface_group=apmanager\n"
#else
"ctrl_interface_group=system\n"
#endif // __ANDROID__
"driver=nl80211\n"
"fragm_threshold=2346\n"
"rts_threshold=2347\n";
const char kExpected80211n5GHzConfigContent[] =
"ssid=TestSsid\n"
"channel=36\n"
"interface=uap0\n"
"ieee80211n=1\n"
"ht_capab=[LDPC HT40+ SMPS-STATIC GF SHORT-GI-20 SHORT-GI-40]\n"
"hw_mode=a\n"
"driver=nl80211\n"
"fragm_threshold=2346\n"
"rts_threshold=2347\n";
const char kExpected80211n24GHzConfigContent[] =
"ssid=TestSsid\n"
"channel=6\n"
"interface=uap0\n"
"ieee80211n=1\n"
"ht_capab=[LDPC SMPS-STATIC GF SHORT-GI-20]\n"
"hw_mode=g\n"
"driver=nl80211\n"
"fragm_threshold=2346\n"
"rts_threshold=2347\n";
const char kExpectedRsnConfigContent[] = "ssid=TestSsid\n"
"channel=6\n"
"interface=uap0\n"
"hw_mode=g\n"
"wpa=2\n"
"rsn_pairwise=CCMP\n"
"wpa_key_mgmt=WPA-PSK\n"
"wpa_passphrase=Passphrase\n"
"driver=nl80211\n"
"fragm_threshold=2346\n"
"rts_threshold=2347\n";
} // namespace
class ConfigTest : public testing::Test {
public:
ConfigTest()
: manager_(&control_interface_) {
ON_CALL(control_interface_, CreateDeviceAdaptorRaw())
.WillByDefault(ReturnNew<FakeDeviceAdaptor>());
ON_CALL(control_interface_, CreateConfigAdaptorRaw())
.WillByDefault(ReturnNew<FakeConfigAdaptor>());
// Defer creation of Config object to allow ControlInterface to setup
// expectations for generating fake adaptors.
config_.reset(new Config(&manager_, 0));
}
void SetupDevice(const std::string& interface) {
// Setup mock device.
device_ = new MockDevice(&manager_);
device_->SetPreferredApInterface(interface);
EXPECT_CALL(manager_, GetDeviceFromInterfaceName(interface))
.WillRepeatedly(Return(device_));
}
void VerifyError(const Error& error,
Error::Type expected_type,
const std::string& expected_message_start) {
EXPECT_EQ(expected_type, error.type());
EXPECT_TRUE(base::StartsWith(error.message(), expected_message_start,
base::CompareCase::INSENSITIVE_ASCII));
}
protected:
MockControl control_interface_;
MockManager manager_;
scoped_refptr<MockDevice> device_;
std::unique_ptr<Config> config_;
};
TEST_F(ConfigTest, GetFrequencyFromChannel) {
uint32_t frequency;
// Invalid channel.
EXPECT_FALSE(Config::GetFrequencyFromChannel(0, &frequency));
EXPECT_FALSE(Config::GetFrequencyFromChannel(166, &frequency));
EXPECT_FALSE(Config::GetFrequencyFromChannel(14, &frequency));
EXPECT_FALSE(Config::GetFrequencyFromChannel(33, &frequency));
// Valid channel.
const uint32_t kChannel1Frequency = 2412;
const uint32_t kChannel13Frequency = 2472;
const uint32_t kChannel34Frequency = 5170;
const uint32_t kChannel165Frequency = 5825;
EXPECT_TRUE(Config::GetFrequencyFromChannel(1, &frequency));
EXPECT_EQ(kChannel1Frequency, frequency);
EXPECT_TRUE(Config::GetFrequencyFromChannel(13, &frequency));
EXPECT_EQ(kChannel13Frequency, frequency);
EXPECT_TRUE(Config::GetFrequencyFromChannel(34, &frequency));
EXPECT_EQ(kChannel34Frequency, frequency);
EXPECT_TRUE(Config::GetFrequencyFromChannel(165, &frequency));
EXPECT_EQ(kChannel165Frequency, frequency);
}
TEST_F(ConfigTest, ValidateSsid) {
Error error;
// SSID must contain between 1 and 32 characters.
EXPECT_TRUE(config_->ValidateSsid(&error, "s"));
EXPECT_TRUE(config_->ValidateSsid(&error, std::string(32, 'c')));
EXPECT_FALSE(config_->ValidateSsid(&error, ""));
EXPECT_FALSE(config_->ValidateSsid(&error, std::string(33, 'c')));
}
TEST_F(ConfigTest, ValidateSecurityMode) {
Error error;
EXPECT_TRUE(config_->ValidateSecurityMode(&error, kSecurityModeNone));
EXPECT_TRUE(config_->ValidateSecurityMode(&error, kSecurityModeRSN));
EXPECT_FALSE(config_->ValidateSecurityMode(&error, "InvalidSecurityMode"));
}
TEST_F(ConfigTest, ValidatePassphrase) {
Error error;
// Passpharse must contain between 8 and 63 characters.
EXPECT_TRUE(config_->ValidatePassphrase(&error, std::string(8, 'c')));
EXPECT_TRUE(config_->ValidatePassphrase(&error, std::string(63, 'c')));
EXPECT_FALSE(config_->ValidatePassphrase(&error, std::string(7, 'c')));
EXPECT_FALSE(config_->ValidatePassphrase(&error, std::string(64, 'c')));
}
TEST_F(ConfigTest, ValidateHwMode) {
Error error;
EXPECT_TRUE(config_->ValidateHwMode(&error, kHwMode80211a));
EXPECT_TRUE(config_->ValidateHwMode(&error, kHwMode80211b));
EXPECT_TRUE(config_->ValidateHwMode(&error, kHwMode80211g));
EXPECT_TRUE(config_->ValidateHwMode(&error, kHwMode80211n));
EXPECT_TRUE(config_->ValidateHwMode(&error, kHwMode80211ac));
EXPECT_FALSE(config_->ValidateSecurityMode(&error, "InvalidHwMode"));
}
TEST_F(ConfigTest, ValidateOperationMode) {
Error error;
EXPECT_TRUE(config_->ValidateOperationMode(&error, kOperationModeServer));
EXPECT_TRUE(config_->ValidateOperationMode(&error, kOperationModeBridge));
EXPECT_FALSE(config_->ValidateOperationMode(&error, "InvalidMode"));
}
TEST_F(ConfigTest, ValidateChannel) {
Error error;
EXPECT_TRUE(config_->ValidateChannel(&error, 1));
EXPECT_TRUE(config_->ValidateChannel(&error, 13));
EXPECT_TRUE(config_->ValidateChannel(&error, 34));
EXPECT_TRUE(config_->ValidateChannel(&error, 165));
EXPECT_FALSE(config_->ValidateChannel(&error, 0));
EXPECT_FALSE(config_->ValidateChannel(&error, 14));
EXPECT_FALSE(config_->ValidateChannel(&error, 33));
EXPECT_FALSE(config_->ValidateChannel(&error, 166));
}
TEST_F(ConfigTest, NoSsid) {
config_->SetChannel(k24GHzChannel);
config_->SetHwMode(kHwMode80211g);
config_->SetInterfaceName(kInterface);
std::string config_content;
Error error;
EXPECT_FALSE(config_->GenerateConfigFile(&error, &config_content));
VerifyError(error, Error::kInvalidConfiguration, "SSID not specified");
}
TEST_F(ConfigTest, NoInterface) {
// Basic 80211.g configuration.
config_->SetSsid(kSsid);
config_->SetChannel(k24GHzChannel);
config_->SetHwMode(kHwMode80211g);
// No device available, fail to generate config file.
Error error;
std::string config_content;
EXPECT_CALL(manager_, GetAvailableDevice()).WillOnce(Return(nullptr));
EXPECT_FALSE(config_->GenerateConfigFile(&error, &config_content));
VerifyError(error, Error::kInternalError, "No device available");
Mock::VerifyAndClearExpectations(&manager_);
// Device available, config file should be generated without any problem.
scoped_refptr<MockDevice> device = new MockDevice(&manager_);
device->SetPreferredApInterface(kInterface);
error.Reset();
EXPECT_CALL(manager_, GetAvailableDevice()).WillOnce(Return(device));
EXPECT_TRUE(config_->GenerateConfigFile(&error, &config_content));
EXPECT_NE(std::string::npos, config_content.find(
kExpected80211gConfigContent))
<< "Expected to find the following config...\n"
<< kExpected80211gConfigContent << "..within content...\n"
<< config_content;
EXPECT_TRUE(error.IsSuccess());
Mock::VerifyAndClearExpectations(&manager_);
}
TEST_F(ConfigTest, InvalidInterface) {
// Basic 80211.g configuration.
config_->SetSsid(kSsid);
config_->SetChannel(k24GHzChannel);
config_->SetHwMode(kHwMode80211g);
config_->SetInterfaceName(kInterface);
// Unable to find the device, fail to generate config file.
Error error;
std::string config_content;
EXPECT_CALL(manager_, GetDeviceFromInterfaceName(kInterface))
.WillOnce(Return(nullptr));
EXPECT_FALSE(config_->GenerateConfigFile(&error, &config_content));
VerifyError(error,
Error::kInvalidConfiguration,
"Unable to find device for the specified interface");
Mock::VerifyAndClearExpectations(&manager_);
}
TEST_F(ConfigTest, BridgeMode) {
config_->SetSsid(kSsid);
config_->SetChannel(k24GHzChannel);
config_->SetHwMode(kHwMode80211g);
config_->SetInterfaceName(kInterface);
config_->SetOperationMode(kOperationModeBridge);
// Bridge interface required for bridge mode.
Error error;
std::string config_content;
EXPECT_FALSE(config_->GenerateConfigFile(&error, &config_content));
VerifyError(
error, Error::kInvalidConfiguration, "Bridge interface not specified");
// Set bridge interface, config file should be generated without error.
config_->SetBridgeInterface(kBridgeInterface);
// Setup mock device.
SetupDevice(kInterface);
error.Reset();
std::string config_content1;
EXPECT_TRUE(config_->GenerateConfigFile(&error, &config_content1));
EXPECT_NE(std::string::npos, config_content1.find(
kExpected80211gBridgeConfigContent))
<< "Expected to find the following config...\n"
<< kExpected80211gBridgeConfigContent << "..within content...\n"
<< config_content1;
EXPECT_TRUE(error.IsSuccess());
}
TEST_F(ConfigTest, 80211gConfig) {
config_->SetSsid(kSsid);
config_->SetChannel(k24GHzChannel);
config_->SetHwMode(kHwMode80211g);
config_->SetInterfaceName(kInterface);
// Setup mock device.
SetupDevice(kInterface);
std::string config_content;
Error error;
EXPECT_TRUE(config_->GenerateConfigFile(&error, &config_content));
EXPECT_NE(std::string::npos, config_content.find(
kExpected80211gConfigContent))
<< "Expected to find the following config...\n"
<< kExpected80211gConfigContent << "..within content...\n"
<< config_content;
EXPECT_TRUE(error.IsSuccess());
}
TEST_F(ConfigTest, 80211gConfigWithControlInterface) {
config_->SetSsid(kSsid);
config_->SetChannel(k24GHzChannel);
config_->SetHwMode(kHwMode80211g);
config_->SetInterfaceName(kInterface);
config_->set_control_interface(kControlInterfacePath);
// Setup mock device.
SetupDevice(kInterface);
std::string config_content;
Error error;
EXPECT_TRUE(config_->GenerateConfigFile(&error, &config_content));
EXPECT_NE(std::string::npos, config_content.find(
kExpected80211gCtrlIfaceConfigContent))
<< "Expected to find the following config...\n"
<< kExpected80211gCtrlIfaceConfigContent << "..within content...\n"
<< config_content;
EXPECT_TRUE(error.IsSuccess());
}
TEST_F(ConfigTest, 80211nConfig) {
config_->SetSsid(kSsid);
config_->SetHwMode(kHwMode80211n);
config_->SetInterfaceName(kInterface);
// Setup mock device.
SetupDevice(kInterface);
// 5GHz channel.
config_->SetChannel(k5GHzChannel);
std::string ghz5_config_content;
Error error;
std::string ht_capab_5ghz(k5GHzHTCapab);
EXPECT_CALL(*device_.get(), GetHTCapability(k5GHzChannel, _))
.WillOnce(DoAll(SetArgPointee<1>(ht_capab_5ghz), Return(true)));
EXPECT_TRUE(config_->GenerateConfigFile(&error, &ghz5_config_content));
EXPECT_NE(std::string::npos, ghz5_config_content.find(
kExpected80211n5GHzConfigContent))
<< "Expected to find the following config...\n"
<< kExpected80211n5GHzConfigContent << "..within content...\n"
<< ghz5_config_content;
EXPECT_TRUE(error.IsSuccess());
Mock::VerifyAndClearExpectations(device_.get());
// 2.4GHz channel.
config_->SetChannel(k24GHzChannel);
std::string ghz24_config_content;
error.Reset();
std::string ht_capab_24ghz(k24GHzHTCapab);
EXPECT_CALL(*device_.get(), GetHTCapability(k24GHzChannel, _))
.WillOnce(DoAll(SetArgPointee<1>(ht_capab_24ghz), Return(true)));
EXPECT_TRUE(config_->GenerateConfigFile(&error, &ghz24_config_content));
EXPECT_NE(std::string::npos, ghz24_config_content.find(
kExpected80211n24GHzConfigContent))
<< "Expected to find the following config...\n"
<< kExpected80211n24GHzConfigContent << "..within content...\n"
<< ghz24_config_content;
EXPECT_TRUE(error.IsSuccess());
Mock::VerifyAndClearExpectations(device_.get());
}
TEST_F(ConfigTest, RsnConfig) {
config_->SetSsid(kSsid);
config_->SetChannel(k24GHzChannel);
config_->SetHwMode(kHwMode80211g);
config_->SetInterfaceName(kInterface);
config_->SetSecurityMode(kSecurityModeRSN);
// Setup mock device.
SetupDevice(kInterface);
// Failed due to no passphrase specified.
std::string config_content;
Error error;
EXPECT_FALSE(config_->GenerateConfigFile(&error, &config_content));
VerifyError(
error,
Error::kInvalidConfiguration,
base::StringPrintf("Passphrase not set for security mode: %s",
kSecurityModeRSN));
error.Reset();
config_->SetPassphrase(kPassphrase);
EXPECT_TRUE(config_->GenerateConfigFile(&error, &config_content));
EXPECT_NE(std::string::npos, config_content.find(
kExpectedRsnConfigContent))
<< "Expected to find the following config...\n"
<< kExpectedRsnConfigContent << "..within content...\n"
<< config_content;
EXPECT_TRUE(error.IsSuccess());
}
} // namespace apmanager