]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: mac80211: improve interface iteration ergonomics
authorJohannes Berg <johannes.berg@intel.com>
Thu, 8 Jan 2026 13:34:31 +0000 (14:34 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 12 Jan 2026 18:48:17 +0000 (19:48 +0100)
Right now, the only way to iterate interfaces is to declare an
iterator function, possibly data structure to use, and pass all
that to the iteration helper function. This is annoying, and
there's really no inherent need for it, except it was easier to
implement with the iflist mutex, but that's not used much now.

Add a new for_each_interface() macro that does the iteration in
a more ergonomic way. To avoid even more exported functions, do
the old ieee80211_iterate_active_interfaces_mtx() as an inline
using the new way, which may also let the compiler optimise it
a bit more, e.g. via inlining the iterator function.

Also provide for_each_active_interface() for the common case of
just iterating active interfaces.

Link: https://patch.msgid.link/20260108143431.f2581e0c381a.Ie387227504c975c109c125b3c57f0bb3fdab2835@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/mac80211.h
net/mac80211/util.c

index c2e49542626c8ec377bbcb10724bdf59a28e8baa..88ae5d60d9b9519d6fb029a8a7f2eff70aeb84d8 100644 (file)
@@ -6272,6 +6272,30 @@ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw,
                                                    struct ieee80211_vif *vif),
                                                void *data);
 
+struct ieee80211_vif *
+__ieee80211_iterate_interfaces(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *prev,
+                              u32 iter_flags);
+
+/**
+ * for_each_interface - iterate interfaces under wiphy mutex
+ * @vif: the iterator variable
+ * @hw: the HW to iterate for
+ * @flags: the iteration flags, see &enum ieee80211_interface_iteration_flags
+ */
+#define for_each_interface(vif, hw, flags)                             \
+       for (vif = __ieee80211_iterate_interfaces(hw, NULL, flags);     \
+            vif;                                                       \
+            vif = __ieee80211_iterate_interfaces(hw, vif, flags))
+
+/**
+ * for_each_active_interface - iterate active interfaces under wiphy mutex
+ * @vif: the iterator variable
+ * @hw: the HW to iterate for
+ */
+#define for_each_active_interface(vif, hw)                             \
+       for_each_interface(vif, hw, IEEE80211_IFACE_ITER_ACTIVE)
+
 /**
  * ieee80211_iterate_active_interfaces_mtx - iterate active interfaces
  *
@@ -6284,12 +6308,18 @@ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw,
  * @iterator: the iterator function to call, cannot sleep
  * @data: first argument of the iterator function
  */
-void ieee80211_iterate_active_interfaces_mtx(struct ieee80211_hw *hw,
-                                            u32 iter_flags,
-                                            void (*iterator)(void *data,
-                                               u8 *mac,
-                                               struct ieee80211_vif *vif),
-                                            void *data);
+static inline void
+ieee80211_iterate_active_interfaces_mtx(struct ieee80211_hw *hw,
+                                       u32 iter_flags,
+                                       void (*iterator)(void *data, u8 *mac,
+                                                        struct ieee80211_vif *vif),
+                                       void *data)
+{
+       struct ieee80211_vif *vif;
+
+       for_each_interface(vif, hw, iter_flags | IEEE80211_IFACE_ITER_ACTIVE)
+               iterator(data, vif->addr, vif);
+}
 
 /**
  * ieee80211_iterate_stations_atomic - iterate stations
index df219e463fb5a66f999039f74c0220de55e8d88b..a7e332a310226ef3705aa7a806827a4ce9482bce 100644 (file)
@@ -799,20 +799,56 @@ void ieee80211_iterate_active_interfaces_atomic(
 }
 EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
 
-void ieee80211_iterate_active_interfaces_mtx(
-       struct ieee80211_hw *hw, u32 iter_flags,
-       void (*iterator)(void *data, u8 *mac,
-                        struct ieee80211_vif *vif),
-       void *data)
+struct ieee80211_vif *
+__ieee80211_iterate_interfaces(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *prev,
+                              u32 iter_flags)
 {
+       bool active_only = iter_flags & IEEE80211_IFACE_ITER_ACTIVE;
+       struct ieee80211_sub_if_data *sdata = NULL, *monitor;
        struct ieee80211_local *local = hw_to_local(hw);
 
        lockdep_assert_wiphy(hw->wiphy);
 
-       __iterate_interfaces(local, iter_flags | IEEE80211_IFACE_ITER_ACTIVE,
-                            iterator, data);
+       if (prev)
+               sdata = vif_to_sdata(prev);
+
+       monitor = rcu_dereference_check(local->monitor_sdata,
+                                       lockdep_is_held(&hw->wiphy->mtx));
+       if (monitor && monitor == sdata)
+               return NULL;
+
+       sdata = list_prepare_entry(sdata, &local->interfaces, list);
+       list_for_each_entry_continue(sdata, &local->interfaces, list) {
+               switch (sdata->vif.type) {
+               case NL80211_IFTYPE_MONITOR:
+                       if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
+                           !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
+                               continue;
+                       break;
+               case NL80211_IFTYPE_AP_VLAN:
+                       continue;
+               default:
+                       break;
+               }
+               if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
+                   active_only && !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+                       continue;
+               if ((iter_flags & IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER) &&
+                   !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+                       continue;
+               if (ieee80211_sdata_running(sdata) || !active_only)
+                       return &sdata->vif;
+       }
+
+       if (monitor && ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
+           (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || !active_only ||
+            monitor->flags & IEEE80211_SDATA_IN_DRIVER))
+               return &monitor->vif;
+
+       return NULL;
 }
-EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_mtx);
+EXPORT_SYMBOL_GPL(__ieee80211_iterate_interfaces);
 
 static void __iterate_stations(struct ieee80211_local *local,
                               void (*iterator)(void *data,