Commit a02ae758 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

mac80211: cleanup reorder buffer handling

The reorder buffer handling is written in a quite
peculiar style (especially comments) and also has
a quirk where it invokes the entire reorder code
in ieee80211_sta_manage_reorder_buf() for just a
handful of lines in it with a special argument.

Split out ieee80211_release_reorder_frames which
can then be invoked from BAR handling and other
reordering code, clean up code and comments and
remove function arguments that are now unused from
ieee80211_sta_manage_reorder_buf().
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent af2ced6a
...@@ -27,11 +27,10 @@ ...@@ -27,11 +27,10 @@
#include "tkip.h" #include "tkip.h"
#include "wme.h" #include "wme.h"
static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx, struct tid_ampdu_rx *tid_agg_rx,
struct sk_buff *skb, u16 head_seq_num);
u16 mpdu_seq_num,
int bar_req);
/* /*
* monitor mode reception * monitor mode reception
* *
...@@ -1592,11 +1591,11 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) ...@@ -1592,11 +1591,11 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
if (ieee80211_is_back_req(bar->frame_control)) { if (ieee80211_is_back_req(bar->frame_control)) {
if (!rx->sta) if (!rx->sta)
return RX_CONTINUE; return RX_DROP_MONITOR;
tid = le16_to_cpu(bar->control) >> 12; tid = le16_to_cpu(bar->control) >> 12;
if (rx->sta->ampdu_mlme.tid_state_rx[tid] if (rx->sta->ampdu_mlme.tid_state_rx[tid]
!= HT_AGG_STATE_OPERATIONAL) != HT_AGG_STATE_OPERATIONAL)
return RX_CONTINUE; return RX_DROP_MONITOR;
tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid]; tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid];
start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4; start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
...@@ -1606,13 +1605,10 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) ...@@ -1606,13 +1605,10 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
mod_timer(&tid_agg_rx->session_timer, mod_timer(&tid_agg_rx->session_timer,
TU_TO_EXP_TIME(tid_agg_rx->timeout)); TU_TO_EXP_TIME(tid_agg_rx->timeout));
/* manage reordering buffer according to requested */ /* release stored frames up to start of BAR */
/* sequence number */ ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num);
rcu_read_lock(); kfree_skb(skb);
ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, return RX_QUEUED;
start_seq_num, 1);
rcu_read_unlock();
return RX_DROP_UNUSABLE;
} }
return RX_CONTINUE; return RX_CONTINUE;
...@@ -2223,6 +2219,18 @@ no_frame: ...@@ -2223,6 +2219,18 @@ no_frame:
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
} }
static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx,
u16 head_seq_num)
{
int index;
while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
tid_agg_rx->buf_size;
ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
}
}
/* /*
* Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If * Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If
...@@ -2234,15 +2242,17 @@ no_frame: ...@@ -2234,15 +2242,17 @@ no_frame:
#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
/* /*
* As it function blongs to Rx path it must be called with * As this function belongs to the RX path it must be under
* the proper rcu_read_lock protection for its flow. * rcu_read_lock protection. It returns false if the frame
* can be processed immediately, true if it was consumed.
*/ */
static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx, struct tid_ampdu_rx *tid_agg_rx,
struct sk_buff *skb, struct sk_buff *skb)
u16 mpdu_seq_num,
int bar_req)
{ {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u16 sc = le16_to_cpu(hdr->seq_ctrl);
u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
u16 head_seq_num, buf_size; u16 head_seq_num, buf_size;
int index; int index;
...@@ -2252,47 +2262,37 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, ...@@ -2252,47 +2262,37 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
/* frame with out of date sequence number */ /* frame with out of date sequence number */
if (seq_less(mpdu_seq_num, head_seq_num)) { if (seq_less(mpdu_seq_num, head_seq_num)) {
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 1; return true;
} }
/* if frame sequence number exceeds our buffering window size or /*
* block Ack Request arrived - release stored frames */ * If frame the sequence number exceeds our buffering window
if ((!seq_less(mpdu_seq_num, head_seq_num + buf_size)) || (bar_req)) { * size release some previous frames to make room for this one.
/* new head to the ordering buffer */ */
if (bar_req) if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) {
head_seq_num = mpdu_seq_num; head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size));
else
head_seq_num =
seq_inc(seq_sub(mpdu_seq_num, buf_size));
/* release stored frames up to new head to stack */ /* release stored frames up to new head to stack */
while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num);
index = seq_sub(tid_agg_rx->head_seq_num,
tid_agg_rx->ssn)
% tid_agg_rx->buf_size;
ieee80211_release_reorder_frame(hw, tid_agg_rx,
index);
}
if (bar_req)
return 1;
} }
/* now the new frame is always in the range of the reordering */ /* Now the new frame is always in the range of the reordering buffer */
/* buffer window */
index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size;
% tid_agg_rx->buf_size;
/* check if we already stored this frame */ /* check if we already stored this frame */
if (tid_agg_rx->reorder_buf[index]) { if (tid_agg_rx->reorder_buf[index]) {
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 1; return true;
} }
/* if arrived mpdu is in the right order and nothing else stored */ /*
/* release it immediately */ * If the current MPDU is in the right order and nothing else
* is stored we can process it directly, no need to buffer it.
*/
if (mpdu_seq_num == tid_agg_rx->head_seq_num && if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
tid_agg_rx->stored_mpdu_num == 0) { tid_agg_rx->stored_mpdu_num == 0) {
tid_agg_rx->head_seq_num = tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
seq_inc(tid_agg_rx->head_seq_num); return false;
return 0;
} }
/* put the frame in the reordering buffer */ /* put the frame in the reordering buffer */
...@@ -2300,8 +2300,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, ...@@ -2300,8 +2300,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
tid_agg_rx->reorder_time[index] = jiffies; tid_agg_rx->reorder_time[index] = jiffies;
tid_agg_rx->stored_mpdu_num++; tid_agg_rx->stored_mpdu_num++;
/* release the buffer until next missing frame */ /* release the buffer until next missing frame */
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
% tid_agg_rx->buf_size; tid_agg_rx->buf_size;
if (!tid_agg_rx->reorder_buf[index] && if (!tid_agg_rx->reorder_buf[index] &&
tid_agg_rx->stored_mpdu_num > 1) { tid_agg_rx->stored_mpdu_num > 1) {
/* /*
...@@ -2312,12 +2312,12 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, ...@@ -2312,12 +2312,12 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
int skipped = 1; int skipped = 1;
for (j = (index + 1) % tid_agg_rx->buf_size; j != index; for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
j = (j + 1) % tid_agg_rx->buf_size) { j = (j + 1) % tid_agg_rx->buf_size) {
if (tid_agg_rx->reorder_buf[j] == NULL) { if (!tid_agg_rx->reorder_buf[j]) {
skipped++; skipped++;
continue; continue;
} }
if (!time_after(jiffies, tid_agg_rx->reorder_time[j] + if (!time_after(jiffies, tid_agg_rx->reorder_time[j] +
HZ / 10)) HT_RX_REORDER_BUF_TIMEOUT))
break; break;
#ifdef CONFIG_MAC80211_HT_DEBUG #ifdef CONFIG_MAC80211_HT_DEBUG
...@@ -2333,19 +2333,23 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, ...@@ -2333,19 +2333,23 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
* Increment the head seq# also for the skipped slots. * Increment the head seq# also for the skipped slots.
*/ */
tid_agg_rx->head_seq_num = tid_agg_rx->head_seq_num =
(tid_agg_rx->head_seq_num + skipped) & (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK;
SEQ_MASK;
skipped = 0; skipped = 0;
} }
} else while (tid_agg_rx->reorder_buf[index]) { } else while (tid_agg_rx->reorder_buf[index]) {
ieee80211_release_reorder_frame(hw, tid_agg_rx, index); ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
index = seq_sub(tid_agg_rx->head_seq_num, index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
tid_agg_rx->ssn) % tid_agg_rx->buf_size; tid_agg_rx->buf_size;
} }
return 1;
return true;
} }
static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, /*
* Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns
* true if the MPDU was buffered, false if it should be processed.
*/
static bool ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct ieee80211_hw *hw = &local->hw; struct ieee80211_hw *hw = &local->hw;
...@@ -2353,31 +2357,32 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, ...@@ -2353,31 +2357,32 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
struct sta_info *sta; struct sta_info *sta;
struct tid_ampdu_rx *tid_agg_rx; struct tid_ampdu_rx *tid_agg_rx;
u16 sc; u16 sc;
u16 mpdu_seq_num;
u8 ret = 0;
int tid; int tid;
if (!ieee80211_is_data_qos(hdr->frame_control))
return false;
/*
* filter the QoS data rx stream according to
* STA/TID and check if this STA/TID is on aggregation
*/
sta = sta_info_get(local, hdr->addr2); sta = sta_info_get(local, hdr->addr2);
if (!sta) if (!sta)
return ret; return false;
/* filter the QoS data rx stream according to
* STA/TID and check if this STA/TID is on aggregation */
if (!ieee80211_is_data_qos(hdr->frame_control))
goto end_reorder;
tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL)
goto end_reorder; return false;
tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
/* qos null data frames are excluded */ /* qos null data frames are excluded */
if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
goto end_reorder; return false;
/* new un-ordered ampdu frame - process it */ /* new, potentially un-ordered, ampdu frame - process it */
/* reset session timer */ /* reset session timer */
if (tid_agg_rx->timeout) if (tid_agg_rx->timeout)
...@@ -2389,16 +2394,11 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, ...@@ -2389,16 +2394,11 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
if (sc & IEEE80211_SCTL_FRAG) { if (sc & IEEE80211_SCTL_FRAG) {
ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr, ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
ret = 1; dev_kfree_skb(skb);
goto end_reorder; return true;
} }
/* according to mpdu sequence number deal with reordering buffer */ return ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb);
mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb,
mpdu_seq_num, 0);
end_reorder:
return ret;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment