shill: track wpa_supplicant state, and use it
to update Service state
BUG=chromium-os:22594
TEST=unittests, manual
Manual testing: tried network_WiFiRoaming.002Suspend,
but this still fails. The reason is that we ignore
transitions into disconnected state. I'll address that
in a separate patch, which will add tracking of
CurrentBSS.
Bonus changes bundled in this commit:
- fix some comments (capitalization/punctuation,
XXX -> TODO)
- WiFiMainTest::InitateConnect arg changed from bare pointer
to refptr
Change-Id: I6c42f9794c8742fa2b46d03a54d77e0545c899c5
Reviewed-on: https://gerrit.chromium.org/gerrit/11460
Reviewed-by: Gaurav Shah <gauravsh@chromium.org>
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 a572a1d..a12814b 100644
--- a/Makefile
+++ b/Makefile
@@ -202,6 +202,7 @@
mock_supplicant_process_proxy.o \
mock_time.o \
mock_wifi.o \
+ mock_wifi_service.o \
modem_info_unittest.o \
modem_manager_unittest.o \
modem_unittest.o \
diff --git a/mock_wifi_service.cc b/mock_wifi_service.cc
new file mode 100644
index 0000000..9dd6e5b
--- /dev/null
+++ b/mock_wifi_service.cc
@@ -0,0 +1,30 @@
+// 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_service.h"
+
+using std::string;
+using std::vector;
+
+namespace shill {
+
+class ControlInterface;
+class EventDispatcher;
+class Manager;
+
+MockWiFiService::MockWiFiService(ControlInterface *control_interface,
+ EventDispatcher *dispatcher,
+ Manager *manager,
+ const WiFiRefPtr &device,
+ const vector<uint8_t> &ssid,
+ const string &mode,
+ const string &security,
+ bool hidden_ssid)
+ : WiFiService(
+ control_interface, dispatcher, manager, device, ssid, mode, security,
+ hidden_ssid) {}
+
+MockWiFiService::~MockWiFiService() {}
+
+} // namespace shill
diff --git a/mock_wifi_service.h b/mock_wifi_service.h
new file mode 100644
index 0000000..a0d4ace
--- /dev/null
+++ b/mock_wifi_service.h
@@ -0,0 +1,34 @@
+// 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_SERVICE_
+#define SHILL_MOCK_WIFI_SERVICE_
+
+#include <gmock/gmock.h>
+
+#include "shill/wifi_service.h"
+
+namespace shill {
+
+class MockWiFiService : public WiFiService {
+ public:
+ MockWiFiService(ControlInterface *control_interface,
+ EventDispatcher *dispatcher,
+ Manager *manager,
+ const WiFiRefPtr &device,
+ const std::vector<uint8_t> &ssid,
+ const std::string &mode,
+ const std::string &security,
+ bool hidden_ssid);
+ virtual ~MockWiFiService();
+
+ MOCK_METHOD1(SetState, void(ConnectState state));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockWiFiService);
+};
+
+} // namespace shill
+
+#endif // SHILL_MOCK_WIFI_SERVICE_
diff --git a/service.cc b/service.cc
index 97cb2f4..2131ce6 100644
--- a/service.cc
+++ b/service.cc
@@ -178,6 +178,10 @@
}
void Service::SetState(ConnectState state) {
+ // TODO(quiche): Print string, rather than enum.
+ LOG(INFO) << friendly_name_ << " " << __func__ << " "
+ << state_ << " -> " << state;
+
if (state == state_) {
return;
}
diff --git a/supplicant_interface_proxy.cc b/supplicant_interface_proxy.cc
index ebc5db0..6d80432 100644
--- a/supplicant_interface_proxy.cc
+++ b/supplicant_interface_proxy.cc
@@ -100,9 +100,9 @@
}
void SupplicantInterfaceProxy::Proxy::PropertiesChanged(
- const std::map<string, ::DBus::Variant> &/*properties*/) {
+ const std::map<string, ::DBus::Variant> &properties) {
LOG(INFO) << __func__;
- // XXX
+ wifi_->PropertiesChanged(properties);
}
void SupplicantInterfaceProxy::Proxy::ScanDone(const bool& success) {
diff --git a/wifi.cc b/wifi.cc
index 336d21b..01d9613 100644
--- a/wifi.cc
+++ b/wifi.cc
@@ -59,6 +59,7 @@
"service type is unsupported";
const char WiFi::kManagerErrorUnsupportedServiceMode[] =
"service mode is unsupported";
+const char WiFi::kInterfaceStateUnknown[] = "shill-unknown";
// NB: we assume supplicant is already running. [quiche.20110518]
WiFi::WiFi(ControlInterface *control_interface,
@@ -79,7 +80,8 @@
bgscan_signal_threshold_(0),
scan_pending_(false),
scan_interval_(0),
- link_up_(false) {
+ link_up_(false),
+ supplicant_state_(kInterfaceStateUnknown) {
PropertyStore *store = this->mutable_store();
store->RegisterString(flimflam::kBgscanMethodProperty, &bgscan_method_);
store->RegisterUint16(flimflam::kBgscanShortIntervalProperty,
@@ -118,9 +120,9 @@
if (!strcmp(e.name(), wpa_supplicant::kErrorInterfaceExists)) {
interface_path =
supplicant_process_proxy_->GetInterface(link_name());
- // XXX crash here, if device missing?
+ // TODO(quiche): Is it okay to crash here, if device is missing?
} else {
- // XXX
+ // TODO(quiche): Log error.
}
}
@@ -128,13 +130,13 @@
proxy_factory_->CreateSupplicantInterfaceProxy(
this, interface_path, wpa_supplicant::kDBusAddr));
- // TODO(quiche) set ApScan=1 and BSSExpireAge=190, like flimflam does?
+ // TODO(quiche) Set ApScan=1 and BSSExpireAge=190, like flimflam does?
- // clear out any networks that might previously have been configured
+ // Clear out any networks that might previously have been configured
// for this interface.
supplicant_interface_proxy_->RemoveAllNetworks();
- // flush interface's BSS cache, so that we get BSSAdded signals for
+ // Flush interface's BSS cache, so that we get BSSAdded signals for
// all BSSes (not just new ones since the last scan).
supplicant_interface_proxy_->FlushBSS(0);
@@ -144,7 +146,7 @@
void WiFi::Stop() {
VLOG(2) << "WiFi " << link_name() << " stopping.";
- // TODO(quiche): remove interface from supplicant
+ // TODO(quiche): Remove interface from supplicant.
supplicant_interface_proxy_.reset(); // breaks a reference cycle
supplicant_process_proxy_.reset();
endpoint_by_bssid_.clear();
@@ -156,9 +158,10 @@
manager()->DeregisterService(*it);
}
services_.clear(); // breaks reference cycles
+ pending_service_ = NULL; // breaks a reference cycle
Device::Stop();
- // XXX anything else to do?
+ // TODO(quiche): Anything else to do?
VLOG(3) << "WiFi " << link_name() << " task_factory_ "
<< (task_factory_.empty() ? "is empty." : "is not empty.");
@@ -166,6 +169,8 @@
<< (supplicant_process_proxy_.get() ? "is set." : "is not set.");
VLOG(3) << "WiFi " << link_name() << " supplicant_interface_proxy_ "
<< (supplicant_interface_proxy_.get() ? "is set." : "is not set.");
+ VLOG(3) << "WiFi " << link_name() << " pending_service_ "
+ << (pending_service_.get() ? "is set." : "is not set.");
VLOG(3) << "WiFi " << link_name() << " has " << endpoint_by_bssid_.size()
<< " EndpointMap entries.";
VLOG(3) << "WiFi " << link_name() << " has " << service_by_private_id_.size()
@@ -175,8 +180,8 @@
void WiFi::Scan(Error */*error*/) {
LOG(INFO) << __func__;
- // needs to send a D-Bus message, but may be called from D-Bus
- // signal handler context (via Manager::RequestScan). so defer work
+ // Needs to send a D-Bus message, but may be called from D-Bus
+ // signal handler context (via Manager::RequestScan). So defer work
// to event loop.
dispatcher()->PostTask(
task_factory_.NewRunnableMethod(&WiFi::ScanTask));
@@ -187,8 +192,8 @@
}
void WiFi::LinkEvent(unsigned int flags, unsigned int change) {
- // TODO(quiche): figure out how to relate these events to supplicant
- // events. e.g., may be we can ignore LinkEvent, in favor of events
+ // TODO(quiche): Figure out how to relate these events to supplicant
+ // events. E.g., may be we can ignore LinkEvent, in favor of events
// from SupplicantInterfaceProxy?
Device::LinkEvent(flags, change);
if ((flags & IFF_LOWER_UP) != 0 && !link_up_) {
@@ -202,7 +207,7 @@
} else if ((flags & IFF_LOWER_UP) == 0 && link_up_) {
LOG(INFO) << link_name() << " is down";
link_up_ = false;
- // TODO(quiche): attempt to reconnect to current SSID, another SSID,
+ // TODO(quiche): Attempt to reconnect to current SSID, another SSID,
// or initiate a scan.
}
}
@@ -210,23 +215,31 @@
void WiFi::BSSAdded(
const ::DBus::Path &/*BSS*/,
const std::map<string, ::DBus::Variant> &properties) {
- // TODO(quiche): write test to verify correct behavior in the case
+ // TODO(quiche): Write test to verify correct behavior in the case
// where we get multiple BSSAdded events for a single endpoint.
- // (old Endpoint's refcount should fall to zero, and old Endpoint
- // should be destroyed)
+ // (Old Endpoint's refcount should fall to zero, and old Endpoint
+ // should be destroyed.)
//
- // note: we assume that BSSIDs are unique across endpoints. this
+ // Note: we assume that BSSIDs are unique across endpoints. This
// means that if an AP reuses the same BSSID for multiple SSIDs, we
// lose.
WiFiEndpointRefPtr endpoint(new WiFiEndpoint(properties));
endpoint_by_bssid_[endpoint->bssid_hex()] = endpoint;
}
+void WiFi::PropertiesChanged(const map<string, ::DBus::Variant> &properties) {
+ // TODO(quiche): Handle changes in other properties.
+ if (ContainsKey(properties, wpa_supplicant::kInterfacePropertyState)) {
+ StateChanged(properties.find(wpa_supplicant::kInterfacePropertyState)->
+ second.reader().get_string());
+ }
+}
+
void WiFi::ScanDone() {
LOG(INFO) << __func__;
- // defer handling of scan result processing, because that processing
- // may require the the registration of new D-Bus objects. and such
+ // Defer handling of scan result processing, because that processing
+ // may require the the registration of new D-Bus objects. And such
// registration can't be done in the context of a D-Bus signal
// handler.
dispatcher()->PostTask(
@@ -237,9 +250,9 @@
const map<string, DBus::Variant> &service_params) {
DBus::Path network_path;
- // TODO(quiche): handle cases where already connected
+ // TODO(quiche): Handle cases where already connected.
- // TODO(quiche): set scan_ssid=1 in service_params, like flimflam does?
+ // TODO(quiche): Set scan_ssid=1 in service_params, like flimflam does?
try {
network_path =
supplicant_interface_proxy_->AddNetwork(service_params);
@@ -249,15 +262,16 @@
}
supplicant_interface_proxy_->SelectNetwork(network_path);
- // XXX add to favorite networks list?
+ // TODO(quiche): Add to favorite networks list?
// SelectService here (instead of in LinkEvent, like Ethernet), so
// that, if we fail to bring up L2, we can attribute failure correctly.
//
- // TODO(quiche): when we add code for dealing with connection failures,
+ // TODO(quiche): When we add code for dealing with connection failures,
// reconsider if this is the right place to change the selected service.
// see discussion in crosbug.com/20191.
SelectService(service);
+ pending_service_ = service;
}
WiFiServiceRefPtr WiFi::FindService(const std::vector<uint8_t> &ssid,
@@ -306,7 +320,7 @@
scan_pending_ = false;
- // TODO(quiche): group endpoints into services, instead of creating
+ // TODO(quiche): Group endpoints into services, instead of creating
// a service for every endpoint.
for (EndpointMap::iterator i(endpoint_by_bssid_.begin());
i != endpoint_by_bssid_.end(); ++i) {
@@ -341,7 +355,7 @@
}
}
- // TODO(quiche): unregister removed services from manager
+ // TODO(quiche): Unregister removed services from manager.
}
void WiFi::ScanTask() {
@@ -361,7 +375,45 @@
scan_pending_ = true;
}
-// used by manager, via static WiFi::GetService method
+void WiFi::StateChanged(const string &new_state) {
+ const string &old_state = supplicant_state_;
+
+ LOG(INFO) << link_name() << " " << __func__ << " "
+ << old_state << " -> " << new_state;
+
+ if (pending_service_.get()) {
+ if (new_state == wpa_supplicant::kInterfaceStateCompleted) {
+ // TODO(quiche): Check if we have a race with LinkEvent and/or
+ // IPConfigUpdatedCallback here.
+
+ // After 802.11 negotiation is Completed, we start Configuring
+ // IP connectivity.
+ pending_service_->SetState(Service::kStateConfiguring);
+ } else if (new_state == wpa_supplicant::kInterfaceStateAssociated) {
+ pending_service_->SetState(Service::kStateAssociating);
+ } else if (new_state == wpa_supplicant::kInterfaceStateAuthenticating ||
+ new_state == wpa_supplicant::kInterfaceStateAssociating ||
+ new_state == wpa_supplicant::kInterfaceState4WayHandshake ||
+ new_state == wpa_supplicant::kInterfaceStateGroupHandshake) {
+ // Ignore transitions into these states from Completed, to avoid
+ // bothering the user when roaming, or re-keying.
+ if (old_state != wpa_supplicant::kInterfaceStateCompleted)
+ pending_service_->SetState(Service::kStateAssociating);
+ } else {
+ // Other transitions do not affect Service state.
+ //
+ // Note in particular that we ignore a State change into
+ // kInterfaceStateDisconnected, in favor of observing the corresponding
+ // change in CurrentBSS.
+ //
+ // TODO(quiche): Actually implement tracking of CurrentBSS.
+ }
+ }
+
+ supplicant_state_ = new_state;
+}
+
+// Used by Manager.
WiFiServiceRefPtr WiFi::GetService(const KeyValueStore &args, Error *error) {
if (!args.ContainsString(flimflam::kTypeProperty)) {
error->Populate(Error::kInvalidArguments, kManagerErrorTypeRequired);
@@ -446,8 +498,8 @@
security_method,
hidden_ssid);
services_.push_back(service);
- // TODO(quiche): add to service_by_private_id_?
- // TODO(quiche): register service with manager
+ // TODO(quiche): Add to |service_by_private_id_|?
+ // TODO(quiche): Register |service| with Manager.
}
if (security_method == flimflam::kSecurityWep ||
@@ -461,7 +513,7 @@
}
}
- // TODO(quiche): apply any other configuration parameters
+ // TODO(quiche): Apply any other configuration parameters.
return service;
}
diff --git a/wifi.h b/wifi.h
index 6965560..fd1cedf 100644
--- a/wifi.h
+++ b/wifi.h
@@ -46,6 +46,8 @@
// wpa_supplicant.
void BSSAdded(const ::DBus::Path &BSS,
const std::map<std::string, ::DBus::Variant> &properties);
+ void PropertiesChanged(
+ const std::map<std::string, ::DBus::Variant> &properties);
void ScanDone();
// called by WiFiService
@@ -57,8 +59,10 @@
virtual WiFiServiceRefPtr GetService(const KeyValueStore &args, Error *error);
private:
+ friend class WiFiMainTest; // access to supplicant_*_proxy_, link_up_
FRIEND_TEST(WiFiMainTest, FindServiceWEP);
FRIEND_TEST(WiFiMainTest, FindServiceWPA);
+ FRIEND_TEST(WiFiMainTest, InitialSupplicantState); // kInterfaceStateUnknown
typedef std::map<const std::string, WiFiEndpointRefPtr> EndpointMap;
typedef std::map<const std::string, WiFiServiceRefPtr> ServiceMap;
@@ -71,6 +75,7 @@
static const char kManagerErrorUnsupportedSecurityMode[];
static const char kManagerErrorUnsupportedServiceType[];
static const char kManagerErrorUnsupportedServiceMode[];
+ static const char kInterfaceStateUnknown[];
WiFiServiceRefPtr FindService(const std::vector<uint8_t> &ssid,
const std::string &mode,
@@ -78,6 +83,7 @@
ByteArrays GetHiddenSSIDList();
void ScanDoneTask();
void ScanTask();
+ void StateChanged(const std::string &new_state);
// Store cached copies of singletons for speed/ease of testing.
ProxyFactory *proxy_factory_;
@@ -96,8 +102,9 @@
uint16 scan_interval_;
bool link_up_;
std::vector<WiFiServiceRefPtr> services_;
+ WiFiServiceRefPtr pending_service_;
+ std::string supplicant_state_;
- friend class WiFiMainTest; // access to supplicant_*_proxy_, link_up_
DISALLOW_COPY_AND_ASSIGN(WiFi);
};
diff --git a/wifi_service.cc b/wifi_service.cc
index 3dd3362..6843d88 100644
--- a/wifi_service.cc
+++ b/wifi_service.cc
@@ -35,7 +35,7 @@
EventDispatcher *dispatcher,
Manager *manager,
const WiFiRefPtr &device,
- const std::vector<uint8_t> ssid,
+ const std::vector<uint8_t> &ssid,
const std::string &mode,
const std::string &security,
bool hidden_ssid)
diff --git a/wifi_service.h b/wifi_service.h
index 5f7b1e9..e3ad062 100644
--- a/wifi_service.h
+++ b/wifi_service.h
@@ -26,7 +26,7 @@
EventDispatcher *dispatcher,
Manager *manager,
const WiFiRefPtr &device,
- const std::vector<uint8_t> ssid,
+ const std::vector<uint8_t> &ssid,
const std::string &mode,
const std::string &security,
bool hidden_ssid);
diff --git a/wifi_unittest.cc b/wifi_unittest.cc
index 716ebc6..5185e46 100644
--- a/wifi_unittest.cc
+++ b/wifi_unittest.cc
@@ -13,6 +13,7 @@
#include <string>
#include <vector>
+#include <base/memory/ref_counted.h>
#include <base/memory/scoped_ptr.h>
#include <base/string_number_conversions.h>
#include <base/string_util.h>
@@ -33,6 +34,7 @@
#include "shill/mock_rtnl_handler.h"
#include "shill/mock_supplicant_interface_proxy.h"
#include "shill/mock_supplicant_process_proxy.h"
+#include "shill/mock_wifi_service.h"
#include "shill/nice_mock_control.h"
#include "shill/property_store_unittest.h"
#include "shill/proxy_factory.h"
@@ -48,6 +50,7 @@
using ::testing::AnyNumber;
using ::testing::DefaultValue;
using ::testing::InSequence;
+using ::testing::Mock;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::Test;
@@ -145,6 +148,8 @@
}
protected:
+ typedef scoped_refptr<MockWiFiService> MockWiFiServiceRefPtr;
+
class TestProxyFactory : public ProxyFactory {
public:
explicit TestProxyFactory(WiFiMainTest *test) : test_(test) {}
@@ -180,13 +185,28 @@
SupplicantInterfaceProxyInterface *GetSupplicantInterfaceProxy() {
return wifi_->supplicant_interface_proxy_.get();
}
- void InitiateConnect(WiFiService *service) {
+ const string &GetSupplicantState() {
+ return wifi_->supplicant_state_;
+ }
+ void InitiateConnect(WiFiServiceRefPtr service) {
map<string, ::DBus::Variant> params;
wifi_->ConnectTo(service, params);
}
bool IsLinkUp() {
return wifi_->link_up_;
}
+ MockWiFiServiceRefPtr MakeMockService() {
+ vector<uint8_t> ssid(1, 'a');
+ return new MockWiFiService(
+ &control_interface_,
+ &dispatcher_,
+ &manager_,
+ wifi_,
+ ssid,
+ flimflam::kModeManaged,
+ flimflam::kSecurityNone,
+ false);
+ }
void ReportBSS(const ::DBus::Path &bss_path,
const string &ssid,
const string &bssid,
@@ -198,6 +218,9 @@
void ReportScanDone() {
wifi_->ScanDoneTask();
}
+ void ReportStateChanged(const string &new_state) {
+ wifi_->StateChanged(new_state);
+ }
void StartWiFi() {
wifi_->Start();
}
@@ -739,4 +762,44 @@
dispatcher_.DispatchPendingEvents();
}
+TEST_F(WiFiMainTest, InitialSupplicantState) {
+ EXPECT_EQ(WiFi::kInterfaceStateUnknown, GetSupplicantState());
+}
+
+TEST_F(WiFiMainTest, StateChangeNoService) {
+ // State change should succeed even if there is no pending Service.
+ ReportStateChanged(wpa_supplicant::kInterfaceStateScanning);
+ EXPECT_EQ(wpa_supplicant::kInterfaceStateScanning, GetSupplicantState());
+}
+
+TEST_F(WiFiMainTest, StateChangeWithService) {
+ // Forward transition should trigger a Service state change.
+ StartWiFi();
+ dispatcher_.DispatchPendingEvents();
+ MockWiFiServiceRefPtr service = MakeMockService();
+ InitiateConnect(service);
+ EXPECT_CALL(*service.get(), SetState(Service::kStateAssociating));
+ ReportStateChanged(wpa_supplicant::kInterfaceStateAssociated);
+ // Verify expectations now, because WiFi may report other state changes
+ // when WiFi is Stop()-ed (during TearDown()).
+ Mock::VerifyAndClearExpectations(service.get());
+}
+
+TEST_F(WiFiMainTest, StateChangeBackwardsWithService) {
+ // Some backwards transitions should not trigger a Service state change.
+ // Supplicant state should still be updated, however.
+ StartWiFi();
+ dispatcher_.DispatchPendingEvents();
+ MockWiFiServiceRefPtr service = MakeMockService();
+ InitiateConnect(service);
+ ReportStateChanged(wpa_supplicant::kInterfaceStateCompleted);
+ EXPECT_CALL(*service.get(), SetState(_)).Times(0);
+ ReportStateChanged(wpa_supplicant::kInterfaceStateAuthenticating);
+ EXPECT_EQ(wpa_supplicant::kInterfaceStateAuthenticating,
+ GetSupplicantState());
+ // Verify expectations now, because WiFi may report other state changes
+ // when WiFi is Stop()-ed (during TearDown()).
+ Mock::VerifyAndClearExpectations(service.get());
+}
+
} // namespace shill
diff --git a/wpa_supplicant.cc b/wpa_supplicant.cc
index 2f79fac..01d5f9c 100644
--- a/wpa_supplicant.cc
+++ b/wpa_supplicant.cc
@@ -15,6 +15,16 @@
const char kDBusPath[] = "/fi/w1/wpa_supplicant1";
const char kDriverNL80211[] = "nl80211";
const char kErrorInterfaceExists[] = "fi.w1.wpa_supplicant1.InterfaceExists";
+const char kInterfacePropertyState[] = "State";
+const char kInterfaceState4WayHandshake[] = "4way_handshake";
+const char kInterfaceStateAssociated[] = "associated";
+const char kInterfaceStateAssociating[] = "associating";
+const char kInterfaceStateAuthenticating[] = "authenticating";
+const char kInterfaceStateCompleted[] = "completed";
+const char kInterfaceStateDisconnected[] = "disconnected";
+const char kInterfaceStateGroupHandshake[] = "group_handshake";
+const char kInterfaceStateInactive[] = "inactive";
+const char kInterfaceStateScanning[] = "scanning";
const char kKeyManagementMethodSuffixEAP[] = "-eap";
const char kKeyManagementMethodSuffixPSK[] = "-psk";
const char kKeyModeNone[] = "NONE";
diff --git a/wpa_supplicant.h b/wpa_supplicant.h
index 78aeaa6..5934629 100644
--- a/wpa_supplicant.h
+++ b/wpa_supplicant.h
@@ -18,6 +18,16 @@
extern const char kDBusPath[];
extern const char kDriverNL80211[];
extern const char kErrorInterfaceExists[];
+extern const char kInterfacePropertyState[];
+extern const char kInterfaceState4WayHandshake[];
+extern const char kInterfaceStateAssociated[];
+extern const char kInterfaceStateAssociating[];
+extern const char kInterfaceStateAuthenticating[];
+extern const char kInterfaceStateCompleted[];
+extern const char kInterfaceStateDisconnected[];
+extern const char kInterfaceStateGroupHandshake[];
+extern const char kInterfaceStateInactive[];
+extern const char kInterfaceStateScanning[];
extern const char kKeyManagementMethodSuffixEAP[];
extern const char kKeyManagementMethodSuffixPSK[];
extern const char kKeyModeNone[];