summaryrefslogtreecommitdiff
path: root/net/mac80211/agg-tx.c
diff options
context:
space:
mode:
authorNikolay Martynov <mar.kolya@gmail.com>2011-11-23 06:50:28 +0400
committerJohn W. Linville <linville@tuxdriver.com>2011-11-28 23:43:49 +0400
commit285fa6958c1d56469ec8a0e879ae7487a4e62840 (patch)
treec0c335499809c2b90ef145576e726543c508e67c /net/mac80211/agg-tx.c
parent94c2fb82bd7c9055bec8e410c387befce33d1299 (diff)
downloadlinux-285fa6958c1d56469ec8a0e879ae7487a4e62840.tar.xz
mac80211: timeout tx agg sessions in way similar to rx agg sessions
Currently tx aggregation is not being timed out even if timeout is specified when aggregation is opened. Tx tid stays active until delba arrives from recipient (i.e. recipient times out tid when it is inactive). The problem with this approach is that delba can get lost in the air and tx tid will stay perpetually opened on the originator while closed on recipient thus all data sent via this tid will be lost. This patch implements tx tid timeouting in way very similar to rx tid timeouting. Signed-off-by: Nikolay Martynov <mar.kolya@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/agg-tx.c')
-rw-r--r--net/mac80211/agg-tx.c35
1 files changed, 34 insertions, 1 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 39d72ccaffb3..a2d9654aabcb 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -180,6 +180,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
del_timer_sync(&tid_tx->addba_resp_timer);
+ del_timer_sync(&tid_tx->session_timer);
/*
* After this packets are no longer handed right through
@@ -349,6 +350,28 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
tid_tx->timeout);
}
+/*
+ * After accepting the AddBA Response we activated a timer,
+ * resetting it after each frame that we send.
+ */
+static void sta_tx_agg_session_timer_expired(unsigned long data)
+{
+ /* not an elegant detour, but there is no choice as the timer passes
+ * only one argument, and various sta_info are needed here, so init
+ * flow in sta_info_create gives the TID as data, while the timer_to_id
+ * array gives the sta through container_of */
+ 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]);
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+ printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid);
+#endif
+
+ ieee80211_stop_tx_ba_session(&sta->sta, *ptid);
+}
+
int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
u16 timeout)
{
@@ -418,11 +441,16 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
tid_tx->timeout = timeout;
- /* Tx timer */
+ /* response timer */
tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired;
tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid];
init_timer(&tid_tx->addba_resp_timer);
+ /* tx timer */
+ tid_tx->session_timer.function = sta_tx_agg_session_timer_expired;
+ tid_tx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
+ init_timer(&tid_tx->session_timer);
+
/* assign a dialog token */
sta->ampdu_mlme.dialog_token_allocator++;
tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator;
@@ -778,6 +806,11 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
ieee80211_agg_tx_operational(local, sta, tid);
sta->ampdu_mlme.addba_req_num[tid] = 0;
+
+ if (tid_tx->timeout)
+ mod_timer(&tid_tx->session_timer,
+ TU_TO_EXP_TIME(tid_tx->timeout));
+
} else {
___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR,
true);