mac80211: don't reorder frames with SN smaller than SSN
authorSara Sharon <sara.sharon@intel.com>
Mon, 6 Feb 2017 13:28:42 +0000 (15:28 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 27 Feb 2017 13:00:26 +0000 (14:00 +0100)
When RX aggregation starts, transmitter may continue send frames
with SN smaller than SSN until the AddBA response is received.
However, the reorder buffer is already initialized at this point,
which will cause the drop of such frames as duplicates since the
head SN of the reorder buffer is set to the SSN, which is bigger.

Cc: stable@vger.kernel.org
Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/agg-rx.c
net/mac80211/rx.c
net/mac80211/sta_info.h

index 3b5fd4188f2ac7c67c269ad425812221294c823e..58ad23a441097c6f621dee8f7baf0961c252e96c 100644 (file)
@@ -398,6 +398,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
        tid_agg_rx->timeout = timeout;
        tid_agg_rx->stored_mpdu_num = 0;
        tid_agg_rx->auto_seq = auto_seq;
+       tid_agg_rx->started = false;
        tid_agg_rx->reorder_buf_filtered = 0;
        status = WLAN_STATUS_SUCCESS;
 
index a8443d8bc2332377514b40a55fd5e6a8513c0d40..28cc494a774d0e5e2180965fbc7731b2f7f8125c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
- * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -1034,6 +1034,18 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
        buf_size = tid_agg_rx->buf_size;
        head_seq_num = tid_agg_rx->head_seq_num;
 
+       /*
+        * If the current MPDU's SN is smaller than the SSN, it shouldn't
+        * be reordered.
+        */
+       if (unlikely(!tid_agg_rx->started)) {
+               if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) {
+                       ret = false;
+                       goto out;
+               }
+               tid_agg_rx->started = true;
+       }
+
        /* frame with out of date sequence number */
        if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) {
                dev_kfree_skb(skb);
index dd06ef0b88614566ea4eb751a314856d38fb0e39..15599c70a38fc9741d31df9a753f313f465ae8a3 100644 (file)
@@ -189,6 +189,7 @@ struct tid_ampdu_tx {
  * @auto_seq: used for offloaded BA sessions to automatically pick head_seq_and
  *     and ssn.
  * @removed: this session is removed (but might have been found due to RCU)
+ * @started: this session has started (head ssn or higher was received)
  *
  * This structure's lifetime is managed by RCU, assignments to
  * the array holding it must hold the aggregation mutex.
@@ -212,8 +213,9 @@ struct tid_ampdu_rx {
        u16 ssn;
        u16 buf_size;
        u16 timeout;
-       bool auto_seq;
-       bool removed;
+       u8 auto_seq:1,
+          removed:1,
+          started:1;
 };
 
 /**