diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4a80d74975e8..dae3f9ec1154 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1594,13 +1594,16 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw); void ieee80211_scan_completed(struct ieee80211_hw *hw); /** - * ieee80211_iterate_active_interfaces - iterate active interfaces + * ieee80211_iterate_active_interfaces- iterate active interfaces * * This function iterates over the interfaces associated with a given * hardware that are currently active and calls the callback for them. + * This function allows the iterator function to sleep, when the iterator + * function is atomic @ieee80211_iterate_active_interfaces_atomic can + * be used. * * @hw: the hardware struct of which the interfaces should be iterated over - * @iterator: the iterator function to call, cannot sleep + * @iterator: the iterator function to call * @data: first argument of the iterator function */ void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw, @@ -1608,6 +1611,24 @@ void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw, struct ieee80211_vif *vif), void *data); +/** + * ieee80211_iterate_active_interfaces_atomic - iterate active interfaces + * + * This function iterates over the interfaces associated with a given + * hardware that are currently active and calls the callback for them. + * This function requires the iterator callback function to be atomic, + * if that is not desired, use @ieee80211_iterate_active_interfaces instead. + * + * @hw: the hardware struct of which the interfaces should be iterated over + * @iterator: the iterator function to call, cannot sleep + * @data: first argument of the iterator function + */ +void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw, + void (*iterator)(void *data, + u8 *mac, + struct ieee80211_vif *vif), + void *data); + /** * ieee80211_start_tx_ba_session - Start a tx Block Ack session. * @hw: pointer as obtained from ieee80211_alloc_hw(). diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 24a465c4df09..131e9e6c8a32 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -389,6 +389,41 @@ void ieee80211_iterate_active_interfaces( struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; + rtnl_lock(); + + list_for_each_entry(sdata, &local->interfaces, list) { + switch (sdata->vif.type) { + case IEEE80211_IF_TYPE_INVALID: + case IEEE80211_IF_TYPE_MNTR: + case IEEE80211_IF_TYPE_VLAN: + continue; + case IEEE80211_IF_TYPE_AP: + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: + case IEEE80211_IF_TYPE_WDS: + case IEEE80211_IF_TYPE_MESH_POINT: + break; + } + if (sdata->dev == local->mdev) + continue; + if (netif_running(sdata->dev)) + iterator(data, sdata->dev->dev_addr, + &sdata->vif); + } + + rtnl_unlock(); +} +EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); + +void ieee80211_iterate_active_interfaces_atomic( + struct ieee80211_hw *hw, + void (*iterator)(void *data, u8 *mac, + struct ieee80211_vif *vif), + void *data) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata; + rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { @@ -413,4 +448,4 @@ void ieee80211_iterate_active_interfaces( rcu_read_unlock(); } -EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); +EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);