aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorNikolay Martynov <mar.kolya@gmail.com>2011-11-22 21:50:28 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-11-28 14:43:49 -0500
commit285fa6958c1d56469ec8a0e879ae7487a4e62840 (patch)
treec0c335499809c2b90ef145576e726543c508e67c /net/mac80211
parent94c2fb82bd7c9055bec8e410c387befce33d1299 (diff)
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')
-rw-r--r--net/mac80211/agg-tx.c35
-rw-r--r--net/mac80211/sta_info.h2
-rw-r--r--net/mac80211/tx.c8
3 files changed, 44 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,
180 set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); 180 set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
181 181
182 del_timer_sync(&tid_tx->addba_resp_timer); 182 del_timer_sync(&tid_tx->addba_resp_timer);
183 del_timer_sync(&tid_tx->session_timer);
183 184
184 /* 185 /*
185 * After this packets are no longer handed right through 186 * 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)
349 tid_tx->timeout); 350 tid_tx->timeout);
350} 351}
351 352
353/*
354 * After accepting the AddBA Response we activated a timer,
355 * resetting it after each frame that we send.
356 */
357static void sta_tx_agg_session_timer_expired(unsigned long data)
358{
359 /* not an elegant detour, but there is no choice as the timer passes
360 * only one argument, and various sta_info are needed here, so init
361 * flow in sta_info_create gives the TID as data, while the timer_to_id
362 * array gives the sta through container_of */
363 u8 *ptid = (u8 *)data;
364 u8 *timer_to_id = ptid - *ptid;
365 struct sta_info *sta = container_of(timer_to_id, struct sta_info,
366 timer_to_tid[0]);
367
368#ifdef CONFIG_MAC80211_HT_DEBUG
369 printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid);
370#endif
371
372 ieee80211_stop_tx_ba_session(&sta->sta, *ptid);
373}
374
352int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, 375int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
353 u16 timeout) 376 u16 timeout)
354{ 377{
@@ -418,11 +441,16 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
418 441
419 tid_tx->timeout = timeout; 442 tid_tx->timeout = timeout;
420 443
421 /* Tx timer */ 444 /* response timer */
422 tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired; 445 tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired;
423 tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid]; 446 tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid];
424 init_timer(&tid_tx->addba_resp_timer); 447 init_timer(&tid_tx->addba_resp_timer);
425 448
449 /* tx timer */
450 tid_tx->session_timer.function = sta_tx_agg_session_timer_expired;
451 tid_tx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
452 init_timer(&tid_tx->session_timer);
453
426 /* assign a dialog token */ 454 /* assign a dialog token */
427 sta->ampdu_mlme.dialog_token_allocator++; 455 sta->ampdu_mlme.dialog_token_allocator++;
428 tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator; 456 tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator;
@@ -778,6 +806,11 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
778 ieee80211_agg_tx_operational(local, sta, tid); 806 ieee80211_agg_tx_operational(local, sta, tid);
779 807
780 sta->ampdu_mlme.addba_req_num[tid] = 0; 808 sta->ampdu_mlme.addba_req_num[tid] = 0;
809
810 if (tid_tx->timeout)
811 mod_timer(&tid_tx->session_timer,
812 TU_TO_EXP_TIME(tid_tx->timeout));
813
781 } else { 814 } else {
782 ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 815 ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR,
783 true); 816 true);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 6280e8bca49d..ccd34e926542 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -88,6 +88,7 @@ enum ieee80211_sta_info_flags {
88 * struct tid_ampdu_tx - TID aggregation information (Tx). 88 * struct tid_ampdu_tx - TID aggregation information (Tx).
89 * 89 *
90 * @rcu_head: rcu head for freeing structure 90 * @rcu_head: rcu head for freeing structure
91 * @session_timer: check if we keep Tx-ing on the TID (by timeout value)
91 * @addba_resp_timer: timer for peer's response to addba request 92 * @addba_resp_timer: timer for peer's response to addba request
92 * @pending: pending frames queue -- use sta's spinlock to protect 93 * @pending: pending frames queue -- use sta's spinlock to protect
93 * @dialog_token: dialog token for aggregation session 94 * @dialog_token: dialog token for aggregation session
@@ -110,6 +111,7 @@ enum ieee80211_sta_info_flags {
110 */ 111 */
111struct tid_ampdu_tx { 112struct tid_ampdu_tx {
112 struct rcu_head rcu_head; 113 struct rcu_head rcu_head;
114 struct timer_list session_timer;
113 struct timer_list addba_resp_timer; 115 struct timer_list addba_resp_timer;
114 struct sk_buff_head pending; 116 struct sk_buff_head pending;
115 unsigned long state; 117 unsigned long state;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index a5ff02fbda8c..68cbd0095429 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1067,9 +1067,11 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
1067 int tid) 1067 int tid)
1068{ 1068{
1069 bool queued = false; 1069 bool queued = false;
1070 bool reset_agg_timer = false;
1070 1071
1071 if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) { 1072 if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
1072 info->flags |= IEEE80211_TX_CTL_AMPDU; 1073 info->flags |= IEEE80211_TX_CTL_AMPDU;
1074 reset_agg_timer = true;
1073 } else if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { 1075 } else if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
1074 /* 1076 /*
1075 * nothing -- this aggregation session is being started 1077 * nothing -- this aggregation session is being started
@@ -1101,6 +1103,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
1101 /* do nothing, let packet pass through */ 1103 /* do nothing, let packet pass through */
1102 } else if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) { 1104 } else if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
1103 info->flags |= IEEE80211_TX_CTL_AMPDU; 1105 info->flags |= IEEE80211_TX_CTL_AMPDU;
1106 reset_agg_timer = true;
1104 } else { 1107 } else {
1105 queued = true; 1108 queued = true;
1106 info->control.vif = &tx->sdata->vif; 1109 info->control.vif = &tx->sdata->vif;
@@ -1110,6 +1113,11 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
1110 spin_unlock(&tx->sta->lock); 1113 spin_unlock(&tx->sta->lock);
1111 } 1114 }
1112 1115
1116 /* reset session timer */
1117 if (reset_agg_timer && tid_tx->timeout)
1118 mod_timer(&tid_tx->session_timer,
1119 TU_TO_EXP_TIME(tid_tx->timeout));
1120
1113 return queued; 1121 return queued;
1114} 1122}
1115 1123