mac80211: send delBA on unexpected BlockAck data frames
authorJohannes Berg <johannes.berg@intel.com>
Mon, 29 Aug 2016 20:25:18 +0000 (23:25 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 12 Sep 2016 09:46:21 +0000 (11:46 +0200)
When we receive data frames with ACK policy BlockAck, send
delBA as requested by the 802.11 spec. Since this would be
happening for every frame inside an A-MPDU if it's really
received outside a session, limit it to a single attempt.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/agg-rx.c
net/mac80211/rx.c
net/mac80211/sta_info.h

index 282e99bdb3017d9ac074c20ab73a417aae81befd..a5d69dfc8e03ee41a47c10cbe21f0957ce58d543 100644 (file)
@@ -409,8 +409,10 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
        }
 
 end:
-       if (status == WLAN_STATUS_SUCCESS)
+       if (status == WLAN_STATUS_SUCCESS) {
                __set_bit(tid, sta->ampdu_mlme.agg_session_valid);
+               __clear_bit(tid, sta->ampdu_mlme.unexpected_agg);
+       }
        mutex_unlock(&sta->ampdu_mlme.mtx);
 
 end_no_lock:
index 284f0f25e22e9bd061553957b8f5db69b7464a6b..ad636c930f8438e3763b81c025aba47f73548244 100644 (file)
@@ -1122,8 +1122,15 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
        tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
 
        tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
-       if (!tid_agg_rx)
+       if (!tid_agg_rx) {
+               if (ack_policy == IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK &&
+                   !test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) &&
+                   !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg))
+                       ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid,
+                                            WLAN_BACK_RECIPIENT,
+                                            WLAN_REASON_QSTA_REQUIRE_SETUP);
                goto dont_reorder;
+       }
 
        /* qos null data frames are excluded */
        if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
index 0556be3e3628abe312f91af2c69227952038b71d..530231b73278cd1518ecd994aea02877eb7f11da 100644 (file)
@@ -230,6 +230,8 @@ struct tid_ampdu_rx {
  * @tid_rx_stop_requested:  bitmap indicating which BA sessions per TID the
  *     driver requested to close until the work for it runs
  * @agg_session_valid: bitmap indicating which TID has a rx BA session open on
+ * @unexpected_agg: bitmap indicating which TID already sent a delBA due to
+ *     unexpected aggregation related frames outside a session
  * @work: work struct for starting/stopping aggregation
  * @tid_tx: aggregation info for Tx per TID
  * @tid_start_tx: sessions where start was requested
@@ -244,6 +246,7 @@ struct sta_ampdu_mlme {
        unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
        unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
        unsigned long agg_session_valid[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
+       unsigned long unexpected_agg[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
        /* tx */
        struct work_struct work;
        struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS];