apmanager: add support for HT capability

Parse wiphy's HT capability and add it to the AP service's configuration
file to correctly support AP in 80211n mode.

BUG=chromium:431763
TEST=unittests and manual test by using python to invoke dbus calls
     to start AP service in 802.11n mode.

Change-Id: I6c902136832eea6b38b806f733231d6cbe14e3f6
Reviewed-on: https://chromium-review.googlesource.com/231681
Reviewed-by: Peter Qiu <zqiu@chromium.org>
Commit-Queue: Peter Qiu <zqiu@chromium.org>
Tested-by: Peter Qiu <zqiu@chromium.org>
diff --git a/config.cc b/config.cc
index 8f70c80..7fa98da 100644
--- a/config.cc
+++ b/config.cc
@@ -23,6 +23,7 @@
 const char Config::kHostapdConfigKeyControlInterface[] = "ctrl_interface";
 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";
@@ -56,6 +57,14 @@
 // 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;
+
 Config::Config(Manager* manager, const string& service_path)
     : org::chromium::apmanager::ConfigAdaptor(this),
       manager_(manager),
@@ -72,6 +81,20 @@
 
 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;
+}
+
 void Config::RegisterAsync(ExportedObjectManager* object_manager,
                            AsyncEventSequencer* sequencer) {
   CHECK(!dbus_object_) << "Already registered";
@@ -101,13 +124,13 @@
   base::StringAppendF(
       config_str, "%s=%d\n", kHostapdConfigKeyChannel, GetChannel());
 
-  // Hardware mode.
-  if (!AppendHwMode(error, config_str)) {
+  // Interface.
+  if (!AppendInterface(error, config_str)) {
     return false;
   }
 
-  // Interface.
-  if (!AppendInterface(error, config_str)) {
+  // Hardware mode.
+  if (!AppendHwMode(error, config_str)) {
     return false;
   }
 
@@ -158,8 +181,17 @@
     }
     base::StringAppendF(config_str, "%s=1\n", kHostapdConfigKeyIeee80211n);
 
-    // TODO(zqiu): Determine HT Capabilities based on the interface PHY's
-    // capababilites.
+    // Get HT Capability.
+    string ht_cap;
+    if (!device_->GetHTCapability(GetChannel(), &ht_cap)) {
+      chromeos::Error::AddTo(
+          error, FROM_HERE, chromeos::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;