* [PATCH 1/2] wifi: mac80211: improve interface iteration ergonomics
@ 2026-01-08 13:34 Johannes Berg
2026-01-08 13:34 ` [PATCH 2/2] wifi: mac80211: improve station " Johannes Berg
0 siblings, 1 reply; 5+ messages in thread
From: Johannes Berg @ 2026-01-08 13:34 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
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.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/mac80211.h | 42 +++++++++++++++++++++++++++++-----
net/mac80211/util.c | 52 +++++++++++++++++++++++++++++++++++-------
2 files changed, 80 insertions(+), 14 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index c2e49542626c..88ae5d60d9b9 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -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
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 0c46009a3d63..13f2e911f330 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -800,20 +800,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,
--
2.52.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 2/2] wifi: mac80211: improve station iteration ergonomics
2026-01-08 13:34 [PATCH 1/2] wifi: mac80211: improve interface iteration ergonomics Johannes Berg
@ 2026-01-08 13:34 ` Johannes Berg
2026-02-11 6:49 ` Ping-Ke Shih
0 siblings, 1 reply; 5+ messages in thread
From: Johannes Berg @ 2026-01-08 13:34 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
Right now, the only way to iterate stations 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.
Add a new for_each_station() macro that does the iteration in
a more ergonomic way. To avoid even more exported functions, do
the old ieee80211_iterate_stations_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.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/mac80211.h | 29 +++++++++++++++++++++++++----
net/mac80211/util.c | 23 +++++++++++++++++------
2 files changed, 42 insertions(+), 10 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 88ae5d60d9b9..36daccef6554 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -6338,6 +6338,20 @@ void ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw,
struct ieee80211_sta *sta),
void *data);
+struct ieee80211_sta *
+__ieee80211_iterate_stations(struct ieee80211_hw *hw,
+ struct ieee80211_sta *prev);
+
+/**
+ * for_each_station - iterate stations under wiphy mutex
+ * @sta: the iterator variable
+ * @hw: the HW to iterate for
+ */
+#define for_each_station(sta, hw) \
+ for (sta = __ieee80211_iterate_stations(hw, NULL); \
+ sta; \
+ sta = __ieee80211_iterate_stations(hw, sta))
+
/**
* ieee80211_iterate_stations_mtx - iterate stations
*
@@ -6350,10 +6364,17 @@ void ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw,
* @iterator: the iterator function to call
* @data: first argument of the iterator function
*/
-void ieee80211_iterate_stations_mtx(struct ieee80211_hw *hw,
- void (*iterator)(void *data,
- struct ieee80211_sta *sta),
- void *data);
+static inline void
+ieee80211_iterate_stations_mtx(struct ieee80211_hw *hw,
+ void (*iterator)(void *data,
+ struct ieee80211_sta *sta),
+ void *data)
+{
+ struct ieee80211_sta *sta;
+
+ for_each_station(sta, hw)
+ iterator(data, sta);
+}
/**
* ieee80211_queue_work - add work onto the mac80211 workqueue
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 13f2e911f330..b95f7d50e77d 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -880,18 +880,29 @@ void ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_stations_atomic);
-void ieee80211_iterate_stations_mtx(struct ieee80211_hw *hw,
- void (*iterator)(void *data,
- struct ieee80211_sta *sta),
- void *data)
+struct ieee80211_sta *
+__ieee80211_iterate_stations(struct ieee80211_hw *hw,
+ struct ieee80211_sta *prev)
{
struct ieee80211_local *local = hw_to_local(hw);
+ struct sta_info *sta = NULL;
lockdep_assert_wiphy(local->hw.wiphy);
- __iterate_stations(local, iterator, data);
+ if (prev)
+ sta = container_of(prev, struct sta_info, sta);
+
+ sta = list_prepare_entry(sta, &local->sta_list, list);
+ list_for_each_entry_continue(sta, &local->sta_list, list) {
+ if (!sta->uploaded)
+ continue;
+
+ return &sta->sta;
+ }
+
+ return NULL;
}
-EXPORT_SYMBOL_GPL(ieee80211_iterate_stations_mtx);
+EXPORT_SYMBOL_GPL(__ieee80211_iterate_stations);
struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev)
{
--
2.52.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* RE: [PATCH 2/2] wifi: mac80211: improve station iteration ergonomics
2026-01-08 13:34 ` [PATCH 2/2] wifi: mac80211: improve station " Johannes Berg
@ 2026-02-11 6:49 ` Ping-Ke Shih
2026-02-11 7:54 ` Johannes Berg
0 siblings, 1 reply; 5+ messages in thread
From: Ping-Ke Shih @ 2026-02-11 6:49 UTC (permalink / raw)
To: Johannes Berg, linux-wireless@vger.kernel.org; +Cc: Johannes Berg
Hi Johannes,
> +/**
> + * for_each_station - iterate stations under wiphy mutex
> + * @sta: the iterator variable
> + * @hw: the HW to iterate for
> + */
> +#define for_each_station(sta, hw) \
> + for (sta = __ieee80211_iterate_stations(hw, NULL); \
> + sta; \
> + sta = __ieee80211_iterate_stations(hw, sta))
> +
I'm going to use for_each_station() in rtw89 driver, and the code in driver side
looks very simple! Thanks for this new API.
However, without other callers rather than ieee80211_iterate_xxx(), I'd like
to know if it is expected that driver uses for_each_station()? Since help
text is added, I think it can be, right?
Another question is that adding ieee80211_ prefix would be consistent with
other API? If you agree, I can make patches.
As well as for_each_interface().
Ping-Ke
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] wifi: mac80211: improve station iteration ergonomics
2026-02-11 6:49 ` Ping-Ke Shih
@ 2026-02-11 7:54 ` Johannes Berg
2026-02-11 8:08 ` Ping-Ke Shih
0 siblings, 1 reply; 5+ messages in thread
From: Johannes Berg @ 2026-02-11 7:54 UTC (permalink / raw)
To: Ping-Ke Shih, linux-wireless@vger.kernel.org
On Wed, 2026-02-11 at 06:49 +0000, Ping-Ke Shih wrote:
> Hi Johannes,
>
> > +/**
> > + * for_each_station - iterate stations under wiphy mutex
> > + * @sta: the iterator variable
> > + * @hw: the HW to iterate for
> > + */
> > +#define for_each_station(sta, hw) \
> > + for (sta = __ieee80211_iterate_stations(hw, NULL); \
> > + sta; \
> > + sta = __ieee80211_iterate_stations(hw, sta))
> > +
>
> I'm going to use for_each_station() in rtw89 driver, and the code in driver side
> looks very simple! Thanks for this new API.
>
> However, without other callers rather than ieee80211_iterate_xxx(), I'd like
> to know if it is expected that driver uses for_each_station()? Since help
> text is added, I think it can be, right?
Yeah definitely, I wouldn't have added it to mac80211.h otherwise. I'm
already using it in our driver, those patches just haven't gone upstream
yet.
> Another question is that adding ieee80211_ prefix would be consistent with
> other API? If you agree, I can make patches.
>
> As well as for_each_interface().
Yeah that's a good question I guess. There's some precedent either way,
e.g. for_each_netdev() and netdev_for_each_uc_addr(), though it's a bit
more along the lines of "object_for_each_member()" rather than
"subsystem_for_each_something()" - which would be more like
ieee80211_hw_for_each_station() here? The notable exception to this
being damon_*. And objects are also missing, we have for_each_netdev(),
not netns_for_each_netdev().
Oh and the order of arguments is also not consistent anywhere it seems.
list_for_each_entry() is "iter, list, member", whereas for_each_netdev()
is "net, iter".
I suppose I have no strong opinion about it, there doesn't really seem
to be _any_ consistency around it. Maybe we should be consistent overall
with them though in mac80211.h, and if renaming not just do the new
ones? And maybe that's not worth the churn?
Yeah I don't know what to say I guess, I suppose that means if you feel
strongly one or the other is better I'm happy to adjust :)
johannes
^ permalink raw reply [flat|nested] 5+ messages in thread
* RE: [PATCH 2/2] wifi: mac80211: improve station iteration ergonomics
2026-02-11 7:54 ` Johannes Berg
@ 2026-02-11 8:08 ` Ping-Ke Shih
0 siblings, 0 replies; 5+ messages in thread
From: Ping-Ke Shih @ 2026-02-11 8:08 UTC (permalink / raw)
To: Johannes Berg, linux-wireless@vger.kernel.org
Johannes Berg <johannes@sipsolutions.net> wrote:
> On Wed, 2026-02-11 at 06:49 +0000, Ping-Ke Shih wrote:
> > Hi Johannes,
> >
> > > +/**
> > > + * for_each_station - iterate stations under wiphy mutex
> > > + * @sta: the iterator variable
> > > + * @hw: the HW to iterate for
> > > + */
> > > +#define for_each_station(sta, hw) \
> > > + for (sta = __ieee80211_iterate_stations(hw, NULL); \
> > > + sta; \
> > > + sta = __ieee80211_iterate_stations(hw, sta))
> > > +
> >
> > I'm going to use for_each_station() in rtw89 driver, and the code in driver side
> > looks very simple! Thanks for this new API.
> >
> > However, without other callers rather than ieee80211_iterate_xxx(), I'd like
> > to know if it is expected that driver uses for_each_station()? Since help
> > text is added, I think it can be, right?
>
> Yeah definitely, I wouldn't have added it to mac80211.h otherwise. I'm
> already using it in our driver, those patches just haven't gone upstream
> yet.
>
> > Another question is that adding ieee80211_ prefix would be consistent with
> > other API? If you agree, I can make patches.
> >
> > As well as for_each_interface().
>
> Yeah that's a good question I guess. There's some precedent either way,
> e.g. for_each_netdev() and netdev_for_each_uc_addr(), though it's a bit
> more along the lines of "object_for_each_member()" rather than
> "subsystem_for_each_something()" - which would be more like
> ieee80211_hw_for_each_station() here? The notable exception to this
> being damon_*. And objects are also missing, we have for_each_netdev(),
> not netns_for_each_netdev().
>
> Oh and the order of arguments is also not consistent anywhere it seems.
> list_for_each_entry() is "iter, list, member", whereas for_each_netdev()
> is "net, iter".
>
> I suppose I have no strong opinion about it, there doesn't really seem
> to be _any_ consistency around it. Maybe we should be consistent overall
> with them though in mac80211.h, and if renaming not just do the new
> ones? And maybe that's not worth the churn?
>
> Yeah I don't know what to say I guess, I suppose that means if you feel
> strongly one or the other is better I'm happy to adjust :)
I don't have strong opinion to either one. Let's keep as it was. :)
Ping-Ke
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-02-11 8:08 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-08 13:34 [PATCH 1/2] wifi: mac80211: improve interface iteration ergonomics Johannes Berg
2026-01-08 13:34 ` [PATCH 2/2] wifi: mac80211: improve station " Johannes Berg
2026-02-11 6:49 ` Ping-Ke Shih
2026-02-11 7:54 ` Johannes Berg
2026-02-11 8:08 ` Ping-Ke Shih
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox