aboutsummaryrefslogtreecommitdiff
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.c60
1 files changed, 38 insertions, 22 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index ba36fc29e532..0ba613dd1cc4 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -113,6 +113,23 @@ static int link_sta_info_hash_del(struct ieee80211_local *local,
&link_sta->link_hash_node, link_sta_rht_params);
}
+void ieee80211_purge_sta_txqs(struct sta_info *sta)
+{
+ struct ieee80211_local *local = sta->sdata->local;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
+ struct txq_info *txqi;
+
+ if (!sta->sta.txq[i])
+ continue;
+
+ txqi = to_txq_info(sta->sta.txq[i]);
+
+ ieee80211_txq_purge(local, txqi);
+ }
+}
+
static void __cleanup_single_sta(struct sta_info *sta)
{
int ac, i;
@@ -139,16 +156,7 @@ static void __cleanup_single_sta(struct sta_info *sta)
atomic_dec(&ps->num_sta_ps);
}
- for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
- struct txq_info *txqi;
-
- if (!sta->sta.txq[i])
- continue;
-
- txqi = to_txq_info(sta->sta.txq[i]);
-
- ieee80211_txq_purge(local, txqi);
- }
+ ieee80211_purge_sta_txqs(sta);
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]);
@@ -1267,6 +1275,8 @@ static int _sta_info_move_state(struct sta_info *sta,
enum ieee80211_sta_state new_state,
bool recalc)
{
+ struct ieee80211_local *local = sta->local;
+
might_sleep();
if (sta->sta_state == new_state)
@@ -1342,6 +1352,24 @@ static int _sta_info_move_state(struct sta_info *sta,
} else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) {
ieee80211_vif_dec_num_mcast(sta->sdata);
clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
+
+ /*
+ * If we have encryption offload, flush (station) queues
+ * (after ensuring concurrent TX completed) so we won't
+ * transmit anything later unencrypted if/when keys are
+ * also removed, which might otherwise happen depending
+ * on how the hardware offload works.
+ */
+ if (local->ops->set_key) {
+ synchronize_net();
+ if (local->ops->flush_sta)
+ drv_flush_sta(local, sta->sdata, sta);
+ else
+ ieee80211_flush_queues(local,
+ sta->sdata,
+ false);
+ }
+
ieee80211_clear_fast_xmit(sta);
ieee80211_clear_fast_rx(sta);
}
@@ -1407,18 +1435,6 @@ static void __sta_info_destroy_part2(struct sta_info *sta, bool recalc)
WARN_ON_ONCE(ret);
}
- /* Flush queues before removing keys, as that might remove them
- * from hardware, and then depending on the offload method, any
- * frames sitting on hardware queues might be sent out without
- * any encryption at all.
- */
- if (local->ops->set_key) {
- if (local->ops->flush_sta)
- drv_flush_sta(local, sta->sdata, sta);
- else
- ieee80211_flush_queues(local, sta->sdata, false);
- }
-
/* now keys can no longer be reached */
ieee80211_free_sta_keys(local, sta);