Commit 7cca2acd authored by Kees Cook's avatar Kees Cook Committed by Johannes Berg

mac80211: aggregation: Convert timers to use timer_setup()

In preparation for unconditionally passing the struct timer_list pointer to
all timer callbacks, switch to using the new timer_setup() and from_timer()
to pass the timer pointer explicitly.

This removes the tid mapping array and expands the tid structures to
add a pointer back to the station, along with the tid index itself.

Cc: Johannes Berg <johannes@sipsolutions.net>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: linux-wireless@vger.kernel.org
Cc: netdev@vger.kernel.org
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
[switch tid variables to u8, the valid range is 0-15 at most,
 initialize tid_tx->sta/tid properly]
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 44905265
...@@ -151,21 +151,17 @@ EXPORT_SYMBOL(ieee80211_stop_rx_ba_session); ...@@ -151,21 +151,17 @@ EXPORT_SYMBOL(ieee80211_stop_rx_ba_session);
* After accepting the AddBA Request we activated a timer, * After accepting the AddBA Request we activated a timer,
* resetting it after each frame that arrives from the originator. * resetting it after each frame that arrives from the originator.
*/ */
static void sta_rx_agg_session_timer_expired(unsigned long data) static void sta_rx_agg_session_timer_expired(struct timer_list *t)
{ {
/* not an elegant detour, but there is no choice as the timer passes struct tid_ampdu_rx *tid_rx_timer =
* only one argument, and various sta_info are needed here, so init from_timer(tid_rx_timer, t, session_timer);
* flow in sta_info_create gives the TID as data, while the timer_to_id struct sta_info *sta = tid_rx_timer->sta;
* array gives the sta through container_of */ u8 tid = tid_rx_timer->tid;
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]);
struct tid_ampdu_rx *tid_rx; struct tid_ampdu_rx *tid_rx;
unsigned long timeout; unsigned long timeout;
rcu_read_lock(); rcu_read_lock();
tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[*ptid]); tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
if (!tid_rx) { if (!tid_rx) {
rcu_read_unlock(); rcu_read_unlock();
return; return;
...@@ -180,21 +176,18 @@ static void sta_rx_agg_session_timer_expired(unsigned long data) ...@@ -180,21 +176,18 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
rcu_read_unlock(); rcu_read_unlock();
ht_dbg(sta->sdata, "RX session timer expired on %pM tid %d\n", ht_dbg(sta->sdata, "RX session timer expired on %pM tid %d\n",
sta->sta.addr, (u16)*ptid); sta->sta.addr, tid);
set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired); set_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired);
ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work); ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
} }
static void sta_rx_agg_reorder_timer_expired(unsigned long data) static void sta_rx_agg_reorder_timer_expired(struct timer_list *t)
{ {
u8 *ptid = (u8 *)data; struct tid_ampdu_rx *tid_rx = from_timer(tid_rx, t, reorder_timer);
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(); rcu_read_lock();
ieee80211_release_reorder_timeout(sta, *ptid); ieee80211_release_reorder_timeout(tid_rx->sta, tid_rx->tid);
rcu_read_unlock(); rcu_read_unlock();
} }
...@@ -356,14 +349,12 @@ void ___ieee80211_start_rx_ba_session(struct sta_info *sta, ...@@ -356,14 +349,12 @@ void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
spin_lock_init(&tid_agg_rx->reorder_lock); spin_lock_init(&tid_agg_rx->reorder_lock);
/* rx timer */ /* rx timer */
setup_deferrable_timer(&tid_agg_rx->session_timer, timer_setup(&tid_agg_rx->session_timer,
sta_rx_agg_session_timer_expired, sta_rx_agg_session_timer_expired, TIMER_DEFERRABLE);
(unsigned long)&sta->timer_to_tid[tid]);
/* rx reorder timer */ /* rx reorder timer */
setup_timer(&tid_agg_rx->reorder_timer, timer_setup(&tid_agg_rx->reorder_timer,
sta_rx_agg_reorder_timer_expired, sta_rx_agg_reorder_timer_expired, 0);
(unsigned long)&sta->timer_to_tid[tid]);
/* prepare reordering buffer */ /* prepare reordering buffer */
tid_agg_rx->reorder_buf = tid_agg_rx->reorder_buf =
...@@ -399,6 +390,8 @@ void ___ieee80211_start_rx_ba_session(struct sta_info *sta, ...@@ -399,6 +390,8 @@ void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
tid_agg_rx->auto_seq = auto_seq; tid_agg_rx->auto_seq = auto_seq;
tid_agg_rx->started = false; tid_agg_rx->started = false;
tid_agg_rx->reorder_buf_filtered = 0; tid_agg_rx->reorder_buf_filtered = 0;
tid_agg_rx->tid = tid;
tid_agg_rx->sta = sta;
status = WLAN_STATUS_SUCCESS; status = WLAN_STATUS_SUCCESS;
/* activate it for RX */ /* activate it for RX */
......
...@@ -422,15 +422,12 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, ...@@ -422,15 +422,12 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
* add Block Ack response will arrive from the recipient. * add Block Ack response will arrive from the recipient.
* If this timer expires sta_addba_resp_timer_expired will be executed. * If this timer expires sta_addba_resp_timer_expired will be executed.
*/ */
static void sta_addba_resp_timer_expired(unsigned long data) static void sta_addba_resp_timer_expired(struct timer_list *t)
{ {
/* not an elegant detour, but there is no choice as the timer passes struct tid_ampdu_tx *tid_tx_timer =
* only one argument, and both sta_info and TID are needed, so init from_timer(tid_tx_timer, t, addba_resp_timer);
* flow in sta_info_create gives the TID as data, while the timer_to_id struct sta_info *sta = tid_tx_timer->sta;
* array gives the sta through container_of */ u8 tid = tid_tx_timer->tid;
u16 tid = *(u8 *)data;
struct sta_info *sta = container_of((void *)data,
struct sta_info, timer_to_tid[tid]);
struct tid_ampdu_tx *tid_tx; struct tid_ampdu_tx *tid_tx;
/* check if the TID waits for addBA response */ /* check if the TID waits for addBA response */
...@@ -525,21 +522,17 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) ...@@ -525,21 +522,17 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
* After accepting the AddBA Response we activated a timer, * After accepting the AddBA Response we activated a timer,
* resetting it after each frame that we send. * resetting it after each frame that we send.
*/ */
static void sta_tx_agg_session_timer_expired(unsigned long data) static void sta_tx_agg_session_timer_expired(struct timer_list *t)
{ {
/* not an elegant detour, but there is no choice as the timer passes struct tid_ampdu_tx *tid_tx_timer =
* only one argument, and various sta_info are needed here, so init from_timer(tid_tx_timer, t, session_timer);
* flow in sta_info_create gives the TID as data, while the timer_to_id struct sta_info *sta = tid_tx_timer->sta;
* array gives the sta through container_of */ u8 tid = tid_tx_timer->tid;
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]);
struct tid_ampdu_tx *tid_tx; struct tid_ampdu_tx *tid_tx;
unsigned long timeout; unsigned long timeout;
rcu_read_lock(); rcu_read_lock();
tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[*ptid]); tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
if (!tid_tx || test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { if (!tid_tx || test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
rcu_read_unlock(); rcu_read_unlock();
return; return;
...@@ -555,9 +548,9 @@ static void sta_tx_agg_session_timer_expired(unsigned long data) ...@@ -555,9 +548,9 @@ static void sta_tx_agg_session_timer_expired(unsigned long data)
rcu_read_unlock(); rcu_read_unlock();
ht_dbg(sta->sdata, "tx session timer expired on %pM tid %d\n", ht_dbg(sta->sdata, "tx session timer expired on %pM tid %d\n",
sta->sta.addr, (u16)*ptid); sta->sta.addr, tid);
ieee80211_stop_tx_ba_session(&sta->sta, *ptid); ieee80211_stop_tx_ba_session(&sta->sta, tid);
} }
int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
...@@ -670,16 +663,15 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, ...@@ -670,16 +663,15 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
__set_bit(HT_AGG_STATE_WANT_START, &tid_tx->state); __set_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
tid_tx->timeout = timeout; tid_tx->timeout = timeout;
tid_tx->sta = sta;
tid_tx->tid = tid;
/* response timer */ /* response timer */
setup_timer(&tid_tx->addba_resp_timer, timer_setup(&tid_tx->addba_resp_timer, sta_addba_resp_timer_expired, 0);
sta_addba_resp_timer_expired,
(unsigned long)&sta->timer_to_tid[tid]);
/* tx timer */ /* tx timer */
setup_deferrable_timer(&tid_tx->session_timer, timer_setup(&tid_tx->session_timer,
sta_tx_agg_session_timer_expired, sta_tx_agg_session_timer_expired, TIMER_DEFERRABLE);
(unsigned long)&sta->timer_to_tid[tid]);
/* assign a dialog token */ /* assign a dialog token */
sta->ampdu_mlme.dialog_token_allocator++; sta->ampdu_mlme.dialog_token_allocator++;
......
...@@ -379,14 +379,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, ...@@ -379,14 +379,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
if (sta_prepare_rate_control(local, sta, gfp)) if (sta_prepare_rate_control(local, sta, gfp))
goto free_txq; goto free_txq;
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
/*
* timer_to_tid must be initialized with identity mapping
* to enable session_timer's data differentiation. See
* sta_rx_agg_session_timer_expired for usage.
*/
sta->timer_to_tid[i] = i;
}
for (i = 0; i < IEEE80211_NUM_ACS; i++) { for (i = 0; i < IEEE80211_NUM_ACS; i++) {
skb_queue_head_init(&sta->ps_tx_buf[i]); skb_queue_head_init(&sta->ps_tx_buf[i]);
skb_queue_head_init(&sta->tx_filtered[i]); skb_queue_head_init(&sta->tx_filtered[i]);
......
...@@ -126,6 +126,8 @@ enum ieee80211_agg_stop_reason { ...@@ -126,6 +126,8 @@ enum ieee80211_agg_stop_reason {
AGG_STOP_DESTROY_STA, AGG_STOP_DESTROY_STA,
}; };
struct sta_info;
/** /**
* struct tid_ampdu_tx - TID aggregation information (Tx). * struct tid_ampdu_tx - TID aggregation information (Tx).
* *
...@@ -133,8 +135,10 @@ enum ieee80211_agg_stop_reason { ...@@ -133,8 +135,10 @@ enum ieee80211_agg_stop_reason {
* @session_timer: check if we keep Tx-ing on the TID (by timeout value) * @session_timer: check if we keep Tx-ing on the TID (by timeout value)
* @addba_resp_timer: timer for peer's response to addba request * @addba_resp_timer: timer for peer's response to addba request
* @pending: pending frames queue -- use sta's spinlock to protect * @pending: pending frames queue -- use sta's spinlock to protect
* @sta: station we are attached to
* @dialog_token: dialog token for aggregation session * @dialog_token: dialog token for aggregation session
* @timeout: session timeout value to be filled in ADDBA requests * @timeout: session timeout value to be filled in ADDBA requests
* @tid: TID number
* @state: session state (see above) * @state: session state (see above)
* @last_tx: jiffies of last tx activity * @last_tx: jiffies of last tx activity
* @stop_initiator: initiator of a session stop * @stop_initiator: initiator of a session stop
...@@ -158,6 +162,7 @@ struct tid_ampdu_tx { ...@@ -158,6 +162,7 @@ struct tid_ampdu_tx {
struct timer_list session_timer; struct timer_list session_timer;
struct timer_list addba_resp_timer; struct timer_list addba_resp_timer;
struct sk_buff_head pending; struct sk_buff_head pending;
struct sta_info *sta;
unsigned long state; unsigned long state;
unsigned long last_tx; unsigned long last_tx;
u16 timeout; u16 timeout;
...@@ -169,6 +174,7 @@ struct tid_ampdu_tx { ...@@ -169,6 +174,7 @@ struct tid_ampdu_tx {
u16 failed_bar_ssn; u16 failed_bar_ssn;
bool bar_pending; bool bar_pending;
bool amsdu; bool amsdu;
u8 tid;
}; };
/** /**
...@@ -181,12 +187,14 @@ struct tid_ampdu_tx { ...@@ -181,12 +187,14 @@ struct tid_ampdu_tx {
* @reorder_time: jiffies when skb was added * @reorder_time: jiffies when skb was added
* @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
* @reorder_timer: releases expired frames from the reorder buffer. * @reorder_timer: releases expired frames from the reorder buffer.
* @sta: station we are attached to
* @last_rx: jiffies of last rx activity * @last_rx: jiffies of last rx activity
* @head_seq_num: head sequence number in reordering buffer. * @head_seq_num: head sequence number in reordering buffer.
* @stored_mpdu_num: number of MPDUs in reordering buffer * @stored_mpdu_num: number of MPDUs in reordering buffer
* @ssn: Starting Sequence Number expected to be aggregated. * @ssn: Starting Sequence Number expected to be aggregated.
* @buf_size: buffer size for incoming A-MPDUs * @buf_size: buffer size for incoming A-MPDUs
* @timeout: reset timer value (in TUs). * @timeout: reset timer value (in TUs).
* @tid: TID number
* @rcu_head: RCU head used for freeing this struct * @rcu_head: RCU head used for freeing this struct
* @reorder_lock: serializes access to reorder buffer, see below. * @reorder_lock: serializes access to reorder buffer, see below.
* @auto_seq: used for offloaded BA sessions to automatically pick head_seq_and * @auto_seq: used for offloaded BA sessions to automatically pick head_seq_and
...@@ -208,6 +216,7 @@ struct tid_ampdu_rx { ...@@ -208,6 +216,7 @@ struct tid_ampdu_rx {
u64 reorder_buf_filtered; u64 reorder_buf_filtered;
struct sk_buff_head *reorder_buf; struct sk_buff_head *reorder_buf;
unsigned long *reorder_time; unsigned long *reorder_time;
struct sta_info *sta;
struct timer_list session_timer; struct timer_list session_timer;
struct timer_list reorder_timer; struct timer_list reorder_timer;
unsigned long last_rx; unsigned long last_rx;
...@@ -216,6 +225,7 @@ struct tid_ampdu_rx { ...@@ -216,6 +225,7 @@ struct tid_ampdu_rx {
u16 ssn; u16 ssn;
u16 buf_size; u16 buf_size;
u16 timeout; u16 timeout;
u8 tid;
u8 auto_seq:1, u8 auto_seq:1,
removed:1, removed:1,
started:1; started:1;
...@@ -447,7 +457,6 @@ struct ieee80211_sta_rx_stats { ...@@ -447,7 +457,6 @@ struct ieee80211_sta_rx_stats {
* plus one for non-QoS frames) * plus one for non-QoS frames)
* @tid_seq: per-TID sequence numbers for sending to this STA * @tid_seq: per-TID sequence numbers for sending to this STA
* @ampdu_mlme: A-MPDU state machine state * @ampdu_mlme: A-MPDU state machine state
* @timer_to_tid: identity mapping to ID timers
* @mesh: mesh STA information * @mesh: mesh STA information
* @debugfs_dir: debug filesystem directory dentry * @debugfs_dir: debug filesystem directory dentry
* @dead: set to true when sta is unlinked * @dead: set to true when sta is unlinked
...@@ -554,7 +563,6 @@ struct sta_info { ...@@ -554,7 +563,6 @@ struct sta_info {
* Aggregation information, locked with lock. * Aggregation information, locked with lock.
*/ */
struct sta_ampdu_mlme ampdu_mlme; struct sta_ampdu_mlme ampdu_mlme;
u8 timer_to_tid[IEEE80211_NUM_TIDS];
#ifdef CONFIG_MAC80211_DEBUGFS #ifdef CONFIG_MAC80211_DEBUGFS
struct dentry *debugfs_dir; struct dentry *debugfs_dir;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment