shill: implement Manager.GetService (error-case only)
BUG=chromium-os:20254
TEST=unittests, WiFiManager/000_SSID_Length_Limit
this gives us enough to pass the autotest for
network_WiFiManager/000_SSID_Length_Limit.
Change-Id: Ib0305e707d2203327d846be3e0b206033d6a884a
Reviewed-on: http://gerrit.chromium.org/gerrit/7567
Commit-Ready: mukesh agrawal <quiche@chromium.org>
Reviewed-by: mukesh agrawal <quiche@chromium.org>
Tested-by: mukesh agrawal <quiche@chromium.org>
diff --git a/Makefile b/Makefile
index 050658d..05a2f6d 100644
--- a/Makefile
+++ b/Makefile
@@ -101,6 +101,7 @@
ipconfig.o \
ipconfig_dbus_adaptor.o \
key_file_store.o \
+ key_value_store.o \
manager.o \
manager_dbus_adaptor.o \
modem.o \
@@ -183,6 +184,7 @@
mock_store.o \
mock_supplicant_interface_proxy.o \
mock_supplicant_process_proxy.o \
+ mock_wifi.o \
modem_info_unittest.o \
modem_manager_unittest.o \
modem_unittest.o \
diff --git a/cellular_service.cc b/cellular_service.cc
index 26556d3..f2c2b10 100644
--- a/cellular_service.cc
+++ b/cellular_service.cc
@@ -23,10 +23,9 @@
EventDispatcher *dispatcher,
Manager *manager,
const CellularRefPtr &device)
- : Service(control_interface, dispatcher, manager),
+ : Service(control_interface, dispatcher, manager, flimflam::kTypeCellular),
strength_(0),
- cellular_(device),
- type_(flimflam::kTypeCellular) {
+ cellular_(device) {
PropertyStore *store = this->mutable_store();
store->RegisterConstString(flimflam::kActivationStateProperty,
&activation_state_);
@@ -40,7 +39,6 @@
store->RegisterConstStringmap(flimflam::kServingOperatorProperty,
&serving_operator_.ToDict());
store->RegisterConstUint8(flimflam::kSignalStrengthProperty, &strength_);
- store->RegisterConstString(flimflam::kTypeProperty, &type_);
store->RegisterConstString(flimflam::kUsageURLProperty, &usage_url_);
}
diff --git a/cellular_service.h b/cellular_service.h
index b2ab054..072a08e 100644
--- a/cellular_service.h
+++ b/cellular_service.h
@@ -78,7 +78,6 @@
std::map<std::string, std::string> last_good_apn_info_;
CellularRefPtr cellular_;
- const std::string type_;
DISALLOW_COPY_AND_ASSIGN(CellularService);
};
diff --git a/dbus_adaptor.cc b/dbus_adaptor.cc
index a8cbc45..808b325 100644
--- a/dbus_adaptor.cc
+++ b/dbus_adaptor.cc
@@ -12,6 +12,7 @@
#include "shill/accessor_interface.h"
#include "shill/dbus_adaptor.h"
#include "shill/error.h"
+#include "shill/key_value_store.h"
#include "shill/property_store.h"
using std::map;
@@ -133,6 +134,28 @@
}
// static
+void DBusAdaptor::ArgsToKeyValueStore(
+ const map<string, ::DBus::Variant> &args,
+ KeyValueStore *out,
+ Error *error) { // XXX should be ::DBus::Error?
+ for (map<string, ::DBus::Variant>::const_iterator it = args.begin();
+ it != args.end();
+ ++it) {
+ DBus::type<string> string_type;
+ DBus::type<bool> bool_type;
+
+ if (it->second.signature() == string_type.sig()) {
+ out->SetString(it->first, it->second.reader().get_string());
+ } else if (it->second.signature() == bool_type.sig()) {
+ out->SetBool(it->first, it->second.reader().get_bool());
+ } else {
+ error->Populate(Error::kInternalError);
+ return; // skip remaining args after error
+ }
+ }
+}
+
+// static
::DBus::Variant DBusAdaptor::BoolToVariant(bool value) {
::DBus::Variant v;
v.writer().append_bool(value);
diff --git a/dbus_adaptor.h b/dbus_adaptor.h
index 6676984..6523f05 100644
--- a/dbus_adaptor.h
+++ b/dbus_adaptor.h
@@ -19,6 +19,8 @@
#define SHILL_INTERFACE "org.chromium.flimflam"
#define SHILL_PATH "/org/chromium/flimflam"
+class Error;
+class KeyValueStore;
class PropertyStore;
// Superclass for all DBus-backed Adaptor objects
@@ -35,6 +37,10 @@
static bool GetProperties(const PropertyStore &store,
std::map<std::string, ::DBus::Variant> *out,
::DBus::Error *error);
+ static void ArgsToKeyValueStore(
+ const std::map<std::string, ::DBus::Variant> &args,
+ KeyValueStore *out,
+ Error *error);
static ::DBus::Variant BoolToVariant(bool value);
static ::DBus::Variant ByteToVariant(uint8 value);
diff --git a/dbus_adaptor_unittest.cc b/dbus_adaptor_unittest.cc
index 36b68b3..c93acfe 100644
--- a/dbus_adaptor_unittest.cc
+++ b/dbus_adaptor_unittest.cc
@@ -12,6 +12,7 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
+#include "shill/key_value_store.h"
#include "shill/manager.h"
#include "shill/mock_control.h"
#include "shill/mock_device.h"
@@ -186,4 +187,17 @@
EXPECT_TRUE(DBusAdaptor::DispatchOnType(&store, "", byte_v_, &e10));
}
+TEST_F(DBusAdaptorTest, ArgsToKeyValueStore) {
+ map<string, ::DBus::Variant> args;
+ KeyValueStore args_kv;
+ Error error;
+
+ args["string_arg"].writer().append_string("string");
+ args["bool_arg"].writer().append_bool(true);
+ DBusAdaptor::ArgsToKeyValueStore(args, &args_kv, &error);
+ EXPECT_TRUE(error.IsSuccess());
+ EXPECT_EQ("string", args_kv.GetString("string_arg"));
+ EXPECT_EQ(true, args_kv.GetBool("bool_arg"));
+}
+
} // namespace shill
diff --git a/error.cc b/error.cc
index 030e598..e486bb5 100644
--- a/error.cc
+++ b/error.cc
@@ -65,9 +65,12 @@
message_ = message;
}
-void Error::ToDBusError(::DBus::Error *error) const {
+bool Error::ToDBusError(::DBus::Error *error) const {
if (IsFailure()) {
error->set(GetName(type_).c_str(), message_.c_str());
+ return true;
+ } else {
+ return false;
}
}
diff --git a/error.h b/error.h
index dc2ab19..c1fb2b1 100644
--- a/error.h
+++ b/error.h
@@ -49,9 +49,9 @@
void Populate(Type type); // Uses the default message for |type|.
void Populate(Type type, const std::string &message);
- // Sets the DBus |error| to this error if it's failure. Leaves |error|
- // unchanged otherwise.
- void ToDBusError(::DBus::Error *error) const;
+ // Sets the DBus |error| and returns true if Error represents failure.
+ // Leaves |error| unchanged, and returns false, otherwise.
+ bool ToDBusError(::DBus::Error *error) const;
Type type() const { return type_; }
const std::string &message() const { return message_; }
diff --git a/ethernet_service.cc b/ethernet_service.cc
index 8e1cdd6..679266c 100644
--- a/ethernet_service.cc
+++ b/ethernet_service.cc
@@ -34,12 +34,9 @@
EventDispatcher *dispatcher,
Manager *manager,
const EthernetRefPtr &device)
- : Service(control_interface, dispatcher, manager),
- ethernet_(device),
- type_(flimflam::kTypeEthernet) {
+ : Service(control_interface, dispatcher, manager, flimflam::kTypeEthernet),
+ ethernet_(device) {
set_auto_connect(true);
-
- mutable_store()->RegisterConstString(flimflam::kTypeProperty, &type_);
}
EthernetService::~EthernetService() { }
diff --git a/ethernet_service.h b/ethernet_service.h
index 2934c6a..e132f50 100644
--- a/ethernet_service.h
+++ b/ethernet_service.h
@@ -38,7 +38,6 @@
std::string GetDeviceRpcId();
EthernetRefPtr ethernet_;
- const std::string type_;
DISALLOW_COPY_AND_ASSIGN(EthernetService);
};
diff --git a/ieee80211.h b/ieee80211.h
new file mode 100644
index 0000000..5fa34bd
--- /dev/null
+++ b/ieee80211.h
@@ -0,0 +1,21 @@
+// 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_IEEE80211_H
+#define SHILL_IEEE80211_H
+
+namespace shill {
+
+namespace IEEE_80211 {
+const unsigned int kMaxSSIDLen = 32;
+
+const unsigned int kWEP40AsciiLen = 5;
+const unsigned int kWEP40HexLen = 10;
+const unsigned int kWEP104AsciiLen = 13;
+const unsigned int kWEP104HexLen = 26;
+};
+
+} // namespace shill
+
+#endif // SHILL_IEEE_80211_H
diff --git a/key_value_store.cc b/key_value_store.cc
new file mode 100644
index 0000000..bc0f55b
--- /dev/null
+++ b/key_value_store.cc
@@ -0,0 +1,45 @@
+// 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/key_value_store.h"
+
+#include <base/logging.h>
+#include <base/stl_util-inl.h>
+
+using std::map;
+using std::string;
+
+namespace shill {
+
+KeyValueStore::KeyValueStore() {}
+
+bool KeyValueStore::ContainsBool(const string &name) const {
+ return ContainsKey(bool_properties_, name);
+}
+
+bool KeyValueStore::ContainsString(const string &name) const {
+ return ContainsKey(string_properties_, name);
+}
+
+bool KeyValueStore::GetBool(const string &name) const {
+ map<string, bool>::const_iterator it(bool_properties_.find(name));
+ CHECK(it != bool_properties_.end());
+ return it->second;
+}
+
+const string &KeyValueStore::GetString(const string &name) const {
+ map<string, string>::const_iterator it(string_properties_.find(name));
+ CHECK(it != string_properties_.end());
+ return it->second;
+}
+
+void KeyValueStore::SetBool(const string &name, bool value) {
+ bool_properties_[name] = value;
+}
+
+void KeyValueStore::SetString(const string &name, const string &value) {
+ string_properties_[name] = value;
+}
+
+} // namespace shill
diff --git a/key_value_store.h b/key_value_store.h
new file mode 100644
index 0000000..bf02600
--- /dev/null
+++ b/key_value_store.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_KEY_VALUE_STORE_
+#define SHILL_KEY_VALUE_STORE_
+
+#include <map>
+#include <string>
+
+#include <base/basictypes.h>
+
+namespace shill {
+
+class KeyValueStore {
+ // A simple store for key-value pairs, which supports (a limited set of)
+ // heterogenous value types.
+ //
+ // Compare to PropertyStore, which enables a class to (selectively)
+ // expose its instance members as properties accessible via
+ // RPC. (RPC support for ProperyStore is implemented in a
+ // protocol-specific adaptor. e.g. dbus_adpator.)
+ //
+ // Implemented separately from PropertyStore, to avoid complicating
+ // the PropertyStore interface. In particular, objects implementing the
+ // PropertyStore interface always provide the storage themselves. In
+ // contrast, users of KeyValueStore expect KeyValueStore to provide
+ // storage.
+ public:
+ KeyValueStore();
+
+ bool ContainsBool(const std::string &name) const;
+ bool ContainsString(const std::string &name) const;
+
+ bool GetBool(const std::string &name) const;
+ const std::string &GetString(const std::string &name) const;
+
+ void SetBool(const std::string &name, bool value);
+ void SetString(const std::string& name,
+ const std::string& value);
+
+ private:
+ std::map<std::string, bool> bool_properties_;
+ std::map<std::string, std::string> string_properties_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeyValueStore);
+};
+
+} // namespace shill
+
+#endif // SHILL_KEY_VALUE_STORE_
diff --git a/manager.cc b/manager.cc
index 996c291..3b109e2 100644
--- a/manager.cc
+++ b/manager.cc
@@ -7,6 +7,7 @@
#include <time.h>
#include <stdio.h>
+#include <map>
#include <string>
#include <vector>
@@ -29,12 +30,17 @@
#include "shill/resolver.h"
#include "shill/shill_event.h"
#include "shill/service.h"
+#include "shill/wifi.h"
+#include "shill/wifi_service.h"
using std::string;
using std::vector;
namespace shill {
+// static
+const char Manager::kManagerErrorNoDevice[] = "no wifi devices available";
+
Manager::Manager(ControlInterface *control_interface,
EventDispatcher *dispatcher,
GLib *glib,
@@ -304,6 +310,21 @@
}
// called via RPC (e.g., from ManagerDBusAdaptor)
+WiFiServiceRefPtr Manager::GetWifiService(const KeyValueStore &args,
+ Error *error) {
+ std::vector<DeviceRefPtr> wifi_devices;
+ FilterByTechnology(Device::kWifi, &wifi_devices);
+ if (wifi_devices.empty()) {
+ error->Populate(Error::kInvalidArguments, kManagerErrorNoDevice);
+ return NULL;
+ } else {
+ WiFi *wifi = dynamic_cast<WiFi *>(wifi_devices.front().get());
+ CHECK(wifi);
+ return wifi->GetService(args, error);
+ }
+}
+
+// called via RPC (e.g., from ManagerDBusAdaptor)
void Manager::RequestScan(const std::string &technology, Error *error) {
if (technology == flimflam::kTypeWifi || technology == "") {
vector<DeviceRefPtr> wifi_devices;
diff --git a/manager.h b/manager.h
index 6bddeb5..bd03330 100644
--- a/manager.h
+++ b/manager.h
@@ -19,6 +19,7 @@
#include "shill/property_store.h"
#include "shill/service.h"
#include "shill/shill_event.h"
+#include "shill/wifi.h"
namespace shill {
@@ -69,6 +70,7 @@
std::vector<std::string> EnumerateAvailableServices();
// called via RPC (e.g., from ManagerDBusAdaptor)
+ WiFiServiceRefPtr GetWifiService(const KeyValueStore &args, Error *error);
void RequestScan(const std::string &technology, Error *error);
virtual DeviceInfo *device_info() { return &device_info_; }
@@ -83,6 +85,8 @@
private:
friend class ManagerAdaptorInterface;
+ static const char kManagerErrorNoDevice[];
+
std::string CalculateState();
std::vector<std::string> AvailableTechnologies();
std::vector<std::string> ConnectedTechnologies();
diff --git a/manager_dbus_adaptor.cc b/manager_dbus_adaptor.cc
index 36ace30..9318401 100644
--- a/manager_dbus_adaptor.cc
+++ b/manager_dbus_adaptor.cc
@@ -13,7 +13,9 @@
#include "shill/device.h"
#include "shill/error.h"
+#include "shill/key_value_store.h"
#include "shill/manager.h"
+#include "shill/wifi_service.h"
using std::map;
using std::string;
@@ -132,16 +134,32 @@
::DBus::Error &error) {
}
+// deprecated synonym for GetWifiService
::DBus::Path ManagerDBusAdaptor::GetService(
- const map<string, ::DBus::Variant> &,
+ const map<string, ::DBus::Variant> &args,
::DBus::Error &error) {
- return ::DBus::Path();
+ return GetWifiService(args, error);
}
+// called, e.g., to get Service handle for a hidden SSID
::DBus::Path ManagerDBusAdaptor::GetWifiService(
- const map<string, ::DBus::Variant> &,
+ const map<string, ::DBus::Variant> &args,
::DBus::Error &error) {
- return ::DBus::Path();
+ KeyValueStore args_store;
+ Error e;
+ WiFiServiceRefPtr service;
+ string ret;
+
+ DBusAdaptor::ArgsToKeyValueStore(args, &args_store, &e);
+ if (e.IsSuccess()) {
+ service = manager_->GetWifiService(args_store, &e);
+ }
+
+ if (e.ToDBusError(&error)) {
+ return "/"; // ensure return is syntactically valid
+ } else {
+ return service->GetRpcIdentifier();
+ }
}
void ManagerDBusAdaptor::ConfigureWifiService(
diff --git a/manager_unittest.cc b/manager_unittest.cc
index 960fddb..242d6e9 100644
--- a/manager_unittest.cc
+++ b/manager_unittest.cc
@@ -16,13 +16,16 @@
#include "shill/adaptor_interfaces.h"
#include "shill/error.h"
+#include "shill/key_value_store.h"
#include "shill/mock_adaptors.h"
#include "shill/mock_control.h"
#include "shill/mock_device.h"
#include "shill/mock_glib.h"
#include "shill/mock_profile.h"
#include "shill/mock_service.h"
+#include "shill/mock_wifi.h"
#include "shill/property_store_unittest.h"
+#include "shill/wifi_service.h"
using std::map;
using std::set;
@@ -55,7 +58,14 @@
manager(),
"null3",
"addr3",
- 3)) {
+ 3)),
+ mock_wifi_(new NiceMock<MockWiFi>(control_interface(),
+ dispatcher(),
+ manager(),
+ "wifi0",
+ "addr4",
+ 4))
+ {
}
virtual ~ManagerTest() {}
@@ -69,6 +79,7 @@
scoped_refptr<MockDevice> mock_device_;
scoped_refptr<MockDevice> mock_device2_;
scoped_refptr<MockDevice> mock_device3_;
+ scoped_refptr<MockWiFi> mock_wifi_;
};
TEST_F(ManagerTest, Contains) {
@@ -316,4 +327,23 @@
}
}
+TEST_F(ManagerTest, GetWifiServiceNoDevice) {
+ KeyValueStore args;
+ Error e;
+ manager()->GetWifiService(args, &e);
+ EXPECT_EQ(Error::kInvalidArguments, e.type());
+ EXPECT_EQ("no wifi devices available", e.message());
+}
+
+TEST_F(ManagerTest, GetWifiService) {
+ KeyValueStore args;
+ Error e;
+ WiFiServiceRefPtr wifi_service;
+
+ manager()->RegisterDevice(mock_wifi_);
+ EXPECT_CALL(*mock_wifi_, GetService(_, _))
+ .WillRepeatedly(Return(wifi_service));
+ manager()->GetWifiService(args, &e);
+}
+
} // namespace shill
diff --git a/mock_service.cc b/mock_service.cc
index a88fbc8..6125479 100644
--- a/mock_service.cc
+++ b/mock_service.cc
@@ -24,7 +24,7 @@
MockService::MockService(ControlInterface *control_interface,
EventDispatcher *dispatcher,
Manager *manager)
- : Service(control_interface, dispatcher, manager) {
+ : Service(control_interface, dispatcher, manager, "mock") {
ON_CALL(*this, GetRpcIdentifier()).WillByDefault(Return(""));
}
diff --git a/mock_wifi.cc b/mock_wifi.cc
new file mode 100644
index 0000000..68fa119
--- /dev/null
+++ b/mock_wifi.cc
@@ -0,0 +1,28 @@
+// 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/mock_wifi.h"
+
+#include <string>
+
+namespace shill {
+
+using std::string;
+
+MockWiFi::MockWiFi(ControlInterface *control_interface,
+ EventDispatcher *dispatcher,
+ Manager *manager,
+ const string &link_name,
+ const string &address,
+ int interface_index)
+ : WiFi(control_interface,
+ dispatcher,
+ manager,
+ link_name,
+ address,
+ interface_index) {}
+
+MockWiFi::~MockWiFi() {}
+
+} // namespace shill
diff --git a/mock_wifi.h b/mock_wifi.h
new file mode 100644
index 0000000..9dc8430
--- /dev/null
+++ b/mock_wifi.h
@@ -0,0 +1,46 @@
+// 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_MOCK_WIFI_
+#define SHILL_MOCK_WIFI_
+
+#include <string>
+
+#include <base/memory/ref_counted.h>
+#include <gmock/gmock.h>
+
+#include "shill/key_value_store.h"
+#include "shill/refptr_types.h"
+#include "shill/wifi.h"
+#include "shill/wifi_service.h"
+
+namespace shill {
+
+class ControlInterface;
+class Error;
+class EventDispatcher;
+
+class MockWiFi : public WiFi {
+ public:
+ MockWiFi(ControlInterface *control_interface,
+ EventDispatcher *dispatcher,
+ Manager *manager,
+ const std::string &link_name,
+ const std::string &address,
+ int interface_index);
+ virtual ~MockWiFi();
+
+ MOCK_METHOD0(Start, void());
+ MOCK_METHOD0(Stop, void());
+ MOCK_METHOD1(Scan, void(Error *error));
+ MOCK_METHOD2(GetService,
+ WiFiServiceRefPtr(const KeyValueStore &args, Error *error));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockWiFi);
+};
+
+} // namespace shill
+
+#endif // SHILL_MOCK_WIFI_
diff --git a/service.cc b/service.cc
index 29b2f3a..f4867bc 100644
--- a/service.cc
+++ b/service.cc
@@ -65,7 +65,8 @@
Service::Service(ControlInterface *control_interface,
EventDispatcher *dispatcher,
- Manager *manager)
+ Manager *manager,
+ const string &type)
: state_(kStateUnknown),
failure_(kFailureUnknown),
auto_connect_(false),
@@ -74,6 +75,7 @@
favorite_(false),
priority_(kPriorityNone),
save_credentials_(true),
+ type_(type),
dispatcher_(dispatcher),
name_(base::UintToString(serial_number_++)),
available_(false),
@@ -137,6 +139,7 @@
// store_.RegisterConstStringmap(flimflam::kProviderProperty, &provider_);
store_.RegisterBool(flimflam::kSaveCredentialsProperty, &save_credentials_);
+ store_.RegisterConstString(flimflam::kTypeProperty, &type_);
// flimflam::kSecurityProperty: Registered in WiFiService
HelpRegisterDerivedString(flimflam::kStateProperty,
&Service::CalculateState,
diff --git a/service.h b/service.h
index 6f7cb8e..032693f 100644
--- a/service.h
+++ b/service.h
@@ -25,6 +25,7 @@
class Endpoint;
class Error;
class EventDispatcher;
+class KeyValueStore;
class Manager;
class ServiceAdaptorInterface;
class StoreInterface;
@@ -86,7 +87,8 @@
// A constructor for the Service object
Service(ControlInterface *control_interface,
EventDispatcher *dispatcher,
- Manager *manager);
+ Manager *manager,
+ const std::string &type);
virtual ~Service();
virtual void Connect(Error *error) = 0;
@@ -221,6 +223,7 @@
std::string proxy_config_;
bool save_credentials_;
EapCredentials eap_; // Only saved if |save_credentials_| is true.
+ const std::string type_;
ProfileRefPtr profile_;
PropertyStore store_;
diff --git a/service_unittest.cc b/service_unittest.cc
index 35063f0..efbd149 100644
--- a/service_unittest.cc
+++ b/service_unittest.cc
@@ -45,7 +45,7 @@
ServiceUnderTest(ControlInterface *control_interface,
EventDispatcher *dispatcher,
Manager *manager)
- : Service(control_interface, dispatcher, manager) {}
+ : Service(control_interface, dispatcher, manager, "stub") {}
virtual ~ServiceUnderTest() {}
virtual void Connect(Error *error) {}
diff --git a/wifi.cc b/wifi.cc
index dd2acb9..18195ec 100644
--- a/wifi.cc
+++ b/wifi.cc
@@ -15,10 +15,15 @@
#include <vector>
#include <base/logging.h>
+#include <base/string_number_conversions.h>
+#include <base/string_util.h>
#include <chromeos/dbus/service_constants.h>
#include "shill/control_interface.h"
#include "shill/device.h"
+#include "shill/error.h"
+#include "shill/key_value_store.h"
+#include "shill/ieee80211.h"
#include "shill/manager.h"
#include "shill/profile.h"
#include "shill/proxy_factory.h"
@@ -28,9 +33,28 @@
#include "shill/wifi_endpoint.h"
#include "shill/wifi_service.h"
+using std::map;
using std::string;
+using std::vector;
namespace shill {
+
+// statics
+//
+// Note that WiFi generates some manager-level errors, because it implements
+// the Manager.GetWiFiService flimflam API. The API is implemented here,
+// rather than in manager, to keep WiFi-specific logic in the right place.
+const char WiFi::kManagerErrorPassphraseRequired[] = "must specify passphrase";
+const char WiFi::kManagerErrorSSIDRequired[] = "must specify SSID";
+const char WiFi::kManagerErrorSSIDTooLong[] = "SSID is too long";
+const char WiFi::kManagerErrorSSIDTooShort[] = "SSID is too short";
+const char WiFi::kManagerErrorTypeRequired[] = "must specify service type";
+const char WiFi::kManagerErrorUnsupportedSecurityMode[] =
+ "security mode is unsupported";
+const char WiFi::kManagerErrorUnsupportedServiceType[] =
+ "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";
@@ -298,4 +322,163 @@
scan_pending_ = true;
}
+// used by manager, via static WiFi::GetService method
+WiFiServiceRefPtr WiFi::GetService(const KeyValueStore &args, Error *error) {
+ if (!args.ContainsString(flimflam::kTypeProperty)) {
+ error->Populate(Error::kInvalidArguments, kManagerErrorTypeRequired);
+ return NULL;
+ }
+
+ if (args.GetString(flimflam::kTypeProperty) != flimflam::kTypeWifi) {
+ error->Populate(Error::kNotSupported, kManagerErrorUnsupportedServiceType);
+ return NULL;
+ }
+
+ if (args.ContainsString(flimflam::kModeProperty) &&
+ args.GetString(flimflam::kModeProperty) !=
+ flimflam::kModeManaged) {
+ error->Populate(Error::kNotSupported, kManagerErrorUnsupportedServiceMode);
+ return NULL;
+ }
+
+ if (!args.ContainsString(flimflam::kSSIDProperty)) {
+ error->Populate(Error::kInvalidArguments, kManagerErrorSSIDRequired);
+ return NULL;
+ }
+
+ string ssid = args.GetString(flimflam::kSSIDProperty);
+ if (ssid.length() < 1) {
+ error->Populate(Error::kInvalidNetworkName, kManagerErrorSSIDTooShort);
+ return NULL;
+ }
+
+ if (ssid.length() > IEEE_80211::kMaxSSIDLen) {
+ error->Populate(Error::kInvalidNetworkName, kManagerErrorSSIDTooLong);
+ return NULL;
+ }
+
+ string security_method;
+ if (args.ContainsString(flimflam::kSecurityProperty)) {
+ security_method = args.GetString(flimflam::kSecurityProperty);
+ } else {
+ security_method = flimflam::kSecurityNone;
+ }
+
+ if (security_method != flimflam::kSecurityNone &&
+ security_method != flimflam::kSecurityWep &&
+ security_method != flimflam::kSecurityPsk &&
+ security_method != flimflam::kSecurityWpa &&
+ security_method != flimflam::kSecurityRsn &&
+ security_method != flimflam::kSecurity8021x) {
+ error->Populate(Error::kNotSupported,
+ kManagerErrorUnsupportedSecurityMode);
+ return NULL;
+ }
+
+ if ((security_method == flimflam::kSecurityWep ||
+ security_method == flimflam::kSecurityPsk ||
+ security_method == flimflam::kSecurityWpa ||
+ security_method == flimflam::kSecurityRsn) &&
+ !args.ContainsString(flimflam::kPassphraseProperty)) {
+ error->Populate(Error::kInvalidArguments,
+ kManagerErrorPassphraseRequired);
+ return NULL;
+ }
+
+ if (security_method == flimflam::kSecurityWep) {
+ string passphrase = args.GetString(flimflam::kPassphraseProperty);
+ passphrase = ParseWEPPassphrase(passphrase, error);
+ if (error->IsFailure()) {
+ return NULL;
+ }
+ }
+
+ WiFiService *service = NULL;
+
+ // TODO(quiche): search for existing service
+
+ if (service == NULL) {
+ // TODO(quiche): construct a new service
+ }
+
+ // TODO(quiche): apply configuration parameters
+
+ return service;
+}
+
+// static
+string WiFi::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 "";
+ }
+}
+
+// static
+bool WiFi::CheckWEPIsHex(const string &passphrase, Error *error) {
+ vector<uint8> passphrase_bytes;
+ if (base::HexStringToBytes(passphrase, &passphrase_bytes)) {
+ return true;
+ } else {
+ error->Populate(Error::kInvalidPassphrase);
+ return false;
+ }
+}
+
+// static
+bool WiFi::CheckWEPKeyIndex(const string &passphrase, Error *error) {
+ if (StartsWithASCII(passphrase, "0:", false) ||
+ StartsWithASCII(passphrase, "1:", false) ||
+ StartsWithASCII(passphrase, "2:", false) ||
+ StartsWithASCII(passphrase, "3:", false)) {
+ return true;
+ } else {
+ error->Populate(Error::kInvalidPassphrase);
+ return false;
+ }
+}
+
+// static
+bool WiFi::CheckWEPPrefix(const string &passphrase, Error *error) {
+ if (StartsWithASCII(passphrase, "0x", false)) {
+ return true;
+ } else {
+ error->Populate(Error::kInvalidPassphrase);
+ return false;
+ }
+}
+
} // namespace shill
diff --git a/wifi.h b/wifi.h
index 04b1d09..a92174f 100644
--- a/wifi.h
+++ b/wifi.h
@@ -17,6 +17,8 @@
namespace shill {
+class Error;
+class KeyValueStore;
class SupplicantInterfaceProxyInterface;
class SupplicantProcessProxyInterface;
class WiFiService;
@@ -47,10 +49,21 @@
// called by WiFiService
void ConnectTo(WiFiService *service);
+ // called by Manager
+ virtual WiFiServiceRefPtr GetService(const KeyValueStore &args, Error *error);
+
private:
typedef std::map<const std::string, WiFiEndpointRefPtr> EndpointMap;
typedef std::map<const std::string, WiFiServiceRefPtr> ServiceMap;
+ static const char kManagerErrorPassphraseRequired[];
+ static const char kManagerErrorSSIDTooLong[];
+ static const char kManagerErrorSSIDTooShort[];
+ static const char kManagerErrorSSIDRequired[];
+ static const char kManagerErrorTypeRequired[];
+ static const char kManagerErrorUnsupportedSecurityMode[];
+ static const char kManagerErrorUnsupportedServiceType[];
+ static const char kManagerErrorUnsupportedServiceMode[];
static const char kSupplicantPath[];
static const char kSupplicantDBusAddr[];
static const char kSupplicantWiFiDriver[];
@@ -65,6 +78,12 @@
void ScanDoneTask();
void ScanTask();
+ static std::string ParseWEPPassphrase(const std::string &passphrase,
+ Error *error);
+ static bool CheckWEPIsHex(const std::string &passphrase, Error *error);
+ static bool CheckWEPKeyIndex(const std::string &passphrase, Error *error);
+ static bool CheckWEPPrefix(const std::string &passphrase, Error *error);
+
ScopedRunnableMethodFactory<WiFi> task_factory_;
scoped_ptr<SupplicantProcessProxyInterface> supplicant_process_proxy_;
scoped_ptr<SupplicantInterfaceProxyInterface> supplicant_interface_proxy_;
diff --git a/wifi_service.cc b/wifi_service.cc
index 8b5046d..6ed8b79 100644
--- a/wifi_service.cc
+++ b/wifi_service.cc
@@ -28,9 +28,8 @@
const std::vector<uint8_t> ssid,
const std::string &mode,
const std::string &key_management)
- : Service(control_interface, dispatcher, manager),
+ : Service(control_interface, dispatcher, manager, flimflam::kTypeWifi),
security_(flimflam::kSecurityNone),
- type_(flimflam::kTypeWifi),
mode_(mode),
task_factory_(this),
wifi_(device),
@@ -43,7 +42,6 @@
store->RegisterBool(flimflam::kPassphraseRequiredProperty, &need_passphrase_);
store->RegisterConstString(flimflam::kSecurityProperty, &security_);
store->RegisterConstUint8(flimflam::kSignalStrengthProperty, &strength_);
- store->RegisterConstString(flimflam::kTypeProperty, &type_);
store->RegisterConstString(flimflam::kWifiAuthMode, &auth_mode_);
store->RegisterConstBool(flimflam::kWifiHiddenSsid, &hidden_ssid_);
diff --git a/wifi_service.h b/wifi_service.h
index 6784f20..e0176af 100644
--- a/wifi_service.h
+++ b/wifi_service.h
@@ -51,7 +51,6 @@
bool need_passphrase_;
std::string security_;
uint8 strength_;
- const std::string type_;
// TODO(cmasone): see if the below can be pulled from the endpoint associated
// with this service instead.
const std::string mode_;
diff --git a/wifi_unittest.cc b/wifi_unittest.cc
index c2d9a1e..2751eb8 100644
--- a/wifi_unittest.cc
+++ b/wifi_unittest.cc
@@ -22,6 +22,7 @@
#include <gtest/gtest.h>
#include "shill/dbus_adaptor.h"
+#include "shill/key_value_store.h"
#include "shill/manager.h"
#include "shill/mock_device.h"
#include "shill/mock_dhcp_config.h"
@@ -197,6 +198,40 @@
void StopWiFi() {
wifi_->Stop();
}
+ void GetOpenService(const char *service_type,
+ const char *ssid,
+ const char *mode,
+ Error &result) {
+ return GetService(service_type, ssid, mode, NULL, NULL, result);
+ }
+ void GetService(const char *service_type,
+ const char *ssid,
+ const char *mode,
+ const char *security,
+ const char *passphrase,
+ Error &result) {
+ map<string, ::DBus::Variant> args;
+ Error e;
+ KeyValueStore args_kv;
+
+ // in general, we want to avoid D-Bus specific code for any RPCs
+ // that come in via adaptors. we make an exception here, because
+ // calls to GetWifiService are rerouted from the Manager object to
+ // the Wifi class.
+ if (service_type != NULL)
+ args[flimflam::kTypeProperty].writer().append_string(service_type);
+ if (ssid != NULL)
+ args[flimflam::kSSIDProperty].writer().append_string(ssid);
+ if (mode != NULL)
+ args[flimflam::kModeProperty].writer().append_string(mode);
+ if (security != NULL)
+ args[flimflam::kSecurityProperty].writer().append_string(security);
+ if (passphrase != NULL)
+ args[flimflam::kPassphraseProperty].writer().append_string(passphrase);
+
+ DBusAdaptor::ArgsToKeyValueStore(args, &args_kv, &e);
+ wifi_->GetService(args_kv, &result);
+ }
MockManager *manager() {
return &manager_;
}
@@ -390,4 +425,161 @@
}
}
+TEST_F(WiFiMainTest, GetWifiServiceOpen) {
+ Error e;
+ GetOpenService("wifi", "an_ssid", "managed", e);
+ EXPECT_TRUE(e.IsSuccess());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceOpenNoType) {
+ Error e;
+ GetOpenService(NULL, "an_ssid", "managed", e);
+ EXPECT_EQ(Error::kInvalidArguments, e.type());
+ EXPECT_EQ("must specify service type", e.message());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceOpenNoSSID) {
+ Error e;
+ GetOpenService("wifi", NULL, "managed", e);
+ EXPECT_EQ(Error::kInvalidArguments, e.type());
+ EXPECT_EQ("must specify SSID", e.message());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceOpenLongSSID) {
+ Error e;
+ GetOpenService(
+ "wifi", "123456789012345678901234567890123", "managed", e);
+ EXPECT_EQ(Error::kInvalidNetworkName, e.type());
+ EXPECT_EQ("SSID is too long", e.message());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceOpenShortSSID) {
+ Error e;
+ GetOpenService("wifi", "", "managed", e);
+ EXPECT_EQ(Error::kInvalidNetworkName, e.type());
+ EXPECT_EQ("SSID is too short", e.message());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceOpenBadMode) {
+ Error e;
+ GetOpenService("wifi", "an_ssid", "ad-hoc", e);
+ EXPECT_EQ(Error::kNotSupported, e.type());
+ EXPECT_EQ("service mode is unsupported", e.message());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceOpenNoMode) {
+ Error e;
+ GetOpenService("wifi", "an_ssid", NULL, e);
+ EXPECT_TRUE(e.IsSuccess());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceRSN) {
+ Error e;
+ GetService("wifi", "an_ssid", "managed", "rsn", "secure password", e);
+ EXPECT_TRUE(e.IsSuccess());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceRSNNoPassword) {
+ Error e;
+ GetService("wifi", "an_ssid", "managed", "rsn", NULL, e);
+ EXPECT_EQ(Error::kInvalidArguments, e.type());
+ EXPECT_EQ("must specify passphrase", e.message());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceBadSecurity) {
+ Error e;
+ GetService("wifi", "an_ssid", "managed", "rot-13", NULL, e);
+ EXPECT_EQ(Error::kNotSupported, e.type());
+ EXPECT_EQ("security mode is unsupported", e.message());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceWEPNoPassword) {
+ Error e;
+ GetService("wifi", "an_ssid", "managed", "wep", NULL, e);
+ EXPECT_EQ(Error::kInvalidArguments, e.type());
+ EXPECT_EQ("must specify passphrase", e.message());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceWEPEmptyPassword) {
+ Error e;
+ GetService("wifi", "an_ssid", "managed", "wep", "", e);
+ EXPECT_EQ(Error::kInvalidPassphrase, e.type());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceWEP40ASCII) {
+ Error e;
+ GetService("wifi", "an_ssid", "managed", "wep", "abcde", e);
+ EXPECT_TRUE(e.IsSuccess());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceWEP104ASCII) {
+ Error e;
+ GetService("wifi", "an_ssid", "managed", "wep", "abcdefghijklm", e);
+ EXPECT_TRUE(e.IsSuccess());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceWEP40ASCIIWithKeyIndex) {
+ Error e;
+ GetService("wifi", "an_ssid", "managed", "wep", "0:abcdefghijklm", e);
+ EXPECT_TRUE(e.IsSuccess());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceWEP40Hex) {
+ Error e;
+ GetService("wifi", "an_ssid", "managed", "wep", "0102030405", e);
+ EXPECT_TRUE(e.IsSuccess());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceWEP40HexBadPassphrase) {
+ Error e;
+ GetService("wifi", "an_ssid", "managed", "wep", "O102030405", e);
+ EXPECT_EQ(Error::kInvalidPassphrase, e.type());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceWEP40HexWithKeyIndexBadPassphrase) {
+ Error e;
+ GetService("wifi", "an_ssid", "managed", "wep", "1:O102030405", e);
+ EXPECT_EQ(Error::kInvalidPassphrase, e.type());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceWEP40HexWithKeyIndexAndBaseBadPassphrase) {
+ Error e;
+ GetService("wifi", "an_ssid", "managed", "wep", "1:0xO102030405", e);
+ EXPECT_EQ(Error::kInvalidPassphrase, e.type());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceWEP40HexWithBaseBadPassphrase) {
+ Error e;
+ GetService("wifi", "an_ssid", "managed", "wep", "0xO102030405", e);
+ EXPECT_EQ(Error::kInvalidPassphrase, e.type());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceWEP104Hex) {
+ Error e;
+ GetService("wifi", "an_ssid", "managed", "wep",
+ "0102030405060708090a0b0c0d", e);
+ EXPECT_TRUE(e.IsSuccess());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceWEP104HexUppercase) {
+ Error e;
+ GetService("wifi", "an_ssid", "managed", "wep",
+ "0102030405060708090A0B0C0D", e);
+ EXPECT_TRUE(e.IsSuccess());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceWEP104HexWithKeyIndex) {
+ Error e;
+ GetService("wifi", "an_ssid", "managed", "wep",
+ "0:0102030405060708090a0b0c0d", e);
+ EXPECT_TRUE(e.IsSuccess());
+}
+
+TEST_F(WiFiMainTest, GetWifiServiceWEP104HexWithKeyIndexAndBase) {
+ Error e;
+ GetService("wifi", "an_ssid", "managed", "wep",
+ "0:0x0102030405060708090a0b0c0d", e);
+ EXPECT_TRUE(e.IsSuccess());
+}
+
} // namespace shill