blob: 794e83826bf44cf65f3f4bc0d4ca86bc8c09938b [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 <base/strings/stringprintf.h>
#if !defined(__ANDROID__)
#include <chromeos/dbus/service_constants.h>
#else
#include <dbus/apmanager/dbus-constants.h>
#endif // __ANDROID__
#include "apmanager/error.h"
#include "apmanager/daemon.h"
#include "apmanager/device.h"
#include "apmanager/manager.h"
using std::string;
namespace apmanager {
// static
const char Config::kHostapdConfigKeyBridgeInterface[] = "bridge";
const char Config::kHostapdConfigKeyChannel[] = "channel";
const char Config::kHostapdConfigKeyControlInterface[] = "ctrl_interface";
const char Config::kHostapdConfigKeyControlInterfaceGroup[] =
"ctrl_interface_group";
const char Config::kHostapdConfigKeyDriver[] = "driver";
const char Config::kHostapdConfigKeyFragmThreshold[] = "fragm_threshold";
const char Config::kHostapdConfigKeyHTCapability[] = "ht_capab";
const char Config::kHostapdConfigKeyHwMode[] = "hw_mode";
const char Config::kHostapdConfigKeyIeee80211ac[] = "ieee80211ac";
const char Config::kHostapdConfigKeyIeee80211n[] = "ieee80211n";
const char Config::kHostapdConfigKeyIgnoreBroadcastSsid[] =
"ignore_broadcast_ssid";
const char Config::kHostapdConfigKeyInterface[] = "interface";
const char Config::kHostapdConfigKeyRsnPairwise[] = "rsn_pairwise";
const char Config::kHostapdConfigKeyRtsThreshold[] = "rts_threshold";
const char Config::kHostapdConfigKeySsid[] = "ssid";
const char Config::kHostapdConfigKeyWepDefaultKey[] = "wep_default_key";
const char Config::kHostapdConfigKeyWepKey0[] = "wep_key0";
const char Config::kHostapdConfigKeyWpa[] = "wpa";
const char Config::kHostapdConfigKeyWpaKeyMgmt[] = "wpa_key_mgmt";
const char Config::kHostapdConfigKeyWpaPassphrase[] = "wpa_passphrase";
const char Config::kHostapdHwMode80211a[] = "a";
const char Config::kHostapdHwMode80211b[] = "b";
const char Config::kHostapdHwMode80211g[] = "g";
// static
const uint16_t Config::kPropertyDefaultChannel = 6;
const uint16_t Config::kPropertyDefaultServerAddressIndex = 0;
const bool Config::kPropertyDefaultHiddenNetwork = false;
// static
const char Config::kHostapdDefaultDriver[] = "nl80211";
const char Config::kHostapdDefaultRsnPairwise[] = "CCMP";
const char Config::kHostapdDefaultWpaKeyMgmt[] = "WPA-PSK";
// Fragmentation threshold: disabled.
const int Config::kHostapdDefaultFragmThreshold = 2346;
// RTS threshold: disabled.
const int Config::kHostapdDefaultRtsThreshold = 2347;
// static
const uint16_t Config::kBand24GHzChannelLow = 1;
const uint16_t Config::kBand24GHzChannelHigh = 13;
const uint32_t Config::kBand24GHzBaseFrequency = 2412;
const uint16_t Config::kBand5GHzChannelLow = 34;
const uint16_t Config::kBand5GHzChannelHigh = 165;
const uint16_t Config::kBand5GHzBaseFrequency = 5170;
// static
const int Config::kSsidMinLength = 1;
const int Config::kSsidMaxLength = 32;
const int Config::kPassphraseMinLength = 8;
const int Config::kPassphraseMaxLength = 63;
Config::Config(Manager* manager, int service_identifier)
: manager_(manager),
adaptor_(
manager->control_interface()->CreateConfigAdaptor(
this, service_identifier)) {
// Initialize default configuration values.
SetSecurityMode(kSecurityModeNone);
SetHwMode(kHwMode80211g);
SetOperationMode(kOperationModeServer);
SetServerAddressIndex(kPropertyDefaultServerAddressIndex);
SetChannel(kPropertyDefaultChannel);
SetHiddenNetwork(kPropertyDefaultHiddenNetwork);
SetFullDeviceControl(true);
}
Config::~Config() {}
// static.
bool Config::GetFrequencyFromChannel(uint16_t channel, uint32_t* freq) {
bool ret_value = true;
if (channel >= kBand24GHzChannelLow && channel <= kBand24GHzChannelHigh) {
*freq = kBand24GHzBaseFrequency + (channel - kBand24GHzChannelLow) * 5;
} else if (channel >= kBand5GHzChannelLow &&
channel <= kBand5GHzChannelHigh) {
*freq = kBand5GHzBaseFrequency + (channel - kBand5GHzChannelLow) * 5;
} else {
ret_value = false;
}
return ret_value;
}
bool Config::ValidateSsid(Error* error, const string& value) {
if (value.length() < kSsidMinLength || value.length() > kSsidMaxLength) {
Error::PopulateAndLog(
error,
Error::kInvalidArguments,
base::StringPrintf("SSID must contain between %d and %d characters",
kSsidMinLength, kSsidMaxLength),
FROM_HERE);
return false;
}
return true;
}
bool Config::ValidateSecurityMode(Error* error, const string& value) {
if (value != kSecurityModeNone && value != kSecurityModeRSN) {
Error::PopulateAndLog(
error,
Error::kInvalidArguments,
base::StringPrintf("Invalid/unsupported security mode [%s]",
value.c_str()),
FROM_HERE);
return false;
}
return true;
}
bool Config::ValidatePassphrase(Error* error, const string& value) {
if (value.length() < kPassphraseMinLength ||
value.length() > kPassphraseMaxLength) {
Error::PopulateAndLog(
error,
Error::kInvalidArguments,
base::StringPrintf("Passphrase must contain between %d and %d characters",
kPassphraseMinLength, kPassphraseMaxLength),
FROM_HERE);
return false;
}
return true;
}
bool Config::ValidateHwMode(Error* error, const string& value) {
if (value != kHwMode80211a && value != kHwMode80211b &&
value != kHwMode80211g && value != kHwMode80211n &&
value != kHwMode80211ac) {
Error::PopulateAndLog(
error,
Error::kInvalidArguments,
base::StringPrintf("Invalid HW mode [%s]", value.c_str()),
FROM_HERE);
return false;
}
return true;
}
bool Config::ValidateOperationMode(Error* error, const string& value) {
if (value != kOperationModeServer && value != kOperationModeBridge) {
Error::PopulateAndLog(
error,
Error::kInvalidArguments,
base::StringPrintf("Invalid operation mode [%s]", value.c_str()),
FROM_HERE);
return false;
}
return true;
}
bool Config::ValidateChannel(Error* error, const uint16_t& value) {
if ((value >= kBand24GHzChannelLow && value <= kBand24GHzChannelHigh) ||
(value >= kBand5GHzChannelLow && value <= kBand5GHzChannelHigh)) {
return true;
}
Error::PopulateAndLog(error,
Error::kInvalidArguments,
base::StringPrintf("Invalid channel [%d]", value),
FROM_HERE);
return false;
}
bool Config::GenerateConfigFile(Error* error, string* config_str) {
// SSID.
string ssid = GetSsid();
if (ssid.empty()) {
Error::PopulateAndLog(error,
Error::kInvalidConfiguration,
"SSID not specified",
FROM_HERE);
return false;
}
base::StringAppendF(
config_str, "%s=%s\n", kHostapdConfigKeySsid, ssid.c_str());
// Bridge interface is required for bridge mode operation.
if (GetOperationMode() == kOperationModeBridge) {
if (GetBridgeInterface().empty()) {
Error::PopulateAndLog(
error,
Error::kInvalidConfiguration,
"Bridge interface not specified, required for bridge mode",
FROM_HERE);
return false;
}
base::StringAppendF(config_str,
"%s=%s\n",
kHostapdConfigKeyBridgeInterface,
GetBridgeInterface().c_str());
}
// Channel.
base::StringAppendF(
config_str, "%s=%d\n", kHostapdConfigKeyChannel, GetChannel());
// Interface.
if (!AppendInterface(error, config_str)) {
return false;
}
// Hardware mode.
if (!AppendHwMode(error, config_str)) {
return false;
}
// Security mode configurations.
if (!AppendSecurityMode(error, config_str)) {
return false;
}
// Control interface.
if (!control_interface_.empty()) {
base::StringAppendF(config_str,
"%s=%s\n",
kHostapdConfigKeyControlInterface,
control_interface_.c_str());
base::StringAppendF(config_str,
"%s=%s\n",
kHostapdConfigKeyControlInterfaceGroup,
Daemon::kAPManagerGroupName);
}
// Hostapd default configurations.
if (!AppendHostapdDefaults(error, config_str)) {
return false;
}
return true;
}
bool Config::ClaimDevice() {
if (!device_) {
LOG(ERROR) << "Failed to claim device: device doesn't exist.";
return false;
}
return device_->ClaimDevice(GetFullDeviceControl());
}
bool Config::ReleaseDevice() {
if (!device_) {
LOG(ERROR) << "Failed to release device: device doesn't exist.";
return false;
}
return device_->ReleaseDevice();
}
void Config::SetSsid(const string& ssid) {
adaptor_->SetSsid(ssid);
}
string Config::GetSsid() const {
return adaptor_->GetSsid();
}
void Config::SetInterfaceName(const std::string& interface_name) {
adaptor_->SetInterfaceName(interface_name);
}
string Config::GetInterfaceName() const {
return adaptor_->GetInterfaceName();
}
void Config::SetSecurityMode(const std::string& mode) {
adaptor_->SetSecurityMode(mode);
}
string Config::GetSecurityMode() const {
return adaptor_->GetSecurityMode();
}
void Config::SetPassphrase(const std::string& passphrase) {
adaptor_->SetPassphrase(passphrase);
}
string Config::GetPassphrase() const {
return adaptor_->GetPassphrase();
}
void Config::SetHwMode(const std::string& hw_mode) {
adaptor_->SetHwMode(hw_mode);
}
string Config::GetHwMode() const {
return adaptor_->GetHwMode();
}
void Config::SetOperationMode(const std::string& op_mode) {
adaptor_->SetOperationMode(op_mode);
}
string Config::GetOperationMode() const {
return adaptor_->GetOperationMode();
}
void Config::SetChannel(uint16_t channel) {
adaptor_->SetChannel(channel);
}
uint16_t Config::GetChannel() const {
return adaptor_->GetChannel();
}
void Config::SetHiddenNetwork(bool hidden_network) {
adaptor_->SetHiddenNetwork(hidden_network);
}
bool Config::GetHiddenNetwork() const {
return adaptor_->GetHiddenNetwork();
}
void Config::SetBridgeInterface(const std::string& interface_name) {
adaptor_->SetBridgeInterface(interface_name);
}
string Config::GetBridgeInterface() const {
return adaptor_->GetBridgeInterface();
}
void Config::SetServerAddressIndex(uint16_t index) {
adaptor_->SetServerAddressIndex(index);
}
uint16_t Config::GetServerAddressIndex() const {
return adaptor_->GetServerAddressIndex();
}
void Config::SetFullDeviceControl(bool full_control) {
adaptor_->SetFullDeviceControl(full_control);
}
bool Config::GetFullDeviceControl() const {
return adaptor_->GetFullDeviceControl();
}
bool Config::AppendHwMode(Error* error, string* config_str) {
string hw_mode = GetHwMode();
string hostapd_hw_mode;
if (hw_mode == kHwMode80211a) {
hostapd_hw_mode = kHostapdHwMode80211a;
} else if (hw_mode == kHwMode80211b) {
hostapd_hw_mode = kHostapdHwMode80211b;
} else if (hw_mode == kHwMode80211g) {
hostapd_hw_mode = kHostapdHwMode80211g;
} else if (hw_mode == kHwMode80211n) {
// Use 802.11a for 5GHz channel and 802.11g for 2.4GHz channel
if (GetChannel() >= 34) {
hostapd_hw_mode = kHostapdHwMode80211a;
} else {
hostapd_hw_mode = kHostapdHwMode80211g;
}
base::StringAppendF(config_str, "%s=1\n", kHostapdConfigKeyIeee80211n);
// Get HT Capability.
string ht_cap;
if (!device_->GetHTCapability(GetChannel(), &ht_cap)) {
Error::PopulateAndLog(error,
Error::kInvalidConfiguration,
"Failed to get HT Capability",
FROM_HERE);
return false;
}
base::StringAppendF(config_str, "%s=%s\n",
kHostapdConfigKeyHTCapability,
ht_cap.c_str());
} else if (hw_mode == kHwMode80211ac) {
if (GetChannel() >= 34) {
hostapd_hw_mode = kHostapdHwMode80211a;
} else {
hostapd_hw_mode = kHostapdHwMode80211g;
}
base::StringAppendF(config_str, "%s=1\n", kHostapdConfigKeyIeee80211ac);
// TODO(zqiu): Determine VHT Capabilities based on the interface PHY's
// capababilites.
} else {
Error::PopulateAndLog(
error,
Error::kInvalidConfiguration,
base::StringPrintf("Invalid hardware mode: %s", hw_mode.c_str()),
FROM_HERE);
return false;
}
base::StringAppendF(
config_str, "%s=%s\n", kHostapdConfigKeyHwMode, hostapd_hw_mode.c_str());
return true;
}
bool Config::AppendHostapdDefaults(Error* error, string* config_str) {
// Driver: NL80211.
base::StringAppendF(
config_str, "%s=%s\n", kHostapdConfigKeyDriver, kHostapdDefaultDriver);
// Fragmentation threshold: disabled.
base::StringAppendF(config_str,
"%s=%d\n",
kHostapdConfigKeyFragmThreshold,
kHostapdDefaultFragmThreshold);
// RTS threshold: disabled.
base::StringAppendF(config_str,
"%s=%d\n",
kHostapdConfigKeyRtsThreshold,
kHostapdDefaultRtsThreshold);
return true;
}
bool Config::AppendInterface(Error* error, string* config_str) {
string interface = GetInterfaceName();
if (interface.empty()) {
// Ask manager for unused ap capable device.
device_ = manager_->GetAvailableDevice();
if (!device_) {
Error::PopulateAndLog(
error, Error::kInternalError, "No device available", FROM_HERE);
return false;
}
} else {
device_ = manager_->GetDeviceFromInterfaceName(interface);
if (!device_) {
Error::PopulateAndLog(
error,
Error::kInvalidConfiguration,
base::StringPrintf(
"Unable to find device for the specified interface [%s]",
interface.c_str()),
FROM_HERE);
return false;
}
if (device_->GetInUse()) {
Error::PopulateAndLog(
error,
Error::kInvalidConfiguration,
base::StringPrintf("Device [%s] for interface [%s] already in use",
device_->GetDeviceName().c_str(),
interface.c_str()),
FROM_HERE);
return false;
}
}
// Use the preferred AP interface from the device.
selected_interface_ = device_->GetPreferredApInterface();
base::StringAppendF(config_str,
"%s=%s\n",
kHostapdConfigKeyInterface,
selected_interface_.c_str());
return true;
}
bool Config::AppendSecurityMode(Error* error, string* config_str) {
string security_mode = GetSecurityMode();
if (security_mode == kSecurityModeNone) {
// Nothing need to be done for open network.
return true;
}
if (security_mode == kSecurityModeRSN) {
string passphrase = GetPassphrase();
if (passphrase.empty()) {
Error::PopulateAndLog(
error,
Error::kInvalidConfiguration,
base::StringPrintf("Passphrase not set for security mode: %s",
security_mode.c_str()),
FROM_HERE);
return false;
}
base::StringAppendF(config_str, "%s=2\n", kHostapdConfigKeyWpa);
base::StringAppendF(config_str,
"%s=%s\n",
kHostapdConfigKeyRsnPairwise,
kHostapdDefaultRsnPairwise);
base::StringAppendF(config_str,
"%s=%s\n",
kHostapdConfigKeyWpaKeyMgmt,
kHostapdDefaultWpaKeyMgmt);
base::StringAppendF(config_str,
"%s=%s\n",
kHostapdConfigKeyWpaPassphrase,
passphrase.c_str());
return true;
}
Error::PopulateAndLog(
error,
Error::kInvalidConfiguration,
base::StringPrintf("Invalid security mode: %s", security_mode.c_str()),
FROM_HERE);
return false;
}
} // namespace apmanager