534 lines
16 KiB
C++
534 lines
16 KiB
C++
//
|
|
// 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
|