mac80211: allow to get wireless_dev structure from ieee80211_vif
[firefly-linux-kernel-4.4.55.git] / net / mac80211 / util.c
index eec94447eef78bb589fd73e0826c6886bc3a2339..e664b28821a2e571b2ce6f5e6963cf8fd5d75485 100644 (file)
@@ -625,13 +625,14 @@ void ieee80211_wake_vif_queues(struct ieee80211_local *local,
                                        reason, true);
 }
 
-static void __iterate_active_interfaces(struct ieee80211_local *local,
-                                       u32 iter_flags,
-                                       void (*iterator)(void *data, u8 *mac,
-                                               struct ieee80211_vif *vif),
-                                       void *data)
+static void __iterate_interfaces(struct ieee80211_local *local,
+                                u32 iter_flags,
+                                void (*iterator)(void *data, u8 *mac,
+                                                 struct ieee80211_vif *vif),
+                                void *data)
 {
        struct ieee80211_sub_if_data *sdata;
+       bool active_only = iter_flags & IEEE80211_IFACE_ITER_ACTIVE;
 
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
                switch (sdata->vif.type) {
@@ -645,9 +646,9 @@ static void __iterate_active_interfaces(struct ieee80211_local *local,
                        break;
                }
                if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
-                   !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+                   active_only && !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
                        continue;
-               if (ieee80211_sdata_running(sdata))
+               if (ieee80211_sdata_running(sdata) || !active_only)
                        iterator(data, sdata->vif.addr,
                                 &sdata->vif);
        }
@@ -656,12 +657,12 @@ static void __iterate_active_interfaces(struct ieee80211_local *local,
                                      lockdep_is_held(&local->iflist_mtx) ||
                                      lockdep_rtnl_is_held());
        if (sdata &&
-           (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
+           (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || !active_only ||
             sdata->flags & IEEE80211_SDATA_IN_DRIVER))
                iterator(data, sdata->vif.addr, &sdata->vif);
 }
 
-void ieee80211_iterate_active_interfaces(
+void ieee80211_iterate_interfaces(
        struct ieee80211_hw *hw, u32 iter_flags,
        void (*iterator)(void *data, u8 *mac,
                         struct ieee80211_vif *vif),
@@ -670,10 +671,10 @@ void ieee80211_iterate_active_interfaces(
        struct ieee80211_local *local = hw_to_local(hw);
 
        mutex_lock(&local->iflist_mtx);
-       __iterate_active_interfaces(local, iter_flags, iterator, data);
+       __iterate_interfaces(local, iter_flags, iterator, data);
        mutex_unlock(&local->iflist_mtx);
 }
-EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
+EXPORT_SYMBOL_GPL(ieee80211_iterate_interfaces);
 
 void ieee80211_iterate_active_interfaces_atomic(
        struct ieee80211_hw *hw, u32 iter_flags,
@@ -684,7 +685,8 @@ void ieee80211_iterate_active_interfaces_atomic(
        struct ieee80211_local *local = hw_to_local(hw);
 
        rcu_read_lock();
-       __iterate_active_interfaces(local, iter_flags, iterator, data);
+       __iterate_interfaces(local, iter_flags | IEEE80211_IFACE_ITER_ACTIVE,
+                            iterator, data);
        rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
@@ -699,7 +701,8 @@ void ieee80211_iterate_active_interfaces_rtnl(
 
        ASSERT_RTNL();
 
-       __iterate_active_interfaces(local, iter_flags, iterator, data);
+       __iterate_interfaces(local, iter_flags | IEEE80211_IFACE_ITER_ACTIVE,
+                            iterator, data);
 }
 EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl);
 
@@ -742,6 +745,18 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev)
 }
 EXPORT_SYMBOL_GPL(wdev_to_ieee80211_vif);
 
+struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+       if (!ieee80211_sdata_running(sdata) ||
+           !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+               return NULL;
+
+       return &sdata->wdev;
+}
+EXPORT_SYMBOL_GPL(ieee80211_vif_to_wdev);
+
 /*
  * Nothing should have been stuffed into the workqueue during
  * the suspend->resume cycle. Since we can't check each caller
@@ -1811,8 +1826,25 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        list_for_each_entry(sdata, &local->interfaces, list) {
                if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
                    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
-                   ieee80211_sdata_running(sdata))
+                   ieee80211_sdata_running(sdata)) {
                        res = drv_add_interface(local, sdata);
+                       if (WARN_ON(res))
+                               break;
+               }
+       }
+
+       /* If adding any of the interfaces failed above, roll back and
+        * report failure.
+        */
+       if (res) {
+               list_for_each_entry_continue_reverse(sdata, &local->interfaces,
+                                                    list)
+                       if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+                           sdata->vif.type != NL80211_IFTYPE_MONITOR &&
+                           ieee80211_sdata_running(sdata))
+                               drv_remove_interface(local, sdata);
+               ieee80211_handle_reconfig_failure(local);
+               return res;
        }
 
        /* add channel contexts */