blob: 665cba97fcf5848023c71e8f11f21ae865440911 [file] [log] [blame]
// Copyright 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "apmanager/config.h"
#include <string>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include <chromeos/dbus/service_constants.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "apmanager/mock_device.h"
#include "apmanager/mock_manager.h"
using ::testing::_;
using ::testing::Mock;
using ::testing::Return;
using ::testing::SetArgumentPointee;
namespace apmanager {
namespace {
const char kServicePath[] = "/manager/services/0";
const char kSsid[] = "TestSsid";
const char kInterface[] = "uap0";
const char kBridgeInterface[] = "br0";
const char kControlInterfacePath[] = "/var/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=/var/run/apmanager/hostapd/ctrl_iface\n"
"ctrl_interface_group=apmanager\n"
"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() : config_(&manager_, kServicePath) {}
void SetupDevice(const std::string& interface) {
// Setup mock device.
device_ = new MockDevice();
device_->SetPreferredApInterface(interface);
EXPECT_CALL(manager_, GetDeviceFromInterfaceName(interface))
.WillRepeatedly(Return(device_));
}
protected:
Config config_;
MockManager manager_;
scoped_refptr<MockDevice> device_;
};
MATCHER_P(IsConfigErrorStartingWith, message, "") {
return arg != nullptr &&
arg->GetDomain() == chromeos::errors::dbus::kDomain &&
arg->GetCode() == kConfigError &&
StartsWithASCII(arg->GetMessage(), message, false);
}
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) {
chromeos::ErrorPtr 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) {
chromeos::ErrorPtr error;
EXPECT_TRUE(config_.ValidateSecurityMode(&error, kSecurityModeNone));
EXPECT_TRUE(config_.ValidateSecurityMode(&error, kSecurityModeRSN));
EXPECT_FALSE(config_.ValidateSecurityMode(&error, "InvalidSecurityMode"));
}
TEST_F(ConfigTest, ValidatePassphrase) {
chromeos::ErrorPtr 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) {
chromeos::ErrorPtr 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) {
chromeos::ErrorPtr error;
EXPECT_TRUE(config_.ValidateOperationMode(&error, kOperationModeServer));
EXPECT_TRUE(config_.ValidateOperationMode(&error, kOperationModeBridge));
EXPECT_FALSE(config_.ValidateOperationMode(&error, "InvalidMode"));
}
TEST_F(ConfigTest, ValidateChannel) {
chromeos::ErrorPtr 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;
chromeos::ErrorPtr error;
EXPECT_FALSE(config_.GenerateConfigFile(&error, &config_content));
EXPECT_THAT(error, IsConfigErrorStartingWith("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.
chromeos::ErrorPtr error;
std::string config_content;
EXPECT_CALL(manager_, GetAvailableDevice()).WillOnce(Return(nullptr));
EXPECT_FALSE(config_.GenerateConfigFile(&error, &config_content));
EXPECT_THAT(error, IsConfigErrorStartingWith("No device available"));
Mock::VerifyAndClearExpectations(&manager_);
// Device available, config file should be generated without any problem.
scoped_refptr<MockDevice> device = new MockDevice();
device->SetPreferredApInterface(kInterface);
chromeos::ErrorPtr error1;
EXPECT_CALL(manager_, GetAvailableDevice()).WillOnce(Return(device));
EXPECT_TRUE(config_.GenerateConfigFile(&error1, &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_EQ(nullptr, error1.get());
Mock::VerifyAndClearExpectations(&manager_);
}
TEST_F(ConfigTest, InvalidInterface) {
// Basic 80211.g configuration.
config_.SetSsid(kSsid);
config_.SetChannel(k24GHzChannel);
config_.SetHwMode(kHwMode80211g);
config_.SetInterfaceName(kInterface);
// No device available, fail to generate config file.
chromeos::ErrorPtr error;
std::string config_content;
EXPECT_CALL(manager_, GetDeviceFromInterfaceName(kInterface))
.WillOnce(Return(nullptr));
EXPECT_FALSE(config_.GenerateConfigFile(&error, &config_content));
EXPECT_THAT(error,
IsConfigErrorStartingWith(
"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.
chromeos::ErrorPtr error;
std::string config_content;
EXPECT_FALSE(config_.GenerateConfigFile(&error, &config_content));
EXPECT_THAT(error,
IsConfigErrorStartingWith("Bridge interface not specified"));
// Set bridge interface, config file should be generated without error.
config_.SetBridgeInterface(kBridgeInterface);
// Setup mock device.
SetupDevice(kInterface);
chromeos::ErrorPtr error1;
std::string config_content1;
EXPECT_TRUE(config_.GenerateConfigFile(&error1, &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_EQ(nullptr, error1.get());
}
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;
chromeos::ErrorPtr 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_EQ(nullptr, error.get());
}
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;
chromeos::ErrorPtr 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_EQ(nullptr, error.get());
}
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;
chromeos::ErrorPtr error;
std::string ht_capab_5ghz(k5GHzHTCapab);
EXPECT_CALL(*device_.get(), GetHTCapability(k5GHzChannel, _))
.WillOnce(DoAll(SetArgumentPointee<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_EQ(nullptr, error.get());
Mock::VerifyAndClearExpectations(device_.get());
// 2.4GHz channel.
config_.SetChannel(k24GHzChannel);
std::string ghz24_config_content;
chromeos::ErrorPtr error1;
std::string ht_capab_24ghz(k24GHzHTCapab);
EXPECT_CALL(*device_.get(), GetHTCapability(k24GHzChannel, _))
.WillOnce(DoAll(SetArgumentPointee<1>(ht_capab_24ghz), Return(true)));
EXPECT_TRUE(config_.GenerateConfigFile(&error1, &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_EQ(nullptr, error.get());
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;
chromeos::ErrorPtr error;
EXPECT_FALSE(config_.GenerateConfigFile(&error, &config_content));
EXPECT_THAT(error, IsConfigErrorStartingWith(
base::StringPrintf("Passphrase not set for security mode: %s",
kSecurityModeRSN)));
chromeos::ErrorPtr error1;
config_.SetPassphrase(kPassphrase);
EXPECT_TRUE(config_.GenerateConfigFile(&error1, &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_EQ(nullptr, error1.get());
}
} // namespace apmanager