Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 172228
b: refs/heads/master
c: 2569a82
h: refs/heads/master
v: v3
  • Loading branch information
Johannes Berg authored and John W. Linville committed Nov 28, 2009
1 parent 48594ac commit 1c0ce82
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 74 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 1edfb1afba2f6e4114ff09f2e3bc948fcae0c419
refs/heads/master: 2569a826de16ff82302a8a091228275be1aa911c
1 change: 1 addition & 0 deletions trunk/net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
#define IEEE80211_RX_RA_MATCH BIT(1)
#define IEEE80211_RX_AMSDU BIT(2)
#define IEEE80211_RX_FRAGMENTED BIT(3)
/* only add flags here that do not change with subframes of an aMPDU */

struct ieee80211_rx_data {
struct sk_buff *skb;
Expand Down
168 changes: 95 additions & 73 deletions trunk/net/mac80211/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@
#include "tkip.h"
#include "wme.h"

static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
struct sk_buff *skb,
struct ieee80211_rate *rate);

/*
* monitor mode reception
*
Expand Down Expand Up @@ -555,7 +551,8 @@ static inline u16 seq_sub(u16 sq1, u16 sq2)

static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx,
int index)
int index,
struct sk_buff_head *frames)
{
struct ieee80211_supported_band *sband;
struct ieee80211_rate *rate = NULL;
Expand All @@ -571,24 +568,25 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
sband = hw->wiphy->bands[status->band];
if (!(status->flag & RX_FLAG_HT))
rate = &sband->bitrates[status->rate_idx];
__ieee80211_rx_handle_packet(hw, skb, rate);
tid_agg_rx->stored_mpdu_num--;
tid_agg_rx->reorder_buf[index] = NULL;
skb_queue_tail(frames, skb);

no_frame:
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)
u16 head_seq_num,
struct sk_buff_head *frames)
{
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);
ieee80211_release_reorder_frame(hw, tid_agg_rx, index, frames);
}
}

Expand All @@ -608,7 +606,8 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
*/
static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx,
struct sk_buff *skb)
struct sk_buff *skb,
struct sk_buff_head *frames)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u16 sc = le16_to_cpu(hdr->seq_ctrl);
Expand All @@ -632,7 +631,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) {
head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size));
/* release stored frames up to new head to stack */
ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num);
ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num,
frames);
}

/* Now the new frame is always in the range of the reordering buffer */
Expand Down Expand Up @@ -687,7 +687,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
"frames\n",
wiphy_name(hw->wiphy));
#endif
ieee80211_release_reorder_frame(hw, tid_agg_rx, j);
ieee80211_release_reorder_frame(hw, tid_agg_rx,
j, frames);

/*
* Increment the head seq# also for the skipped slots.
Expand All @@ -697,7 +698,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
skipped = 0;
}
} 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, frames);
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
tid_agg_rx->buf_size;
}
Expand All @@ -709,38 +710,39 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
* 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)
static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
struct sk_buff_head *frames)
{
struct sk_buff *skb = rx->skb;
struct ieee80211_local *local = rx->local;
struct ieee80211_hw *hw = &local->hw;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct sta_info *sta;
struct sta_info *sta = rx->sta;
struct tid_ampdu_rx *tid_agg_rx;
u16 sc;
int tid;

if (!ieee80211_is_data_qos(hdr->frame_control))
return false;
goto dont_reorder;

/*
* 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);
if (!sta)
return false;
goto dont_reorder;

tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;

if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL)
return false;
goto dont_reorder;

tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];

/* qos null data frames are excluded */
if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
return false;
goto dont_reorder;

/* new, potentially un-ordered, ampdu frame - process it */

Expand All @@ -755,10 +757,14 @@ static bool ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
dev_kfree_skb(skb);
return true;
return;
}

return ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb);
if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames))
return;

dont_reorder:
__skb_queue_tail(frames, skb);
}

static ieee80211_rx_result debug_noinline
Expand Down Expand Up @@ -863,6 +869,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
return RX_CONTINUE;

/* start without a key */
rx->key = NULL;

if (rx->sta)
stakey = rcu_dereference(rx->sta->key);

Expand Down Expand Up @@ -1815,7 +1824,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
}

static ieee80211_rx_result debug_noinline
ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
{
struct ieee80211_local *local = rx->local;
struct ieee80211_hw *hw = &local->hw;
Expand Down Expand Up @@ -1845,7 +1854,8 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
TU_TO_EXP_TIME(tid_agg_rx->timeout));

/* release stored frames up to start of BAR */
ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num);
ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num,
frames);
kfree_skb(skb);
return RX_QUEUED;
}
Expand Down Expand Up @@ -2168,59 +2178,84 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb,
struct ieee80211_rate *rate)
{
struct sk_buff_head reorder_release;
ieee80211_rx_result res = RX_DROP_MONITOR;

__skb_queue_head_init(&reorder_release);

rx->skb = skb;
rx->sdata = sdata;

#define CALL_RXH(rxh) \
do { \
res = rxh(rx); \
if (res != RX_CONTINUE) \
goto rxh_done; \
goto rxh_next; \
} while (0);

/*
* NB: the rxh_next label works even if we jump
* to it from here because then the list will
* be empty, which is a trivial check
*/
CALL_RXH(ieee80211_rx_h_passive_scan)
CALL_RXH(ieee80211_rx_h_check)
CALL_RXH(ieee80211_rx_h_decrypt)
CALL_RXH(ieee80211_rx_h_check_more_data)
CALL_RXH(ieee80211_rx_h_sta_process)
CALL_RXH(ieee80211_rx_h_defragment)
CALL_RXH(ieee80211_rx_h_ps_poll)
CALL_RXH(ieee80211_rx_h_michael_mic_verify)
/* must be after MMIC verify so header is counted in MPDU mic */
CALL_RXH(ieee80211_rx_h_remove_qos_control)
CALL_RXH(ieee80211_rx_h_amsdu)

ieee80211_rx_reorder_ampdu(rx, &reorder_release);

while ((skb = __skb_dequeue(&reorder_release))) {
/*
* all the other fields are valid across frames
* that belong to an aMPDU since they are on the
* same TID from the same station
*/
rx->skb = skb;

CALL_RXH(ieee80211_rx_h_decrypt)
CALL_RXH(ieee80211_rx_h_check_more_data)
CALL_RXH(ieee80211_rx_h_sta_process)
CALL_RXH(ieee80211_rx_h_defragment)
CALL_RXH(ieee80211_rx_h_ps_poll)
CALL_RXH(ieee80211_rx_h_michael_mic_verify)
/* must be after MMIC verify so header is counted in MPDU mic */
CALL_RXH(ieee80211_rx_h_remove_qos_control)
CALL_RXH(ieee80211_rx_h_amsdu)
#ifdef CONFIG_MAC80211_MESH
if (ieee80211_vif_is_mesh(&sdata->vif))
CALL_RXH(ieee80211_rx_h_mesh_fwding);
if (ieee80211_vif_is_mesh(&sdata->vif))
CALL_RXH(ieee80211_rx_h_mesh_fwding);
#endif
CALL_RXH(ieee80211_rx_h_data)
CALL_RXH(ieee80211_rx_h_ctrl)
CALL_RXH(ieee80211_rx_h_action)
CALL_RXH(ieee80211_rx_h_mgmt)
CALL_RXH(ieee80211_rx_h_data)

/* special treatment -- needs the queue */
res = ieee80211_rx_h_ctrl(rx, &reorder_release);
if (res != RX_CONTINUE)
goto rxh_next;

CALL_RXH(ieee80211_rx_h_action)
CALL_RXH(ieee80211_rx_h_mgmt)

#undef CALL_RXH

rxh_done:
switch (res) {
case RX_DROP_MONITOR:
I802_DEBUG_INC(sdata->local->rx_handlers_drop);
if (rx->sta)
rx->sta->rx_dropped++;
/* fall through */
case RX_CONTINUE:
ieee80211_rx_cooked_monitor(rx, rate);
break;
case RX_DROP_UNUSABLE:
I802_DEBUG_INC(sdata->local->rx_handlers_drop);
if (rx->sta)
rx->sta->rx_dropped++;
dev_kfree_skb(rx->skb);
break;
case RX_QUEUED:
I802_DEBUG_INC(sdata->local->rx_handlers_queued);
break;
rxh_next:
switch (res) {
case RX_DROP_MONITOR:
I802_DEBUG_INC(sdata->local->rx_handlers_drop);
if (rx->sta)
rx->sta->rx_dropped++;
/* fall through */
case RX_CONTINUE:
ieee80211_rx_cooked_monitor(rx, rate);
break;
case RX_DROP_UNUSABLE:
I802_DEBUG_INC(sdata->local->rx_handlers_drop);
if (rx->sta)
rx->sta->rx_dropped++;
dev_kfree_skb(rx->skb);
break;
case RX_QUEUED:
I802_DEBUG_INC(sdata->local->rx_handlers_queued);
break;
}
}
}

Expand Down Expand Up @@ -2494,20 +2529,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
return;
}

/*
* In theory, the block ack reordering should happen after duplicate
* removal (ieee80211_rx_h_check(), which is an RX handler). As such,
* the call to ieee80211_rx_reorder_ampdu() should really be moved to
* happen as a new RX handler between ieee80211_rx_h_check and
* ieee80211_rx_h_decrypt. This cleanup may eventually happen, but for
* the time being, the call can be here since RX reorder buf processing
* will implicitly skip duplicates. We could, in theory at least,
* process frames that ieee80211_rx_h_passive_scan would drop (e.g.,
* frames from other than operational channel), but that should not
* happen in normal networks.
*/
if (!ieee80211_rx_reorder_ampdu(local, skb))
__ieee80211_rx_handle_packet(hw, skb, rate);
__ieee80211_rx_handle_packet(hw, skb, rate);

rcu_read_unlock();

Expand Down

0 comments on commit 1c0ce82

Please sign in to comment.