shill: add support for connecting to WPA-PSK networks

BUG=chromium-os:20897
TEST=unittests, some autotests (see below)

the following autotests now pass, at least in the wifi_vm_config:
- network_WiFiManager.000_SSID_Length_Limit
- network_WiFiSecMat.010CheckWPA_TKIP
- network_WiFiSecMat.011CheckWPA_AES
- network_WiFiSecMat.012CheckWPA_Multi
- network_WiFiSecMat.018CheckWPA_CounterMeasures

Change-Id: Ie7499fd87f661ceef3ef0aae348a08bd43c305f4
Reviewed-on: http://gerrit.chromium.org/gerrit/8586
Tested-by: mukesh agrawal <quiche@google.com>
Reviewed-by: Paul Stewart <pstew@chromium.org>
diff --git a/wifi_endpoint.cc b/wifi_endpoint.cc
index 300c258..3791bdc 100644
--- a/wifi_endpoint.cc
+++ b/wifi_endpoint.cc
@@ -5,41 +5,35 @@
 #include "shill/wifi_endpoint.h"
 
 #include <base/logging.h>
+#include <base/stl_util-inl.h>
 #include <base/stringprintf.h>
 #include <base/string_number_conversions.h>
+#include <base/string_util.h>
 #include <chromeos/dbus/service_constants.h>
 
+#include "shill/wpa_supplicant.h"
+
+using std::map;
+using std::set;
 using std::string;
+using std::vector;
 
 namespace shill {
 
-const char WiFiEndpoint::kSupplicantPropertySSID[]   = "SSID";
-const char WiFiEndpoint::kSupplicantPropertyBSSID[]  = "BSSID";
-const char WiFiEndpoint::kSupplicantPropertySignal[] = "Signal";
-const char WiFiEndpoint::kSupplicantPropertyMode[]   = "Mode";
-
-const char WiFiEndpoint::kSupplicantNetworkModeInfrastructure[] =
-    "infrastructure";
-const char WiFiEndpoint::kSupplicantNetworkModeAdHoc[]       = "ad-hoc";
-const char WiFiEndpoint::kSupplicantNetworkModeAccessPoint[] = "ap";
-
-const uint32_t WiFiEndpoint::kSupplicantNetworkModeInfrastructureInt = 0;
-const uint32_t WiFiEndpoint::kSupplicantNetworkModeAdHocInt          = 1;
-const uint32_t WiFiEndpoint::kSupplicantNetworkModeAccessPointInt    = 2;
-
 WiFiEndpoint::WiFiEndpoint(
-    const std::map<string, ::DBus::Variant> &properties) {
+    const map<string, ::DBus::Variant> &properties) {
   // XXX will segfault on missing properties
   ssid_ =
-      properties.find(kSupplicantPropertySSID)->second.
+      properties.find(wpa_supplicant::kBSSPropertySSID)->second.
       operator std::vector<uint8_t>();
   bssid_ =
-      properties.find(kSupplicantPropertyBSSID)->second.
+      properties.find(wpa_supplicant::kBSSPropertyBSSID)->second.
       operator std::vector<uint8_t>();
   signal_strength_ =
-      properties.find(kSupplicantPropertySignal)->second;
+      properties.find(wpa_supplicant::kBSSPropertySignal)->second;
   network_mode_ = ParseMode(
-      properties.find(kSupplicantPropertyMode)->second);
+      properties.find(wpa_supplicant::kBSSPropertyMode)->second);
+  security_mode_ = ParseSecurity(properties);
 
   if (network_mode_.empty()) {
     // XXX log error?
@@ -58,16 +52,16 @@
 // static
 uint32_t WiFiEndpoint::ModeStringToUint(const std::string &mode_string) {
   if (mode_string == flimflam::kModeManaged)
-    return kSupplicantNetworkModeInfrastructureInt;
+    return wpa_supplicant::kNetworkModeInfrastructureInt;
   else if (mode_string == flimflam::kModeAdhoc)
-    return kSupplicantNetworkModeAdHocInt;
+    return wpa_supplicant::kNetworkModeAdHocInt;
   else
     NOTIMPLEMENTED() << "Shill dos not support " << mode_string
                      << " mode at this time.";
   return 0;
 }
 
-const std::vector<uint8_t> &WiFiEndpoint::ssid() const {
+const vector<uint8_t> &WiFiEndpoint::ssid() const {
   return ssid_;
 }
 
@@ -92,16 +86,20 @@
 }
 
 const string &WiFiEndpoint::network_mode() const {
-    return network_mode_;
+  return network_mode_;
+}
+
+const string &WiFiEndpoint::security_mode() const {
+  return security_mode_;
 }
 
 // static
-const char *WiFiEndpoint::ParseMode(const std::string &mode_string) {
-  if (mode_string == kSupplicantNetworkModeInfrastructure) {
+const char *WiFiEndpoint::ParseMode(const string &mode_string) {
+  if (mode_string == wpa_supplicant::kNetworkModeInfrastructure) {
     return flimflam::kModeManaged;
-  } else if (mode_string == kSupplicantNetworkModeAdHoc) {
+  } else if (mode_string == wpa_supplicant::kNetworkModeAdHoc) {
     return flimflam::kModeAdhoc;
-  } else if (mode_string == kSupplicantNetworkModeAccessPoint) {
+  } else if (mode_string == wpa_supplicant::kNetworkModeAccessPoint) {
     NOTREACHED() << "Shill does not support AP mode at this time.";
     return NULL;
   } else {
@@ -110,4 +108,71 @@
   }
 }
 
+// static
+const char *WiFiEndpoint::ParseSecurity(
+    const map<string, ::DBus::Variant> &properties) {
+  set<KeyManagement> rsn_key_management_methods;
+  if (ContainsKey(properties, wpa_supplicant::kPropertyRSN)) {
+    // TODO(quiche): check type before casting
+    const map<string, ::DBus::Variant> rsn_properties(
+        properties.find(wpa_supplicant::kPropertyRSN)->second.
+        operator map<string, ::DBus::Variant>());
+    ParseKeyManagementMethods(rsn_properties, &rsn_key_management_methods);
+  }
+
+  set<KeyManagement> wpa_key_management_methods;
+  if (ContainsKey(properties, wpa_supplicant::kPropertyWPA)) {
+    // TODO(qucihe): check type before casting
+    const map<string, ::DBus::Variant> rsn_properties(
+        properties.find(wpa_supplicant::kPropertyWPA)->second.
+        operator map<string, ::DBus::Variant>());
+    ParseKeyManagementMethods(rsn_properties, &wpa_key_management_methods);
+  }
+
+  bool wep_privacy = false;
+  if (ContainsKey(properties, wpa_supplicant::kPropertyPrivacy)) {
+    wep_privacy = properties.find(wpa_supplicant::kPropertyPrivacy)->second.
+        reader().get_bool();
+  }
+
+  if (ContainsKey(rsn_key_management_methods, kKeyManagement802_1x) ||
+      ContainsKey(wpa_key_management_methods, kKeyManagement802_1x)) {
+    return flimflam::kSecurity8021x;
+  } else if (ContainsKey(rsn_key_management_methods, kKeyManagementPSK)) {
+    return flimflam::kSecurityRsn;
+  } else if (ContainsKey(wpa_key_management_methods, kKeyManagementPSK)) {
+    return flimflam::kSecurityWpa;
+  } else if (wep_privacy) {
+    return flimflam::kSecurityWep;
+  } else {
+    return flimflam::kSecurityNone;
+  }
+}
+
+// static
+void WiFiEndpoint::ParseKeyManagementMethods(
+    const map<string, ::DBus::Variant> &security_method_properties,
+    set<KeyManagement> *key_management_methods) {
+  if (!ContainsKey(security_method_properties,
+                   wpa_supplicant::kSecurityMethodPropertyKeyManagement)) {
+    return;
+  }
+
+  // TODO(quiche): check type before cast
+  const vector<string> key_management_vec =
+      security_method_properties.
+      find(wpa_supplicant::kSecurityMethodPropertyKeyManagement)->second.
+      operator vector<string>();
+  for (vector<string>::const_iterator it = key_management_vec.begin();
+       it != key_management_vec.end();
+       ++it) {
+    if (EndsWith(*it, wpa_supplicant::kKeyManagementMethodSuffixEAP, true)) {
+      key_management_methods->insert(kKeyManagement802_1x);
+    } else if (
+        EndsWith(*it, wpa_supplicant::kKeyManagementMethodSuffixPSK, true)) {
+      key_management_methods->insert(kKeyManagementPSK);
+    }
+  }
+}
+
 }  // namespace shill