iwlwifi: mvm: ignore BAID for SN smaller than SSN
authorSara Sharon <sara.sharon@intel.com>
Thu, 2 Feb 2017 10:51:39 +0000 (12:51 +0200)
committerLuca Coelho <luciano.coelho@intel.com>
Wed, 19 Apr 2017 19:21:47 +0000 (22:21 +0300)
When we get SN that is smaller than SSN of the aggregation,
we shouldn't apply any reordering on them.
Further more, HW NSSN will be zeroed, which can cause us
to make some invalid decisions.
Detect the situation and invalidate the BAID.

Fixes: b915c10174fb ("iwlwifi: mvm: add reorder buffer per queue")
Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.c

index a22fe45eecc48254db214bc5dd1c18f21d31bfc2..32e62175cbd50a3436fbbdad1d593da8cdd37d90 100644 (file)
@@ -626,6 +626,7 @@ struct iwl_mvm_shared_mem_cfg {
  * @reorder_timer: timer for frames are in the reorder buffer. For AMSDU
  *     it is the time of last received sub-frame
  * @removed: prevent timer re-arming
+ * @valid: reordering is valid for this queue
  * @lock: protect reorder buffer internal state
  * @mvm: mvm pointer, needed for frame timer context
  */
@@ -641,6 +642,7 @@ struct iwl_mvm_reorder_buffer {
        unsigned long reorder_time[IEEE80211_MAX_AMPDU_BUF];
        struct timer_list reorder_timer;
        bool removed;
+       bool valid;
        spinlock_t lock;
        struct iwl_mvm *mvm;
 } ____cacheline_aligned_in_smp;
index c99775039f5929d07f6f26416b176bcdb53142d1..8601d25407b3d0003392d6be3e9a8dc336f75688 100644 (file)
@@ -636,9 +636,13 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
                return false;
 
        baid_data = rcu_dereference(mvm->baid_map[baid]);
-       if (WARN(!baid_data,
-                "Received baid %d, but no data exists for this BAID\n", baid))
+       if (!baid_data) {
+               WARN(!(reorder & IWL_RX_MPDU_REORDER_BA_OLD_SN),
+                    "Received baid %d, but no data exists for this BAID\n",
+                    baid);
                return false;
+       }
+
        if (WARN(tid != baid_data->tid || mvm_sta->sta_id != baid_data->sta_id,
                 "baid 0x%x is mapped to sta:%d tid:%d, but was received for sta:%d tid:%d\n",
                 baid, baid_data->sta_id, baid_data->tid, mvm_sta->sta_id,
@@ -653,6 +657,14 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
 
        spin_lock_bh(&buffer->lock);
 
+       if (!buffer->valid) {
+               if (reorder & IWL_RX_MPDU_REORDER_BA_OLD_SN) {
+                       spin_unlock_bh(&buffer->lock);
+                       return false;
+               }
+               buffer->valid = true;
+       }
+
        if (ieee80211_is_back_req(hdr->frame_control)) {
                iwl_mvm_release_frames(mvm, sta, napi, buffer, nssn);
                goto drop;
@@ -737,7 +749,8 @@ drop:
        return true;
 }
 
-static void iwl_mvm_agg_rx_received(struct iwl_mvm *mvm, u8 baid)
+static void iwl_mvm_agg_rx_received(struct iwl_mvm *mvm,
+                                   u32 reorder_data, u8 baid)
 {
        unsigned long now = jiffies;
        unsigned long timeout;
@@ -746,8 +759,10 @@ static void iwl_mvm_agg_rx_received(struct iwl_mvm *mvm, u8 baid)
        rcu_read_lock();
 
        data = rcu_dereference(mvm->baid_map[baid]);
-       if (WARN_ON(!data))
+       if (!data) {
+               WARN_ON(!(reorder_data & IWL_RX_MPDU_REORDER_BA_OLD_SN));
                goto out;
+       }
 
        if (!data->timeout)
                goto out;
@@ -925,8 +940,11 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
                                mac_addr[i] = hdr->addr3[ETH_ALEN - i - 1];
                        ether_addr_copy(hdr->addr3, mac_addr);
                }
-               if (baid != IWL_RX_REORDER_DATA_INVALID_BAID)
-                       iwl_mvm_agg_rx_received(mvm, baid);
+               if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) {
+                       u32 reorder_data = le32_to_cpu(desc->reorder_data);
+
+                       iwl_mvm_agg_rx_received(mvm, reorder_data, baid);
+               }
        }
 
        /* Set up the HT phy flags */
index ea35fcbd3b2660b003c62cf82024d68418f0b360..cc9c92b8e2ba2111dddca6345cd2212409514814 100644 (file)
@@ -2231,6 +2231,7 @@ static void iwl_mvm_init_reorder_buffer(struct iwl_mvm *mvm,
                reorder_buf->mvm = mvm;
                reorder_buf->queue = i;
                reorder_buf->sta_id = sta_id;
+               reorder_buf->valid = false;
                for (j = 0; j < reorder_buf->buf_size; j++)
                        __skb_queue_head_init(&reorder_buf->entries[j]);
        }