Shill: Wait until cfg80211/mac80211 are up before trying to configure.

BUG=chromium-os:33837
TEST=Updated unit tests.

Change-Id: I69711d0a3c366297b0568bca770dd50c2a44f722
Reviewed-on: https://gerrit.chromium.org/gerrit/31237
Commit-Ready: Wade Guthrie <wdg@chromium.org>
Reviewed-by: Wade Guthrie <wdg@chromium.org>
Tested-by: Wade Guthrie <wdg@chromium.org>
diff --git a/config80211.cc b/config80211.cc
index 2343da5..64a7b84 100644
--- a/config80211.cc
+++ b/config80211.cc
@@ -13,6 +13,7 @@
 #include <string>
 
 #include <base/memory/weak_ptr.h>
+#include <base/stl_util.h>
 #include <base/stringprintf.h>
 
 #include "shill/io_handler.h"
@@ -24,7 +25,6 @@
 using base::Bind;
 using base::LazyInstance;
 using base::StringAppendF;
-using std::map;
 using std::string;
 
 namespace shill {
@@ -33,10 +33,11 @@
 LazyInstance<Config80211> g_config80211 = LAZY_INSTANCE_INITIALIZER;
 }  // namespace
 
-map<Config80211::EventType, std::string> *Config80211::event_types_ = NULL;
+Config80211::EventTypeStrings *Config80211::event_types_ = NULL;
 
 Config80211::Config80211()
-    : dispatcher_(NULL),
+    : wifi_state_(kWifiDown),
+      dispatcher_(NULL),
       weak_ptr_factory_(this),
       dispatcher_callback_(Bind(&Config80211::HandleIncomingEvents,
                               weak_ptr_factory_.GetWeakPtr())),
@@ -54,6 +55,11 @@
   return g_config80211.Pointer();
 }
 
+void Config80211::Reset() {
+  wifi_state_ = kWifiDown;
+  subscribed_events_.clear();
+}
+
 bool Config80211::Init(EventDispatcher *dispatcher) {
   if (!sock_) {
     sock_ = new Nl80211Socket;
@@ -68,7 +74,7 @@
   }
 
   if (!event_types_) {
-    event_types_ = new std::map<EventType, std::string>;
+    event_types_ = new EventTypeStrings;
     (*event_types_)[Config80211::kEventTypeConfig] = "config";
     (*event_types_)[Config80211::kEventTypeScan] = "scan";
     (*event_types_)[Config80211::kEventTypeRegulatory] = "regulatory";
@@ -98,7 +104,7 @@
     return false;
   }
 
-  map<EventType, string>::iterator match = (*event_types_).find(type);
+  EventTypeStrings::iterator match = (*event_types_).find(type);
   if (match == (*event_types_).end()) {
     LOG(ERROR) << "Event type " << type << " not found";
     return false;
@@ -107,8 +113,44 @@
   return true;
 }
 
+void Config80211::SetWifiState(WifiState new_state) {
+  if (wifi_state_ == new_state) {
+    return;
+  }
+
+  // If we're newly-up, subscribe to all the event types that have been
+  // requested.
+  if (new_state == kWifiUp) {
+    SubscribedEvents::const_iterator i;
+    for (i = subscribed_events_.begin(); i != subscribed_events_.end(); ++i) {
+      string event_type_string;
+      GetEventTypeString(*i, &event_type_string);
+      ActuallySubscribeToEvents(*i);
+    }
+  }
+  wifi_state_ = new_state;
+}
+
 bool Config80211::SubscribeToEvents(EventType type) {
+  string event_type_string;
+  GetEventTypeString(type, &event_type_string);
+  bool it_worked = true;
+  if (!ContainsKey(subscribed_events_, type)) {
+    if (wifi_state_ == kWifiUp) {
+      it_worked = ActuallySubscribeToEvents(type);
+    }
+    // |subscribed_events_| is a list of events to which we want to subscribe
+    // when wifi comes up (including when it comes _back_ up after it goes
+    // down sometime in the future).
+    subscribed_events_.insert(type);
+  }
+  return it_worked;
+}
+
+bool Config80211::ActuallySubscribeToEvents(EventType type) {
   string group_name;
+  string event_type_string;
+  GetEventTypeString(type, &event_type_string);
 
   if (!GetEventTypeString(type, &group_name)) {
     return false;
@@ -116,7 +158,6 @@
   if (!sock_->AddGroupMembership(group_name)) {
     return false;
   }
-
   // No sequence checking for multicast messages.
   if (!sock_->DisableSequenceChecking()) {
     return false;