Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 213987
b: refs/heads/master
c: 2bff8eb
h: refs/heads/master
i:
  213985: 32ad070
  213983: 3e67985
v: v3
  • Loading branch information
Christian Lamparter authored and John W. Linville committed Aug 16, 2010
1 parent cb47aba commit 5c87a50
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 13 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: 071d9ac253ff51154beb7e33967168e30bc96053
refs/heads/master: 2bff8ebf32a7c5ec9e5f5eeffef94a8cb622f5f0
22 changes: 22 additions & 0 deletions trunk/net/mac80211/agg-rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
tid, 0, reason);

del_timer_sync(&tid_rx->session_timer);
del_timer_sync(&tid_rx->reorder_timer);

call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx);
}
Expand Down Expand Up @@ -120,6 +121,20 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
}

static void sta_rx_agg_reorder_timer_expired(unsigned long data)
{
u8 *ptid = (u8 *)data;
u8 *timer_to_id = ptid - *ptid;
struct sta_info *sta = container_of(timer_to_id, struct sta_info,
timer_to_tid[0]);

rcu_read_lock();
spin_lock(&sta->lock);
ieee80211_release_reorder_timeout(sta, *ptid);
spin_unlock(&sta->lock);
rcu_read_unlock();
}

static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
u8 dialog_token, u16 status, u16 policy,
u16 buf_size, u16 timeout)
Expand Down Expand Up @@ -251,11 +266,18 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
goto end;
}

spin_lock_init(&tid_agg_rx->reorder_lock);

/* rx timer */
tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired;
tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
init_timer(&tid_agg_rx->session_timer);

/* rx reorder timer */
tid_agg_rx->reorder_timer.function = sta_rx_agg_reorder_timer_expired;
tid_agg_rx->reorder_timer.data = (unsigned long)&sta->timer_to_tid[tid];
init_timer(&tid_agg_rx->reorder_timer);

/* prepare reordering buffer */
tid_agg_rx->reorder_buf =
kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC);
Expand Down
1 change: 1 addition & 0 deletions trunk/net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid);
void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
void ieee80211_ba_session_work(struct work_struct *work);
void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid);
void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid);

/* Spectrum management */
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
Expand Down
70 changes: 63 additions & 7 deletions trunk/net/mac80211/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -572,14 +572,16 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
* frames that have not yet been received are assumed to be lost and the skb
* can be released for processing. This may also release other skb's from the
* reorder buffer if there are no additional gaps between the frames.
*
* Callers must hold tid_agg_rx->reorder_lock.
*/
#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)

static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
struct tid_ampdu_rx *tid_agg_rx,
struct sk_buff_head *frames)
{
int index;
int index, j;

/* release the buffer until next missing frame */
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
Expand All @@ -590,7 +592,6 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
* No buffers ready to be released, but check whether any
* frames in the reorder buffer have timed out.
*/
int j;
int skipped = 1;
for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
j = (j + 1) % tid_agg_rx->buf_size) {
Expand All @@ -600,7 +601,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
}
if (!time_after(jiffies, tid_agg_rx->reorder_time[j] +
HT_RX_REORDER_BUF_TIMEOUT))
break;
goto set_release_timer;

#ifdef CONFIG_MAC80211_HT_DEBUG
if (net_ratelimit())
Expand All @@ -624,6 +625,25 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
tid_agg_rx->buf_size;
}

if (tid_agg_rx->stored_mpdu_num) {
j = index = seq_sub(tid_agg_rx->head_seq_num,
tid_agg_rx->ssn) % tid_agg_rx->buf_size;

for (; j != (index - 1) % tid_agg_rx->buf_size;
j = (j + 1) % tid_agg_rx->buf_size) {
if (tid_agg_rx->reorder_buf[j])
break;
}

set_release_timer:

mod_timer(&tid_agg_rx->reorder_timer,
tid_agg_rx->reorder_time[j] +
HT_RX_REORDER_BUF_TIMEOUT);
} else {
del_timer(&tid_agg_rx->reorder_timer);
}
}

/*
Expand All @@ -641,14 +661,16 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
u16 head_seq_num, buf_size;
int index;
bool ret = true;

buf_size = tid_agg_rx->buf_size;
head_seq_num = tid_agg_rx->head_seq_num;

spin_lock(&tid_agg_rx->reorder_lock);
/* frame with out of date sequence number */
if (seq_less(mpdu_seq_num, head_seq_num)) {
dev_kfree_skb(skb);
return true;
goto out;
}

/*
Expand All @@ -669,7 +691,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
/* check if we already stored this frame */
if (tid_agg_rx->reorder_buf[index]) {
dev_kfree_skb(skb);
return true;
goto out;
}

/*
Expand All @@ -679,7 +701,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
tid_agg_rx->stored_mpdu_num == 0) {
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
return false;
ret = false;
goto out;
}

/* put the frame in the reordering buffer */
Expand All @@ -688,7 +711,9 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
tid_agg_rx->stored_mpdu_num++;
ieee80211_sta_reorder_release(hw, tid_agg_rx, frames);

return true;
out:
spin_unlock(&tid_agg_rx->reorder_lock);
return ret;
}

/*
Expand Down Expand Up @@ -2387,6 +2412,37 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
#undef CALL_RXH
}

/*
* This function makes calls into the RX path. Therefore the
* caller must hold the sta_info->lock and everything has to
* be under rcu_read_lock protection as well.
*/
void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
{
struct sk_buff_head frames;
struct ieee80211_rx_data rx = { };

__skb_queue_head_init(&frames);

/* construct rx struct */
rx.sta = sta;
rx.sdata = sta->sdata;
rx.local = sta->local;
rx.queue = tid;
rx.flags |= IEEE80211_RX_RA_MATCH;

if (unlikely(test_bit(SCAN_HW_SCANNING, &sta->local->scanning) ||
test_bit(SCAN_OFF_CHANNEL, &sta->local->scanning)))
rx.flags |= IEEE80211_RX_IN_SCAN;

spin_lock(&sta->ampdu_mlme.tid_rx[tid]->reorder_lock);
ieee80211_sta_reorder_release(&sta->local->hw,
sta->ampdu_mlme.tid_rx[tid], &frames);
spin_unlock(&sta->ampdu_mlme.tid_rx[tid]->reorder_lock);

ieee80211_rx_handlers(&rx, &frames);
}

/* main receive path */

static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
Expand Down
16 changes: 11 additions & 5 deletions trunk/net/mac80211/sta_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,27 +103,33 @@ struct tid_ampdu_tx {
* @reorder_buf: buffer to reorder incoming aggregated MPDUs
* @reorder_time: jiffies when skb was added
* @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
* @reorder_timer: releases expired frames from the reorder buffer.
* @head_seq_num: head sequence number in reordering buffer.
* @stored_mpdu_num: number of MPDUs in reordering buffer
* @ssn: Starting Sequence Number expected to be aggregated.
* @buf_size: buffer size for incoming A-MPDUs
* @timeout: reset timer value (in TUs).
* @dialog_token: dialog token for aggregation session
* @rcu_head: RCU head used for freeing this struct
* @reorder_lock: serializes access to reorder buffer, see below.
*
* This structure is protected by RCU and the per-station
* spinlock. Assignments to the array holding it must hold
* the spinlock, only the RX path can access it under RCU
* lock-free. The RX path, since it is single-threaded,
* can even modify the structure without locking since the
* only other modifications to it are done when the struct
* can not yet or no longer be found by the RX path.
* the spinlock.
*
* The @reorder_lock is used to protect the variables and
* arrays such as @reorder_buf, @reorder_time, @head_seq_num,
* @stored_mpdu_num and @reorder_time from being corrupted by
* concurrent access of the RX path and the expired frame
* release timer.
*/
struct tid_ampdu_rx {
struct rcu_head rcu_head;
spinlock_t reorder_lock;
struct sk_buff **reorder_buf;
unsigned long *reorder_time;
struct timer_list session_timer;
struct timer_list reorder_timer;
u16 head_seq_num;
u16 stored_mpdu_num;
u16 ssn;
Expand Down

0 comments on commit 5c87a50

Please sign in to comment.