普通文本  |  535行  |  16.25 KB

//
// 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