apmanager: initial support for AP configuration

Add Config class for configuring AP service and generating config file
for hostapd instance. Add a DBus service for the Config object and
export the configurations as DBus properties.

BUG=chromium:430536
TEST=unittests
CQ-DEPEND=CL:228886

Change-Id: I25f48b49edb6a88f36cd51f527ef71f1f8c835dd
Reviewed-on: https://chromium-review.googlesource.com/229044
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Commit-Queue: Peter Qiu <zqiu@chromium.org>
Tested-by: Peter Qiu <zqiu@chromium.org>
diff --git a/config.cc b/config.cc
new file mode 100644
index 0000000..46bf6dd
--- /dev/null
+++ b/config.cc
@@ -0,0 +1,235 @@
+// 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 <base/strings/stringprintf.h>
+#include <chromeos/dbus/service_constants.h>
+
+using chromeos::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::kHostapdConfigKeyDriver[] = "driver";
+const char Config::kHostapdConfigKeyFragmThreshold[] = "fragm_threshold";
+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;
+
+Config::Config(
+    const string& service_path,
+    chromeos::dbus_utils::ExportedObjectManager* object_manager,
+    chromeos::dbus_utils::AsyncEventSequencer* sequencer)
+    : org::chromium::apmanager::ConfigAdaptor(this),
+      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);
+}
+
+Config::~Config() {}
+
+bool Config::GenerateConfigFile(ErrorPtr* error, string* config_str) {
+  // SSID.
+  string ssid = GetSsid();
+  if (ssid.empty()) {
+    SetError(__func__, "SSID not specified", error);
+    return false;
+  }
+  base::StringAppendF(
+      config_str, "%s=%s\n", kHostapdConfigKeySsid, ssid.c_str());
+
+  // Channel.
+  base::StringAppendF(
+      config_str, "%s=%d\n", kHostapdConfigKeyChannel, GetChannel());
+
+  // Hardware mode.
+  if (!AppendHwMode(error, config_str)) {
+    return false;
+  }
+
+  // Interface.
+  if (!AppendInterface(error, config_str)) {
+    return false;
+  }
+
+  // Security mode configurations.
+  if (!AppendSecurityMode(error, config_str)) {
+    return false;
+  }
+
+  // Hostapd default configurations.
+  if (!AppendHostapdDefaults(error, config_str)) {
+    return false;
+  }
+
+  return true;
+}
+
+bool Config::AppendHwMode(chromeos::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);
+
+    // TODO(zqiu): Determine HT Capabilities based on the interface PHY's
+    // capababilites.
+  } 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 {
+    SetError(__func__,
+             base::StringPrintf("Invalid hardware mode: %s", hw_mode.c_str()),
+             error);
+    return false;
+  }
+
+  base::StringAppendF(
+      config_str, "%s=%s\n", kHostapdConfigKeyHwMode, hostapd_hw_mode.c_str());
+  return true;
+}
+
+bool Config::AppendHostapdDefaults(chromeos::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(chromeos::ErrorPtr* error,
+                             std::string* config_str) {
+  string interface = GetInterfaceName();
+  if (interface.empty()) {
+    // TODO(zqiu): Ask manager for available ap mode interface.
+    return false;
+  }
+
+  base::StringAppendF(
+      config_str, "%s=%s\n", kHostapdConfigKeyInterface, interface.c_str());
+  return true;
+}
+
+bool Config::AppendSecurityMode(chromeos::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()) {
+      SetError(__func__,
+               base::StringPrintf("Passphrase not set for security mode: %s",
+                                  security_mode.c_str()),
+               error);
+      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;
+  }
+
+  SetError(__func__,
+           base::StringPrintf("Invalid security mode: %s",
+                              security_mode.c_str()),
+           error);
+  return false;
+}
+
+// static.
+void Config::SetError(const string& method,
+                      const string& message,
+                      chromeos::ErrorPtr* error) {
+  chromeos::Error::AddToPrintf(
+      error, chromeos::errors::dbus::kDomain, kConfigError,
+      "%s : %s", method.c_str(), message.c_str());
+}
+
+}  // namespace apmanager