shill: Add support for connecting to WEP networks

BUG=chromium-os:20898
TEST=Unit tests, manually modified network_WiFiManager WEP tests to
connect using various passwords (the WEP tests cannot complete
successfully until shill supports service disconnect),
network_WiFiManager/*WPA* tests

Change-Id: I6a962810983d04776e9ce39bb5e6f8c378aacb7b
Reviewed-on: https://gerrit.chromium.org/gerrit/11511
Commit-Ready: Thieu Le <thieule@chromium.org>
Reviewed-by: Thieu Le <thieule@chromium.org>
Tested-by: Thieu Le <thieule@chromium.org>
diff --git a/wifi_service.cc b/wifi_service.cc
index a3afe3d..8390273 100644
--- a/wifi_service.cc
+++ b/wifi_service.cc
@@ -136,12 +136,17 @@
 
 void WiFiService::SetPassphrase(const string &passphrase, Error *error) {
   if (security_ == flimflam::kSecurityWep) {
-    passphrase_ = ParseWEPPassphrase(passphrase, error);
+    ValidateWEPPassphrase(passphrase, error);
   } else if (security_ == flimflam::kSecurityPsk ||
              security_ == flimflam::kSecurityWpa ||
              security_ == flimflam::kSecurityRsn) {
-    passphrase_ = ParseWPAPassphrase(passphrase, error);
+    ValidateWPAPassphrase(passphrase, error);
+  } else {
+    error->Populate(Error::kNotSupported);
   }
+
+  if (error->IsSuccess())
+    passphrase_ = passphrase;
 }
 
 bool WiFiService::IsLoadableFrom(StoreInterface *storage) const {
@@ -220,7 +225,17 @@
     params[wpa_supplicant::kPropertyPreSharedKey].writer().
         append_string(passphrase_.c_str());
   } else if (security_ == flimflam::kSecurityWep) {
-    NOTIMPLEMENTED();
+    params[wpa_supplicant::kPropertyAuthAlg].writer().
+        append_string(wpa_supplicant::kSecurityAuthAlg);
+    Error error;
+    int key_index;
+    std::vector<uint8> password_bytes;
+    ParseWEPPassphrase(passphrase_, &key_index, &password_bytes, &error);
+    writer = params[wpa_supplicant::kPropertyWEPKey +
+                    base::IntToString(key_index)].writer();
+    writer << password_bytes;
+    params[wpa_supplicant::kPropertyWEPTxKeyIndex].writer().
+        append_uint32(key_index);
   } else if (security_ == flimflam::kSecurityNone) {
     // Nothing special to do here.
   } else {
@@ -242,48 +257,14 @@
 }
 
 // static
-string WiFiService::ParseWEPPassphrase(const string &passphrase, Error *error) {
-  unsigned int length = passphrase.length();
-
-  switch (length) {
-    case IEEE_80211::kWEP40AsciiLen:
-    case IEEE_80211::kWEP104AsciiLen:
-      break;
-    case IEEE_80211::kWEP40AsciiLen + 2:
-    case IEEE_80211::kWEP104AsciiLen + 2:
-      CheckWEPKeyIndex(passphrase, error);
-      break;
-    case IEEE_80211::kWEP40HexLen:
-    case IEEE_80211::kWEP104HexLen:
-      CheckWEPIsHex(passphrase, error);
-      break;
-    case IEEE_80211::kWEP40HexLen + 2:
-    case IEEE_80211::kWEP104HexLen + 2:
-      (CheckWEPKeyIndex(passphrase, error) ||
-       CheckWEPPrefix(passphrase, error)) &&
-          CheckWEPIsHex(passphrase.substr(2), error);
-      break;
-    case IEEE_80211::kWEP40HexLen + 4:
-    case IEEE_80211::kWEP104HexLen + 4:
-      CheckWEPKeyIndex(passphrase, error) &&
-          CheckWEPPrefix(passphrase.substr(2), error) &&
-          CheckWEPIsHex(passphrase.substr(4), error);
-      break;
-    default:
-      error->Populate(Error::kInvalidPassphrase);
-      break;
-  }
-
-  // TODO(quiche): may need to normalize passphrase format
-  if (error->IsSuccess()) {
-    return passphrase;
-  } else {
-    return "";
-  }
+void WiFiService::ValidateWEPPassphrase(const std::string &passphrase,
+                                        Error *error) {
+  ParseWEPPassphrase(passphrase, NULL, NULL, error);
 }
 
 // static
-string WiFiService::ParseWPAPassphrase(const string &passphrase, Error *error) {
+void WiFiService::ValidateWPAPassphrase(const std::string &passphrase,
+                                        Error *error) {
   unsigned int length = passphrase.length();
   vector<uint8> passphrase_bytes;
 
@@ -299,12 +280,79 @@
       error->Populate(Error::kInvalidPassphrase);
     }
   }
+}
 
-  // TODO(quiche): may need to normalize passphrase format
+// static
+void WiFiService::ParseWEPPassphrase(const string &passphrase,
+                                     int *key_index,
+                                     std::vector<uint8> *password_bytes,
+                                     Error *error) {
+  unsigned int length = passphrase.length();
+  int key_index_local;
+  std::string password_text;
+  bool is_hex = false;
+
+  switch (length) {
+    case IEEE_80211::kWEP40AsciiLen:
+    case IEEE_80211::kWEP104AsciiLen:
+      key_index_local = 0;
+      password_text = passphrase;
+      break;
+    case IEEE_80211::kWEP40AsciiLen + 2:
+    case IEEE_80211::kWEP104AsciiLen + 2:
+      if (CheckWEPKeyIndex(passphrase, error)) {
+        base::StringToInt(passphrase.substr(0,1), &key_index_local);
+        password_text = passphrase.substr(2);
+      }
+      break;
+    case IEEE_80211::kWEP40HexLen:
+    case IEEE_80211::kWEP104HexLen:
+      if (CheckWEPIsHex(passphrase, error)) {
+        key_index_local = 0;
+        password_text = passphrase;
+        is_hex = true;
+      }
+      break;
+    case IEEE_80211::kWEP40HexLen + 2:
+    case IEEE_80211::kWEP104HexLen + 2:
+      if(CheckWEPKeyIndex(passphrase, error) &&
+         CheckWEPIsHex(passphrase.substr(2), error)) {
+        base::StringToInt(passphrase.substr(0,1), &key_index_local);
+        password_text = passphrase.substr(2);
+        is_hex = true;
+      } else if (CheckWEPPrefix(passphrase, error) &&
+                 CheckWEPIsHex(passphrase.substr(2), error)) {
+        key_index_local = 0;
+        password_text = passphrase.substr(2);
+        is_hex = true;
+      }
+      break;
+    case IEEE_80211::kWEP40HexLen + 4:
+    case IEEE_80211::kWEP104HexLen + 4:
+      if (CheckWEPKeyIndex(passphrase, error) &&
+          CheckWEPPrefix(passphrase.substr(2), error) &&
+          CheckWEPIsHex(passphrase.substr(4), error)) {
+        base::StringToInt(passphrase.substr(0,1), &key_index_local);
+        password_text = passphrase.substr(4);
+        is_hex = true;
+      }
+      break;
+    default:
+      error->Populate(Error::kInvalidPassphrase);
+      break;
+  }
+
   if (error->IsSuccess()) {
-    return passphrase;
-  } else {
-    return "";
+    if (key_index)
+      *key_index = key_index_local;
+    if (password_bytes) {
+      if (is_hex)
+        base::HexStringToBytes(password_text, password_bytes);
+      else
+        password_bytes->insert(password_bytes->end(),
+                               password_text.begin(),
+                               password_text.end());
+    }
   }
 }