mac80211: fix addba timer

The addba timer function acquires the sta spinlock,
but at the same time we try to del_timer_sync() it
under the spinlock which can produce deadlocks.

To fix this, always del_timer_sync() the timer in
ieee80211_process_addba_resp() and add it again
after checking the conditions, if necessary.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Johannes Berg 2009-10-29 08:34:00 +01:00 committed by John W. Linville
parent e55ea2b152
commit 2171abc586

View file

@ -666,26 +666,25 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
state = &sta->ampdu_mlme.tid_state_tx[tid]; state = &sta->ampdu_mlme.tid_state_tx[tid];
del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
spin_lock_bh(&sta->lock); spin_lock_bh(&sta->lock);
if (!(*state & HT_ADDBA_REQUESTED_MSK)) { if (!(*state & HT_ADDBA_REQUESTED_MSK))
spin_unlock_bh(&sta->lock); goto timer_still_needed;
return;
}
if (mgmt->u.action.u.addba_resp.dialog_token != if (mgmt->u.action.u.addba_resp.dialog_token !=
sta->ampdu_mlme.tid_tx[tid]->dialog_token) { sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
spin_unlock_bh(&sta->lock);
#ifdef CONFIG_MAC80211_HT_DEBUG #ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */ #endif /* CONFIG_MAC80211_HT_DEBUG */
return; goto timer_still_needed;
} }
del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
#ifdef CONFIG_MAC80211_HT_DEBUG #ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid); printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */ #endif /* CONFIG_MAC80211_HT_DEBUG */
if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
== WLAN_STATUS_SUCCESS) { == WLAN_STATUS_SUCCESS) {
u8 curstate = *state; u8 curstate = *state;
@ -699,5 +698,11 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
} else { } else {
___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR); ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
} }
goto out;
timer_still_needed:
add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
out:
spin_unlock_bh(&sta->lock); spin_unlock_bh(&sta->lock);
} }