aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-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