From 8acbea614a75bc2221a84f222dc32be0877861ce Mon Sep 17 00:00:00 2001 From: Paul Stewart Date: Tue, 25 Feb 2014 16:31:37 -0800 Subject: mwifiex: Track BA sequence number reset Some stations reset the sequence number for traffic-ids (TIDs) as they initiate a block-ACK session. In order to detect such behavior, mwifiex must note the starting sequence number given during the ADDBA request. If the first received sequence number after the ADDBA falls outside the receive window for this TID but after the the ADDBA starting sequence number, we can assume that this AP has reset its sequence number during the ADDBA. In this case we must adjust the input window backward to incorporate this received sequence number instead of ignoring it. Otherwise, we could fail to successfully retrieve an arbitrarily large number of downstream frames at the beginning of the block-ACK session. Signed-off-by: Paul Stewart Acked-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11n_rxreorder.c | 27 +++++++++++++++++++++------ drivers/net/wireless/mwifiex/11n_rxreorder.h | 3 ++- drivers/net/wireless/mwifiex/main.h | 1 + 3 files changed, 24 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless/mwifiex') diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index eb17282b364f..35329cfc9a9b 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -279,6 +279,8 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, new_node->tid = tid; memcpy(new_node->ta, ta, ETH_ALEN); new_node->start_win = seq_num; + new_node->init_win = seq_num; + new_node->flags = 0; if (mwifiex_queuing_ra_based(priv)) { dev_dbg(priv->adapter->dev, @@ -298,11 +300,12 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, } if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM && - last_seq >= new_node->start_win) + last_seq >= new_node->start_win) { new_node->start_win = last_seq + 1; + new_node->flags |= RXREOR_INIT_WINDOW_SHIFT; + } new_node->win_size = win_size; - new_node->flags = 0; new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size, GFP_KERNEL); @@ -452,6 +455,7 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, struct mwifiex_rx_reorder_tbl *tbl; int start_win, end_win, win_size; u16 pkt_index; + bool init_window_shift = false; tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta); if (!tbl) { @@ -466,18 +470,29 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv, start_win = tbl->start_win; win_size = tbl->win_size; end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1); + if (tbl->flags & RXREOR_INIT_WINDOW_SHIFT) { + init_window_shift = true; + tbl->flags &= ~RXREOR_INIT_WINDOW_SHIFT; + } mod_timer(&tbl->timer_context.timer, jiffies + msecs_to_jiffies(MIN_FLUSH_TIMER_MS * win_size)); - /* - * If seq_num is less then starting win then ignore and drop the - * packet - */ if (tbl->flags & RXREOR_FORCE_NO_DROP) { dev_dbg(priv->adapter->dev, "RXREOR_FORCE_NO_DROP when HS is activated\n"); tbl->flags &= ~RXREOR_FORCE_NO_DROP; + } else if (init_window_shift && seq_num < start_win && + seq_num >= tbl->init_win) { + dev_dbg(priv->adapter->dev, + "Sender TID sequence number reset %d->%d for SSN %d\n", + start_win, seq_num, tbl->init_win); + tbl->start_win = start_win = seq_num; + end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1); } else { + /* + * If seq_num is less then starting win then ignore and drop + * the packet + */ if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) { if (seq_num >= ((start_win + TWOPOW11) & (MAX_TID_VALUE - 1)) && diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h index 4064041ac852..0fc76e4a60f8 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.h +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h @@ -42,7 +42,8 @@ #define BA_SETUP_PACKET_OFFSET 16 enum mwifiex_rxreor_flags { - RXREOR_FORCE_NO_DROP = 1<<0, + RXREOR_FORCE_NO_DROP = 1<<0, + RXREOR_INIT_WINDOW_SHIFT = 1<<1, }; static inline void mwifiex_reset_11n_rx_seq_num(struct mwifiex_private *priv) diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 407f8eada720..cb1148f0de69 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -575,6 +575,7 @@ struct mwifiex_rx_reorder_tbl { struct list_head list; int tid; u8 ta[ETH_ALEN]; + int init_win; int start_win; int win_size; void **rx_reorder_ptr; -- cgit v1.2.3-59-g8ed1b