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/HACKING b/HACKING
index 3a1f7c2..109de02 100644
--- a/HACKING
+++ b/HACKING
@@ -31,10 +31,12 @@
- Read data via the appropriate named method, rather than depending on
implicit conversion. E.g.,
+ ::DBus::Variant var;
int8 data = var.reader().get_byte();
rather than
+ ::DBus::Variant var;
int8 data = var;
RATIONALE: The explicit version is only marginally longer than the
@@ -44,12 +46,52 @@
- Where there is no named method, call the appropriate cast operator
explicitly. E.g.
+ ::DBus::Variant var;
vector<unsigned int> data = var.operator vector<unsigned int>();
RATIONALE: Calling the cast operator explicitly avoids conflicts with
constructors that might also be used to make the conversion. It also
avoids requiring that the reader understand C++ conversion rules.
+ - Write data via the appropriate named method. E.g.,
+
+ ::DBus::Variant var;
+ int16_t data;
+ var.writer().append_int16(data);
+
+ rather than
+
+ ::DBus::Variant var;
+ int16_t data;
+ var.writer() << data;
+
+ RATIONALE: Similarly as for reading, the explicit version is only
+ marginally longer, and does not require the reader to understand
+ overload resolution.
+
+ - Where there is no named method, write by using the stream
+ insertion operator. E.g.
+
+ ::DBus::Variant var;
+ ::DBus::MessageIter writer;
+ map<string, string> data;
+ writer = var.writer();
+ writer << data;
+
+ RATIONALE: This case is somewhat unfortunate, because it's not as
+ clear as its analogue for reading. However, the alternative is to
+ duplicate the code of the stream insertion operator overloads.
+
+ Note that the writer can't be omitted. E.g.
+
+ ::DBus::Variant var;
+ map<string, string> data;
+ var.writer() << data;
+
+ does not work (at least for some types of |data|). Without the
+ intermediate variable, g++ seems to ignore templates during
+ overload resolution.
+
- When deferring work from a signal handler (e.g. a D-Bus callback) to
the event loop, name the deferred work function by adding "Task" to
the name of the function deferring the work. E.g.
diff --git a/Makefile b/Makefile
index c1f4639..38caba0 100644
--- a/Makefile
+++ b/Makefile
@@ -131,7 +131,8 @@
technology.o \
wifi.o \
wifi_endpoint.o \
- wifi_service.o
+ wifi_service.o \
+ wpa_supplicant.o
SHILL_BIN = shill
SHILL_MAIN_OBJ = shill_main.o
@@ -199,6 +200,7 @@
service_unittest.o \
shill_unittest.o \
testrunner.o \
+ wifi_endpoint_unittest.o \
wifi_service_unittest.o \
wifi_unittest.o
diff --git a/mock_wifi.h b/mock_wifi.h
index 9dc8430..fb3c428 100644
--- a/mock_wifi.h
+++ b/mock_wifi.h
@@ -36,6 +36,9 @@
MOCK_METHOD1(Scan, void(Error *error));
MOCK_METHOD2(GetService,
WiFiServiceRefPtr(const KeyValueStore &args, Error *error));
+ MOCK_METHOD2(ConnectTo,
+ void(WiFiService *,
+ const std::map<std::string, ::DBus::Variant> &));
private:
DISALLOW_COPY_AND_ASSIGN(MockWiFi);
diff --git a/wifi.cc b/wifi.cc
index f11a517..f6602c3 100644
--- a/wifi.cc
+++ b/wifi.cc
@@ -32,6 +32,7 @@
#include "shill/supplicant_process_proxy_interface.h"
#include "shill/wifi_endpoint.h"
#include "shill/wifi_service.h"
+#include "shill/wpa_supplicant.h"
using std::map;
using std::string;
@@ -55,17 +56,6 @@
"service type is unsupported";
const char WiFi::kManagerErrorUnsupportedServiceMode[] =
"service mode is unsupported";
-const char WiFi::kSupplicantPath[] = "/fi/w1/wpa_supplicant1";
-const char WiFi::kSupplicantDBusAddr[] = "fi.w1.wpa_supplicant1";
-const char WiFi::kSupplicantWiFiDriver[] = "nl80211";
-const char WiFi::kSupplicantErrorInterfaceExists[] =
- "fi.w1.wpa_supplicant1.InterfaceExists";
-const char WiFi::kSupplicantPropertySSID[] = "ssid";
-const char WiFi::kSupplicantPropertyNetworkMode[] = "mode";
-const char WiFi::kSupplicantPropertyKeyMode[] = "key_mgmt";
-const char WiFi::kSupplicantPropertyScanType[] = "Type";
-const char WiFi::kSupplicantKeyModeNone[] = "NONE";
-const char WiFi::kSupplicantScanTypeActive[] = "active";
// NB: we assume supplicant is already running. [quiche.20110518]
WiFi::WiFi(ControlInterface *control_interface,
@@ -109,19 +99,19 @@
supplicant_process_proxy_.reset(
ProxyFactory::factory()->CreateSupplicantProcessProxy(
- kSupplicantPath, kSupplicantDBusAddr));
+ wpa_supplicant::kDBusPath, wpa_supplicant::kDBusAddr));
try {
std::map<string, DBus::Variant> create_interface_args;
create_interface_args["Ifname"].writer().
append_string(link_name().c_str());
create_interface_args["Driver"].writer().
- append_string(kSupplicantWiFiDriver);
+ append_string(wpa_supplicant::kDriverNL80211);
// TODO(quiche) create_interface_args["ConfigFile"].writer().append_string
// (file with pkcs config info)
interface_path =
supplicant_process_proxy_->CreateInterface(create_interface_args);
} catch (const DBus::Error e) { // NOLINT
- if (!strcmp(e.name(), kSupplicantErrorInterfaceExists)) {
+ if (!strcmp(e.name(), wpa_supplicant::kErrorInterfaceExists)) {
interface_path =
supplicant_process_proxy_->GetInterface(link_name());
// XXX crash here, if device missing?
@@ -132,7 +122,7 @@
supplicant_interface_proxy_.reset(
ProxyFactory::factory()->CreateSupplicantInterfaceProxy(
- this, interface_path, kSupplicantDBusAddr));
+ this, interface_path, wpa_supplicant::kDBusAddr));
// TODO(quiche) set ApScan=1 and BSSExpireAge=190, like flimflam does?
@@ -239,25 +229,21 @@
task_factory_.NewRunnableMethod(&WiFi::ScanDoneTask));
}
-void WiFi::ConnectTo(WiFiService *service) {
- std::map<string, DBus::Variant> add_network_args;
- DBus::MessageIter writer;
+void WiFi::ConnectTo(WiFiService *service,
+ const map<string, DBus::Variant> &service_params) {
DBus::Path network_path;
// TODO(quiche): handle cases where already connected
- add_network_args[kSupplicantPropertyNetworkMode].writer().
- append_uint32(WiFiEndpoint::ModeStringToUint(service->mode()));
- add_network_args[kSupplicantPropertyKeyMode].writer().
- append_string(service->key_management().c_str());
- // TODO(quiche): figure out why we can't use operator<< without the
- // temporary variable.
- writer = add_network_args[kSupplicantPropertySSID].writer();
- writer << service->ssid();
- // TODO(quiche): set scan_ssid=1, like flimflam does?
+ // TODO(quiche): set scan_ssid=1 in service_params, like flimflam does?
+ try {
+ network_path =
+ supplicant_interface_proxy_->AddNetwork(service_params);
+ } catch (const DBus::Error e) { // NOLINT
+ LOG(ERROR) << "exception while adding network: " << e.what();
+ return;
+ }
- network_path =
- supplicant_interface_proxy_->AddNetwork(add_network_args);
supplicant_interface_proxy_->SelectNetwork(network_path);
// XXX add to favorite networks list?
@@ -289,10 +275,9 @@
LOG(INFO) << "found new endpoint. "
<< "ssid: " << endpoint.ssid_string() << ", "
<< "bssid: " << endpoint.bssid_string() << ", "
- << "signal: " << endpoint.signal_strength();
+ << "signal: " << endpoint.signal_strength() << ", "
+ << "security: " << endpoint.security_mode();
- // XXX key mode should reflect endpoint params (not always use
- // kSupplicantKeyModeNone)
WiFiServiceRefPtr service(
new WiFiService(control_interface(),
dispatcher(),
@@ -300,7 +285,7 @@
this,
endpoint.ssid(),
endpoint.network_mode(),
- kSupplicantKeyModeNone));
+ endpoint.security_mode()));
services()->push_back(service);
service_by_private_id_[service_id_private] = service;
manager()->RegisterService(service);
@@ -315,8 +300,8 @@
void WiFi::ScanTask() {
VLOG(2) << "WiFi " << link_name() << " scan requested.";
std::map<string, DBus::Variant> scan_args;
- scan_args[kSupplicantPropertyScanType].writer().
- append_string(kSupplicantScanTypeActive);
+ scan_args[wpa_supplicant::kPropertyScanType].writer().
+ append_string(wpa_supplicant::kScanTypeActive);
// TODO(quiche) indicate scanning in UI
supplicant_interface_proxy_->Scan(scan_args);
scan_pending_ = true;
diff --git a/wifi.h b/wifi.h
index 7687215..919891f 100644
--- a/wifi.h
+++ b/wifi.h
@@ -47,7 +47,9 @@
void ScanDone();
// called by WiFiService
- void ConnectTo(WiFiService *service);
+ virtual void ConnectTo(
+ WiFiService *service,
+ const std::map<std::string, ::DBus::Variant> &service_params);
// called by Manager
virtual WiFiServiceRefPtr GetService(const KeyValueStore &args, Error *error);
@@ -64,16 +66,6 @@
static const char kManagerErrorUnsupportedSecurityMode[];
static const char kManagerErrorUnsupportedServiceType[];
static const char kManagerErrorUnsupportedServiceMode[];
- static const char kSupplicantPath[];
- static const char kSupplicantDBusAddr[];
- static const char kSupplicantWiFiDriver[];
- static const char kSupplicantErrorInterfaceExists[];
- static const char kSupplicantPropertySSID[];
- static const char kSupplicantPropertyNetworkMode[];
- static const char kSupplicantPropertyKeyMode[];
- static const char kSupplicantPropertyScanType[];
- static const char kSupplicantKeyModeNone[];
- static const char kSupplicantScanTypeActive[];
void ScanDoneTask();
void ScanTask();
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
diff --git a/wifi_endpoint.h b/wifi_endpoint.h
index 17bf60b..c7b161c 100644
--- a/wifi_endpoint.h
+++ b/wifi_endpoint.h
@@ -6,11 +6,13 @@
#define SHILL_WIFI_ENDPOINT_
#include <map>
+#include <set>
#include <string>
#include <vector>
#include <base/memory/ref_counted.h>
#include <dbus-c++/dbus.h>
+#include <gtest/gtest_prod.h> // for FRIEND_TEST
#include "shill/endpoint.h"
#include "shill/shill_event.h"
@@ -33,24 +35,34 @@
const std::string &bssid_hex() const;
int16_t signal_strength() const;
const std::string &network_mode() const;
+ const std::string &security_mode() const;
private:
- static const uint32_t kSupplicantNetworkModeInfrastructureInt;
- static const uint32_t kSupplicantNetworkModeAdHocInt;
- static const uint32_t kSupplicantNetworkModeAccessPointInt;
+ friend class WiFiEndpointTest;
+ // these test cases need access to the KeyManagement enum
+ FRIEND_TEST(WiFiEndpointTest, ParseKeyManagementMethodsEAP);
+ FRIEND_TEST(WiFiEndpointTest, ParseKeyManagementMethodsPSK);
+ FRIEND_TEST(WiFiEndpointTest, ParseKeyManagementMethodsEAPAndPSK);
- static const char kSupplicantPropertySSID[];
- static const char kSupplicantPropertyBSSID[];
- static const char kSupplicantPropertySignal[];
- static const char kSupplicantPropertyMode[];
- static const char kSupplicantNetworkModeInfrastructure[];
- static const char kSupplicantNetworkModeAdHoc[];
- static const char kSupplicantNetworkModeAccessPoint[];
+ enum KeyManagement {
+ kKeyManagement802_1x,
+ kKeyManagementPSK
+ };
// Maps mode strings from supplicant into flimflam's nomenclature, as defined
// in chromeos/dbus/service_constants.h
static const char *ParseMode(const std::string &mode_string);
+ // Parses an Endpoint's properties to identify approprirate flimflam
+ // security property value, as defined in chromeos/dbus/service_constants.h
+ static const char *ParseSecurity(
+ const std::map<std::string, ::DBus::Variant> &properties);
+ // Parses and Endpoint's properties' "RSN" or "WPA" sub-dictionary, to
+ // identify supported key management methods (802.1x or PSK).
+ static void ParseKeyManagementMethods(
+ const std::map<std::string, ::DBus::Variant> &security_method_properties,
+ std::set<KeyManagement> *key_management_methods);
+ // TODO(quiche): make const?
std::vector<uint8_t> ssid_;
std::vector<uint8_t> bssid_;
std::string ssid_string_;
@@ -58,7 +70,10 @@
std::string bssid_string_;
std::string bssid_hex_;
int16_t signal_strength_;
+ // network_mode_ and security_mode_ are represented as flimflam names
+ // (not necessarily the same as wpa_supplicant names)
std::string network_mode_;
+ std::string security_mode_;
DISALLOW_COPY_AND_ASSIGN(WiFiEndpoint);
};
diff --git a/wifi_endpoint_unittest.cc b/wifi_endpoint_unittest.cc
new file mode 100644
index 0000000..cb02824
--- /dev/null
+++ b/wifi_endpoint_unittest.cc
@@ -0,0 +1,138 @@
+// Copyright (c) 2011 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 "shill/wifi_endpoint.h"
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <base/stl_util-inl.h>
+#include <chromeos/dbus/service_constants.h>
+#include <gtest/gtest.h>
+
+#include "shill/wpa_supplicant.h"
+
+using std::map;
+using std::set;
+using std::string;
+using std::vector;
+
+using ::testing::Test;
+
+namespace shill {
+
+class WiFiEndpointTest : public Test {
+ public:
+ WiFiEndpointTest() {}
+ virtual ~WiFiEndpointTest() {}
+
+ protected:
+ vector<string> make_string_vector1(const string &str1) {
+ vector<string> strvec;
+ strvec.push_back(str1);
+ return strvec;
+ }
+
+ vector<string> make_string_vector2(const string &str1, const string &str2) {
+ vector<string> strvec;
+ strvec.push_back(str1);
+ strvec.push_back(str2);
+ return strvec;
+ }
+
+ map<string, ::DBus::Variant> make_key_management_args(
+ vector<string> key_management_method_strings) {
+ map<string, ::DBus::Variant> args;
+ ::DBus::MessageIter writer;
+ writer =
+ args[wpa_supplicant::kSecurityMethodPropertyKeyManagement].writer();
+ writer << key_management_method_strings;
+ return args;
+ }
+
+ map<string, ::DBus::Variant> make_security_args(
+ const string &security_protocol,
+ const string &key_management_method) {
+ map<string, ::DBus::Variant> args;
+ ::DBus::MessageIter writer;
+ writer = args[security_protocol].writer();
+ writer <<
+ make_key_management_args(make_string_vector1(key_management_method));
+ return args;
+ }
+
+ const char *ParseSecurity(
+ const map<string, ::DBus::Variant> &properties) {
+ return WiFiEndpoint::ParseSecurity(properties);
+ }
+};
+
+TEST_F(WiFiEndpointTest, ParseKeyManagementMethodsEAP) {
+ set<WiFiEndpoint::KeyManagement> parsed_methods;
+ WiFiEndpoint::ParseKeyManagementMethods(
+ make_key_management_args(make_string_vector1("something-eap")),
+ &parsed_methods);
+ EXPECT_TRUE(
+ ContainsKey(parsed_methods, WiFiEndpoint::kKeyManagement802_1x));
+ EXPECT_FALSE(
+ ContainsKey(parsed_methods, WiFiEndpoint::kKeyManagementPSK));
+}
+
+TEST_F(WiFiEndpointTest, ParseKeyManagementMethodsPSK) {
+ set<WiFiEndpoint::KeyManagement> parsed_methods;
+ WiFiEndpoint::ParseKeyManagementMethods(
+ make_key_management_args(make_string_vector1("something-psk")),
+ &parsed_methods);
+ EXPECT_TRUE(
+ ContainsKey(parsed_methods, WiFiEndpoint::kKeyManagementPSK));
+ EXPECT_FALSE(
+ ContainsKey(parsed_methods, WiFiEndpoint::kKeyManagement802_1x));
+}
+
+TEST_F(WiFiEndpointTest, ParseKeyManagementMethodsEAPAndPSK) {
+ set<WiFiEndpoint::KeyManagement> parsed_methods;
+ WiFiEndpoint::ParseKeyManagementMethods(
+ make_key_management_args(
+ make_string_vector2("something-eap", "something-psk")),
+ &parsed_methods);
+ EXPECT_TRUE(
+ ContainsKey(parsed_methods, WiFiEndpoint::kKeyManagement802_1x));
+ EXPECT_TRUE(
+ ContainsKey(parsed_methods, WiFiEndpoint::kKeyManagementPSK));
+}
+
+TEST_F(WiFiEndpointTest, ParseSecurityRSN802_1x) {
+ EXPECT_STREQ(flimflam::kSecurity8021x,
+ ParseSecurity(make_security_args("RSN", "something-eap")));
+}
+
+TEST_F(WiFiEndpointTest, ParseSecurityWPA802_1x) {
+ EXPECT_STREQ(flimflam::kSecurity8021x,
+ ParseSecurity(make_security_args("WPA", "something-eap")));
+}
+
+TEST_F(WiFiEndpointTest, ParseSecurityRSNPSK) {
+ EXPECT_STREQ(flimflam::kSecurityRsn,
+ ParseSecurity(make_security_args("RSN", "something-psk")));
+}
+
+TEST_F(WiFiEndpointTest, ParseSecurityWPAPSK) {
+ EXPECT_STREQ(flimflam::kSecurityWpa,
+ ParseSecurity(make_security_args("WPA", "something-psk")));
+}
+
+TEST_F(WiFiEndpointTest, ParseSecurityWEP) {
+ map<string, ::DBus::Variant> top_params;
+ top_params[wpa_supplicant::kPropertyPrivacy].writer().append_bool(true);
+ EXPECT_STREQ(flimflam::kSecurityWep, ParseSecurity(top_params));
+}
+
+TEST_F(WiFiEndpointTest, ParseSecurityNone) {
+ map<string, ::DBus::Variant> top_params;
+ EXPECT_STREQ(flimflam::kSecurityNone, ParseSecurity(top_params));
+}
+
+} // namespace shill
diff --git a/wifi_service.cc b/wifi_service.cc
index 881bf1d..861e969 100644
--- a/wifi_service.cc
+++ b/wifi_service.cc
@@ -11,11 +11,14 @@
#include <base/string_number_conversions.h>
#include <base/string_util.h>
#include <chromeos/dbus/service_constants.h>
+#include <dbus/dbus.h>
#include "shill/control_interface.h"
#include "shill/device.h"
#include "shill/shill_event.h"
#include "shill/wifi.h"
+#include "shill/wifi_endpoint.h"
+#include "shill/wpa_supplicant.h"
using std::string;
@@ -27,15 +30,13 @@
const WiFiRefPtr &device,
const std::vector<uint8_t> ssid,
const std::string &mode,
- const std::string &key_management)
+ const std::string &security)
: Service(control_interface, dispatcher, manager, flimflam::kTypeWifi),
- security_(flimflam::kSecurityNone),
+ security_(security),
mode_(mode),
task_factory_(this),
wifi_(device),
ssid_(ssid) {
- SetEAPKeyManagement(key_management);
-
PropertyStore *store = this->mutable_store();
store->RegisterConstString(flimflam::kModeProperty, &mode_);
store->RegisterString(flimflam::kPassphraseProperty, &passphrase_);
@@ -54,8 +55,30 @@
"_" +
string(reinterpret_cast<const char*>(ssid_.data()), ssid_.size()));
- // TODO(quiche): set based on security properties
- need_passphrase_ = false;
+ // TODO(quiche): determine if it is okay to set EAP.KeyManagement for
+ // a service that is not 802.1x.
+ if (security_ == flimflam::kSecurity8021x) {
+ NOTIMPLEMENTED();
+ // XXX needs_passpharse_ = false ?
+ } else if (security_ == flimflam::kSecurityPsk) {
+ SetEAPKeyManagement("WPA-PSK");
+ need_passphrase_ = true;
+ } else if (security_ == flimflam::kSecurityRsn) {
+ SetEAPKeyManagement("WPA-PSK");
+ need_passphrase_ = true;
+ } else if (security_ == flimflam::kSecurityWpa) {
+ SetEAPKeyManagement("WPA-PSK");
+ need_passphrase_ = true;
+ } else if (security_ == flimflam::kSecurityWep) {
+ SetEAPKeyManagement("NONE");
+ need_passphrase_ = true;
+ } else if (security_ == flimflam::kSecurityNone) {
+ SetEAPKeyManagement("NONE");
+ need_passphrase_ = false;
+ } else {
+ LOG(ERROR) << "unsupported security method " << security_;
+ }
+
// TODO(quiche): figure out when to set true
hidden_ssid_ = false;
}
@@ -105,7 +128,39 @@
// private methods
void WiFiService::ConnectTask() {
- wifi_->ConnectTo(this);
+ std::map<string, DBus::Variant> params;
+ DBus::MessageIter writer;
+
+ params[wpa_supplicant::kNetworkPropertyMode].writer().
+ append_uint32(WiFiEndpoint::ModeStringToUint(mode_));
+
+ if (security_ == flimflam::kSecurity8021x) {
+ NOTIMPLEMENTED();
+ } else if (security_ == flimflam::kSecurityPsk) {
+ NOTIMPLEMENTED();
+ } else if (security_ == flimflam::kSecurityRsn) {
+ NOTIMPLEMENTED();
+ } else if (security_ == flimflam::kSecurityWpa) {
+ params[wpa_supplicant::kPropertySecurityProtocol].writer().
+ append_string(wpa_supplicant::kSecurityModeWPA);
+ params[wpa_supplicant::kPropertyPreSharedKey].writer().
+ append_string(passphrase_.c_str());
+ } else if (security_ == flimflam::kSecurityWep) {
+ NOTIMPLEMENTED();
+ } else if (security_ == flimflam::kSecurityNone) {
+ // nothing special to do here
+ } else {
+ LOG(ERROR) << "can't connect. unsupported security method " << security_;
+ }
+
+ params[wpa_supplicant::kPropertyKeyManagement].writer().
+ append_string(key_management().c_str());
+ // TODO(quiche): figure out why we can't use operator<< without the
+ // temporary variable.
+ writer = params[wpa_supplicant::kNetworkPropertySSID].writer();
+ writer << ssid_;
+
+ wifi_->ConnectTo(this, params);
}
string WiFiService::GetDeviceRpcId() {
diff --git a/wifi_service.h b/wifi_service.h
index 66c0630..a6e7aa6 100644
--- a/wifi_service.h
+++ b/wifi_service.h
@@ -27,7 +27,7 @@
const WiFiRefPtr &device,
const std::vector<uint8_t> ssid,
const std::string &mode,
- const std::string &key_management);
+ const std::string &security);
~WiFiService();
// Inherited from Service.
@@ -44,6 +44,8 @@
const std::vector<uint8_t> &ssid() const;
private:
+ FRIEND_TEST(WiFiServiceTest, ConnectTask);
+
void ConnectTask();
std::string GetDeviceRpcId();
diff --git a/wifi_service_unittest.cc b/wifi_service_unittest.cc
index e142d86..cd68eca 100644
--- a/wifi_service_unittest.cc
+++ b/wifi_service_unittest.cc
@@ -17,36 +17,53 @@
#include "shill/mock_control.h"
#include "shill/mock_service.h"
#include "shill/mock_store.h"
+#include "shill/mock_wifi.h"
#include "shill/property_store_unittest.h"
#include "shill/shill_event.h"
-#include "shill/wifi.h"
+#include "shill/wpa_supplicant.h"
using std::string;
using std::vector;
namespace shill {
+using ::testing::NiceMock;
class WiFiServiceTest : public PropertyStoreTest {
public:
- WiFiServiceTest() {}
+ WiFiServiceTest() : wifi_(
+ new NiceMock<MockWiFi>(
+ control_interface(),
+ dispatcher(),
+ manager(),
+ "wifi",
+ fake_mac,
+ 0)) {}
virtual ~WiFiServiceTest() {}
+
+ protected:
+ static const char fake_mac[];
+ scoped_refptr<MockWiFi> wifi() { return wifi_; }
+
+ private:
+ scoped_refptr<MockWiFi> wifi_;
};
+// static
+const char WiFiServiceTest::fake_mac[] = "AaBBcCDDeeFF";
+
+MATCHER(WPASecurityArgs, "") {
+ return ContainsKey(arg, wpa_supplicant::kPropertySecurityProtocol) &&
+ ContainsKey(arg, wpa_supplicant::kPropertyPreSharedKey);
+}
+
TEST_F(WiFiServiceTest, StorageId) {
vector<uint8_t> ssid(5, 0);
ssid.push_back(0xff);
- static const char fake_mac[] = "AaBBcCDDeeFF";
- WiFiRefPtr wifi = new WiFi(control_interface(),
- dispatcher(),
- manager(),
- "wifi",
- fake_mac,
- 0);
WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
dispatcher(),
manager(),
- wifi,
+ wifi(),
ssid,
flimflam::kModeManaged,
"none");
@@ -62,4 +79,18 @@
EXPECT_NE(id.find(string(flimflam::kModeManaged), mac_pos), string::npos);
}
+TEST_F(WiFiServiceTest, ConnectTask) {
+ vector<uint8_t> ssid(5, 0);
+ WiFiServiceRefPtr wifi_service = new WiFiService(control_interface(),
+ dispatcher(),
+ manager(),
+ wifi(),
+ ssid,
+ flimflam::kModeManaged,
+ flimflam::kSecurityWpa);
+ EXPECT_CALL(*wifi(),
+ ConnectTo(wifi_service.get(), WPASecurityArgs()));
+ wifi_service->ConnectTask();
+}
+
} // namespace shill
diff --git a/wifi_unittest.cc b/wifi_unittest.cc
index dae7dad..f732e16 100644
--- a/wifi_unittest.cc
+++ b/wifi_unittest.cc
@@ -176,7 +176,8 @@
return wifi_->supplicant_interface_proxy_.get();
}
void InitiateConnect(WiFiService *service) {
- wifi_->ConnectTo(service);
+ map<string, ::DBus::Variant> params;
+ wifi_->ConnectTo(service, params);
}
bool IsLinkUp() {
return wifi_->link_up_;
diff --git a/wpa_supplicant.cc b/wpa_supplicant.cc
new file mode 100644
index 0000000..1740220
--- /dev/null
+++ b/wpa_supplicant.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2011 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 "shill/wpa_supplicant.h"
+
+namespace shill {
+
+namespace wpa_supplicant {
+const char kBSSPropertyBSSID[] = "BSSID";
+const char kBSSPropertySSID[] = "SSID";
+const char kBSSPropertyMode[] = "Mode";
+const char kBSSPropertySignal[] = "Signal";
+const char kDBusAddr[] = "fi.w1.wpa_supplicant1";
+const char kDBusPath[] = "/fi/w1/wpa_supplicant1";
+const char kDriverNL80211[] = "nl80211";
+const char kErrorInterfaceExists[] = "fi.w1.wpa_supplicant1.InterfaceExists";
+const char kKeyManagementMethodSuffixEAP[] = "-eap";
+const char kKeyManagementMethodSuffixPSK[] = "-psk";
+const char kKeyModeNone[] = "NONE";
+const char kNetworkModeInfrastructure[] = "infrastructure";
+const char kNetworkModeAdHoc[] = "ad-hoc";
+const char kNetworkModeAccessPoint[] = "ap";
+const char kNetworkPropertyMode[] = "mode";
+const char kNetworkPropertySSID[] = "ssid";
+const char kPropertyKeyManagement[] = "key_mgmt";
+const char kPropertyPreSharedKey[] = "psk";
+const char kPropertyPrivacy[] = "Privacy";
+const char kPropertyRSN[] = "RSN";
+const char kPropertyScanType[] = "Type";
+const char kPropertySecurityProtocol[] = "proto";
+const char kPropertyWPA[] = "WPA";
+const char kScanTypeActive[] = "active";
+const char kSecurityMethodPropertyKeyManagement[] = "KeyMgmt";
+const char kSecurityModeRSN[] = "RSN";
+const char kSecurityModeWPA[] = "WPA";
+
+const uint32_t kNetworkModeInfrastructureInt = 0;
+const uint32_t kNetworkModeAdHocInt = 1;
+const uint32_t kNetworkModeAccessPointInt = 2;
+};
+
+} // namespace shill
diff --git a/wpa_supplicant.h b/wpa_supplicant.h
new file mode 100644
index 0000000..1152ded
--- /dev/null
+++ b/wpa_supplicant.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2011 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.
+
+#ifndef SHILL_WPA_SUPPLICANT_H
+#define SHILL_WPA_SUPPLICANT_H
+
+#include <base/basictypes.h>
+
+namespace shill {
+
+namespace wpa_supplicant {
+extern const char kBSSPropertyBSSID[];
+extern const char kBSSPropertySSID[];
+extern const char kBSSPropertyMode[];
+extern const char kBSSPropertySignal[];
+extern const char kDBusAddr[];
+extern const char kDBusPath[];
+extern const char kDriverNL80211[];
+extern const char kErrorInterfaceExists[];
+extern const char kKeyManagementMethodSuffixEAP[];
+extern const char kKeyManagementMethodSuffixPSK[];
+extern const char kKeyModeNone[];
+extern const char kNetworkModeInfrastructure[];
+extern const char kNetworkModeAdHoc[];
+extern const char kNetworkModeAccessPoint[];
+extern const char kNetworkPropertyMode[];
+extern const char kNetworkPropertySSID[];
+extern const char kPropertyBSSID[];
+extern const char kPropertyKeyManagement[];
+extern const char kPropertyMode[];
+extern const char kPropertyPreSharedKey[];
+extern const char kPropertyPrivacy[];
+extern const char kPropertyRSN[];
+extern const char kPropertyScanType[];
+extern const char kPropertySecurityProtocol[];
+extern const char kPropertySignal[];
+extern const char kPropertyWPA[];
+extern const char kScanTypeActive[];
+extern const char kSecurityMethodPropertyKeyManagement[];
+extern const char kSecurityModeRSN[];
+extern const char kSecurityModeWPA[];
+
+extern const uint32_t kNetworkModeInfrastructureInt;
+extern const uint32_t kNetworkModeAdHocInt;
+extern const uint32_t kNetworkModeAccessPointInt;
+};
+
+} // namespace shill
+
+#endif // SHILL_WPA_SUPPLICANT_H