|
|
@@ -0,0 +1,148 @@
|
|
|
+From: Johannes Berg <[email protected]>
|
|
|
+Date: Thu, 8 Jan 2026 14:34:31 +0100
|
|
|
+Subject: [PATCH] wifi: mac80211: improve interface iteration ergonomics
|
|
|
+
|
|
|
+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 <[email protected]>
|
|
|
+---
|
|
|
+
|
|
|
+--- a/include/net/mac80211.h
|
|
|
++++ b/include/net/mac80211.h
|
|
|
+@@ -6270,6 +6270,30 @@ void ieee80211_iterate_active_interfaces
|
|
|
+ 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
|
|
|
+ *
|
|
|
+@@ -6282,12 +6306,18 @@ void ieee80211_iterate_active_interfaces
|
|
|
+ * @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
|
|
|
+--- a/net/mac80211/util.c
|
|
|
++++ b/net/mac80211/util.c
|
|
|
+@@ -800,20 +800,56 @@ void ieee80211_iterate_active_interfaces
|
|
|
+ }
|
|
|
+ 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,
|