blob: ba865e0a9b43aadf96289589a6e07bb7ae7267cf [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/daemon.h"
#include "apmanager/device.h"
#include "apmanager/manager.h"
using brillo::dbus_utils::AsyncEventSequencer;
using brillo::dbus_utils::ExportedObjectManager;
using brillo::ErrorPtr;
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, const string& service_path)
: org::chromium::apmanager::ConfigAdaptor(this),
manager_(manager),
dbus_path_(dbus::ObjectPath(
base::StringPrintf("%s/config", service_path.c_str()))) {
// 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(ErrorPtr* error, const string& value) {
if (value.length() < kSsidMinLength || value.length() > kSsidMaxLength) {
brillo::Error::AddToPrintf(
error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
"SSID must contain between %d and %d characters",
kSsidMinLength, kSsidMaxLength);
return false;
}
return true;
}
bool Config::ValidateSecurityMode(ErrorPtr* error, const string& value) {
if (value != kSecurityModeNone && value != kSecurityModeRSN) {
brillo::Error::AddToPrintf(
error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
"Invalid/unsupported security mode [%s]", value.c_str());
return false;
}
return true;
}
bool Config::ValidatePassphrase(ErrorPtr* error, const string& value) {
if (value.length() < kPassphraseMinLength ||
value.length() > kPassphraseMaxLength) {
brillo::Error::AddToPrintf(
error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
"Passphrase must contain between %d and %d characters",
kPassphraseMinLength, kPassphraseMaxLength);
return false;
}
return true;
}
bool Config::ValidateHwMode(ErrorPtr* error, const string& value) {
if (value != kHwMode80211a && value != kHwMode80211b &&
value != kHwMode80211g && value != kHwMode80211n &&
value != kHwMode80211ac) {
brillo::Error::AddToPrintf(
error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
"Invalid HW mode [%s]", value.c_str());
return false;
}
return true;
}
bool Config::ValidateOperationMode(ErrorPtr* error, const string& value) {
if (value != kOperationModeServer && value != kOperationModeBridge) {
brillo::Error::AddToPrintf(
error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
"Invalid operation mode [%s]", value.c_str());
return false;
}
return true;
}
bool Config::ValidateChannel(ErrorPtr* error, const uint16_t& value) {
if ((value >= kBand24GHzChannelLow && value <= kBand24GHzChannelHigh) ||
(value >= kBand5GHzChannelLow && value <= kBand5GHzChannelHigh)) {
return true;
}
brillo::Error::AddToPrintf(
error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
"Invalid channel [%d]", value);
return false;
}
void Config::RegisterAsync(ExportedObjectManager* object_manager,
const scoped_refptr<dbus::Bus>& bus,
AsyncEventSequencer* sequencer) {
CHECK(!dbus_object_) << "Already registered";
dbus_object_.reset(
new brillo::dbus_utils::DBusObject(
object_manager,
bus,
dbus_path_));
RegisterWithDBusObject(dbus_object_.get());
dbus_object_->RegisterAsync(
sequencer->GetHandler("Config.RegisterAsync() failed.", true));
}
bool Config::GenerateConfigFile(ErrorPtr* error, string* config_str) {
// SSID.
string ssid = GetSsid();
if (ssid.empty()) {
brillo::Error::AddTo(
error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
"SSID not specified");
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()) {
brillo::Error::AddTo(
error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
"Bridge interface not specified, required for bridge mode");
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();
}
bool Config::AppendHwMode(ErrorPtr* error, std::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)) {
brillo::Error::AddTo(
error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
"Failed to get HT Capability");
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 {
brillo::Error::AddToPrintf(
error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
"Invalid hardware mode: %s", hw_mode.c_str());
return false;
}
base::StringAppendF(
config_str, "%s=%s\n", kHostapdConfigKeyHwMode, hostapd_hw_mode.c_str());
return true;
}
bool Config::AppendHostapdDefaults(ErrorPtr* error,
std::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(ErrorPtr* error,
std::string* config_str) {
string interface = GetInterfaceName();
if (interface.empty()) {
// Ask manager for unused ap capable device.
device_ = manager_->GetAvailableDevice();
if (!device_) {
brillo::Error::AddTo(
error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
"No device available");
return false;
}
} else {
device_ = manager_->GetDeviceFromInterfaceName(interface);
if (!device_) {
brillo::Error::AddToPrintf(
error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
"Unable to find device for the specified interface [%s]",
interface.c_str());
return false;
}
if (device_->GetInUse()) {
brillo::Error::AddToPrintf(
error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
"Device [%s] for interface [%s] already in use",
device_->GetDeviceName().c_str(),
interface.c_str());
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(ErrorPtr* error,
std::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()) {
brillo::Error::AddToPrintf(
error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
"Passphrase not set for security mode: %s", security_mode.c_str());
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;
}
brillo::Error::AddToPrintf(
error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
"Invalid security mode: %s", security_mode.c_str());
return false;
}
} // namespace apmanager