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_unittest.cc b/config_unittest.cc
new file mode 100644
index 0000000..0cc2f38
--- /dev/null
+++ b/config_unittest.cc
@@ -0,0 +1,163 @@
+// 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/string_util.h>
+#include <base/strings/stringprintf.h>
+#include <chromeos/dbus/service_constants.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace apmanager {
+
+namespace {
+
+const char kServicePath[] = "/manager/services/0";
+const char kSsid[] = "TestSsid";
+const char kInterface[] = "uap0";
+const char kPassphrase[] = "Passphrase";
+const uint16_t k24GHzChannel = 6;
+const uint16_t k5GHzChannel = 36;
+
+const char kExpected80211gConfigContent[] = "ssid=TestSsid\n"
+                                            "channel=6\n"
+                                            "hw_mode=g\n"
+                                            "interface=uap0\n"
+                                            "driver=nl80211\n"
+                                            "fragm_threshold=2346\n"
+                                            "rts_threshold=2347\n";
+
+const char kExpected80211n5GHzConfigContent[] = "ssid=TestSsid\n"
+                                                "channel=36\n"
+                                                "ieee80211n=1\n"
+                                                "hw_mode=a\n"
+                                                "interface=uap0\n"
+                                                "driver=nl80211\n"
+                                                "fragm_threshold=2346\n"
+                                                "rts_threshold=2347\n";
+
+const char kExpected80211n24GHzConfigContent[] = "ssid=TestSsid\n"
+                                                 "channel=6\n"
+                                                 "ieee80211n=1\n"
+                                                 "hw_mode=g\n"
+                                                 "interface=uap0\n"
+                                                 "driver=nl80211\n"
+                                                 "fragm_threshold=2346\n"
+                                                 "rts_threshold=2347\n";
+
+const char kExpectedRsnConfigContent[] = "ssid=TestSsid\n"
+                                         "channel=6\n"
+                                         "hw_mode=g\n"
+                                         "interface=uap0\n"
+                                         "wpa=2\n"
+                                         "rsn_pairwise=CCMP\n"
+                                         "wpa_key_mgmt=WPA-PSK\n"
+                                         "wpa_passphrase=Passphrase\n"
+                                         "driver=nl80211\n"
+                                         "fragm_threshold=2346\n"
+                                         "rts_threshold=2347\n";
+
+}  // namespace
+
+class ConfigTest : public testing::Test {
+ public:
+  ConfigTest() : config_(kServicePath, nullptr, nullptr) {}
+
+ protected:
+  Config config_;
+};
+
+MATCHER_P(IsConfigErrorEndingWith, message, "") {
+  return arg != nullptr &&
+      arg->GetDomain() == chromeos::errors::dbus::kDomain &&
+      arg->GetCode() == kConfigError &&
+      EndsWith(arg->GetMessage(), message, false);
+}
+
+TEST_F(ConfigTest, NoSsid) {
+  config_.SetChannel(k24GHzChannel);
+  config_.SetHwMode(kHwMode80211g);
+  config_.SetInterfaceName(kInterface);
+
+  std::string config_content;
+  chromeos::ErrorPtr error;
+  EXPECT_FALSE(config_.GenerateConfigFile(&error, &config_content));
+  EXPECT_THAT(error, IsConfigErrorEndingWith("SSID not specified"));
+}
+
+TEST_F(ConfigTest, 80211gConfig) {
+  config_.SetSsid(kSsid);
+  config_.SetChannel(k24GHzChannel);
+  config_.SetHwMode(kHwMode80211g);
+  config_.SetInterfaceName(kInterface);
+
+  std::string config_content;
+  chromeos::ErrorPtr error;
+  EXPECT_TRUE(config_.GenerateConfigFile(&error, &config_content));
+  EXPECT_NE(std::string::npos, config_content.find(
+                                   kExpected80211gConfigContent))
+      << "Expected to find the following config...\n"
+      << kExpected80211gConfigContent << "..within content...\n"
+      << config_content;
+  EXPECT_EQ(nullptr, error.get());
+}
+
+TEST_F(ConfigTest, 80211nConfig) {
+  config_.SetSsid(kSsid);
+  config_.SetHwMode(kHwMode80211n);
+  config_.SetInterfaceName(kInterface);
+
+  // 5GHz channel.
+  config_.SetChannel(k5GHzChannel);
+  std::string ghz5_config_content;
+  chromeos::ErrorPtr error;
+  EXPECT_TRUE(config_.GenerateConfigFile(&error, &ghz5_config_content));
+  EXPECT_NE(std::string::npos, ghz5_config_content.find(
+                                   kExpected80211n5GHzConfigContent))
+      << "Expected to find the following config...\n"
+      << kExpected80211n5GHzConfigContent << "..within content...\n"
+      << ghz5_config_content;
+  EXPECT_EQ(nullptr, error.get());
+
+  // 2.4GHz channel.
+  config_.SetChannel(k24GHzChannel);
+  std::string ghz24_config_content;
+  chromeos::ErrorPtr error1;
+  EXPECT_TRUE(config_.GenerateConfigFile(&error1, &ghz24_config_content));
+  EXPECT_NE(std::string::npos, ghz24_config_content.find(
+                                   kExpected80211n24GHzConfigContent))
+      << "Expected to find the following config...\n"
+      << kExpected80211n24GHzConfigContent << "..within content...\n"
+      << ghz24_config_content;
+  EXPECT_EQ(nullptr, error.get());
+}
+
+TEST_F(ConfigTest, RsnConfig) {
+  config_.SetSsid(kSsid);
+  config_.SetChannel(k24GHzChannel);
+  config_.SetHwMode(kHwMode80211g);
+  config_.SetInterfaceName(kInterface);
+  config_.SetSecurityMode(kSecurityModeRSN);
+
+  // Failed due to no passphrase specified.
+  std::string config_content;
+  chromeos::ErrorPtr error;
+  EXPECT_FALSE(config_.GenerateConfigFile(&error, &config_content));
+  EXPECT_THAT(error, IsConfigErrorEndingWith(
+      base::StringPrintf("Passphrase not set for security mode: %s",
+                         kSecurityModeRSN)));
+
+  chromeos::ErrorPtr error1;
+  config_.SetPassphrase(kPassphrase);
+  EXPECT_TRUE(config_.GenerateConfigFile(&error1, &config_content));
+  EXPECT_NE(std::string::npos, config_content.find(
+                                   kExpectedRsnConfigContent))
+      << "Expected to find the following config...\n"
+      << kExpectedRsnConfigContent << "..within content...\n"
+      << config_content;
+  EXPECT_EQ(nullptr, error1.get());
+}
+
+}  // namespace apmanager