aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/sta_info.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r--net/mac80211/sta_info.c46
1 files changed, 41 insertions, 5 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index f3e502502fee..ca9fde198188 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -91,9 +91,8 @@ static int sta_info_hash_del(struct ieee80211_local *local,
91 return -ENOENT; 91 return -ENOENT;
92} 92}
93 93
94static void free_sta_work(struct work_struct *wk) 94static void cleanup_single_sta(struct sta_info *sta)
95{ 95{
96 struct sta_info *sta = container_of(wk, struct sta_info, free_sta_wk);
97 int ac, i; 96 int ac, i;
98 struct tid_ampdu_tx *tid_tx; 97 struct tid_ampdu_tx *tid_tx;
99 struct ieee80211_sub_if_data *sdata = sta->sdata; 98 struct ieee80211_sub_if_data *sdata = sta->sdata;
@@ -153,11 +152,35 @@ static void free_sta_work(struct work_struct *wk)
153 sta_info_free(local, sta); 152 sta_info_free(local, sta);
154} 153}
155 154
155void ieee80211_cleanup_sdata_stas(struct ieee80211_sub_if_data *sdata)
156{
157 struct sta_info *sta;
158
159 spin_lock_bh(&sdata->cleanup_stations_lock);
160 while (!list_empty(&sdata->cleanup_stations)) {
161 sta = list_first_entry(&sdata->cleanup_stations,
162 struct sta_info, list);
163 list_del(&sta->list);
164 spin_unlock_bh(&sdata->cleanup_stations_lock);
165
166 cleanup_single_sta(sta);
167
168 spin_lock_bh(&sdata->cleanup_stations_lock);
169 }
170
171 spin_unlock_bh(&sdata->cleanup_stations_lock);
172}
173
156static void free_sta_rcu(struct rcu_head *h) 174static void free_sta_rcu(struct rcu_head *h)
157{ 175{
158 struct sta_info *sta = container_of(h, struct sta_info, rcu_head); 176 struct sta_info *sta = container_of(h, struct sta_info, rcu_head);
177 struct ieee80211_sub_if_data *sdata = sta->sdata;
159 178
160 ieee80211_queue_work(&sta->local->hw, &sta->free_sta_wk); 179 spin_lock(&sdata->cleanup_stations_lock);
180 list_add_tail(&sta->list, &sdata->cleanup_stations);
181 spin_unlock(&sdata->cleanup_stations_lock);
182
183 ieee80211_queue_work(&sdata->local->hw, &sdata->cleanup_stations_wk);
161} 184}
162 185
163/* protected by RCU */ 186/* protected by RCU */
@@ -310,7 +333,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
310 333
311 spin_lock_init(&sta->lock); 334 spin_lock_init(&sta->lock);
312 INIT_WORK(&sta->drv_unblock_wk, sta_unblock); 335 INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
313 INIT_WORK(&sta->free_sta_wk, free_sta_work);
314 INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); 336 INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
315 mutex_init(&sta->ampdu_mlme.mtx); 337 mutex_init(&sta->ampdu_mlme.mtx);
316 338
@@ -862,7 +884,7 @@ void sta_info_init(struct ieee80211_local *local)
862 884
863void sta_info_stop(struct ieee80211_local *local) 885void sta_info_stop(struct ieee80211_local *local)
864{ 886{
865 del_timer(&local->sta_cleanup); 887 del_timer_sync(&local->sta_cleanup);
866 sta_info_flush(local, NULL); 888 sta_info_flush(local, NULL);
867} 889}
868 890
@@ -891,6 +913,20 @@ int sta_info_flush(struct ieee80211_local *local,
891 } 913 }
892 mutex_unlock(&local->sta_mtx); 914 mutex_unlock(&local->sta_mtx);
893 915
916 rcu_barrier();
917
918 if (sdata) {
919 ieee80211_cleanup_sdata_stas(sdata);
920 cancel_work_sync(&sdata->cleanup_stations_wk);
921 } else {
922 mutex_lock(&local->iflist_mtx);
923 list_for_each_entry(sdata, &local->interfaces, list) {
924 ieee80211_cleanup_sdata_stas(sdata);
925 cancel_work_sync(&sdata->cleanup_stations_wk);
926 }
927 mutex_unlock(&local->iflist_mtx);
928 }
929
894 return ret; 930 return ret;
895} 931}
896 932