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: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
af2ced6a32
commit
a02ae758e8
|
@ -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)
|
||||||
|
|
||||||
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)
|
||||||
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:
|
||||||
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:
|
||||||
#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,
|
||||||
/* 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,
|
||||||
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,
|
||||||
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,51 +2333,56 @@ 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,
|
/*
|
||||||
struct sk_buff *skb)
|
* 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 ieee80211_hw *hw = &local->hw;
|
struct ieee80211_hw *hw = &local->hw;
|
||||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||||
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,
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue