diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-07-10 02:39:48 +0200 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-07-24 15:05:10 -0400 |
commit | ca386f3137eb68621fadba546d9eb35ac2f82de3 (patch) | |
tree | bfdb1ecabe0ca942fadec255a7c92ecac405f153 /net | |
parent | 01a7e08436929271c6173b5daf3e193ef5b3561a (diff) |
mac80211: fix multi-use timer
We have, sometimes, multiple things that want to
run but don't have their own timer. Introduce a
new function to mac80211's mlme run_again() that
makes sure that the timer will run again at the
_first_ needed time, use that function and also
properly reprogram the timer once it fired.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/mlme.c | 40 |
1 files changed, 33 insertions, 7 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 8e4a60497bb..c1114bb8095 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -72,6 +72,26 @@ static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd) WARN_ON(!mutex_is_locked(&ifmgd->mtx)); } +/* + * We can have multiple work items (and connection probing) + * scheduling this timer, but we need to take care to only + * reschedule it when it should fire _earlier_ than it was + * asked for before, or if it's not pending right now. This + * function ensures that. Note that it then is required to + * run this function for all timeouts after the first one + * has happened -- the work that runs from this timer will + * do that. + */ +static void run_again(struct ieee80211_if_managed *ifmgd, + unsigned long timeout) +{ + ASSERT_MGD_MTX(ifmgd); + + if (!timer_pending(&ifmgd->timer) || + time_before(timeout, ifmgd->timer.expires)) + mod_timer(&ifmgd->timer, timeout); +} + static int ecw2cw(int ecw) { return (1 << ecw) - 1; @@ -916,7 +936,7 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0); wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; - mod_timer(&ifmgd->timer, wk->timeout); + run_again(ifmgd, wk->timeout); return RX_MGMT_NONE; } @@ -958,7 +978,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, wk->auth_transaction = 2; wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; - mod_timer(&ifmgd->timer, wk->timeout); + run_again(ifmgd, wk->timeout); return RX_MGMT_NONE; } @@ -1079,7 +1099,7 @@ ieee80211_associate(struct ieee80211_sub_if_data *sdata, ieee80211_send_assoc(sdata, wk); wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; - mod_timer(&ifmgd->timer, wk->timeout); + run_again(ifmgd, wk->timeout); return RX_MGMT_NONE; } @@ -1140,7 +1160,7 @@ void ieee80211_beacon_loss_work(struct work_struct *work) ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid, ssid + 2, ssid[1], NULL, 0); - mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); + run_again(ifmgd, jiffies + IEEE80211_PROBE_WAIT); out: mutex_unlock(&ifmgd->mtx); } @@ -1350,8 +1370,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, sdata->dev->name, tu, ms); wk->timeout = jiffies + msecs_to_jiffies(ms); if (ms > IEEE80211_ASSOC_TIMEOUT) - mod_timer(&ifmgd->timer, - jiffies + msecs_to_jiffies(ms)); + run_again(ifmgd, jiffies + msecs_to_jiffies(ms)); return RX_MGMT_NONE; } @@ -1981,8 +2000,15 @@ static void ieee80211_sta_work(struct work_struct *work) } list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) { - if (time_before(jiffies, wk->timeout)) + if (time_is_after_jiffies(wk->timeout)) { + /* + * This work item isn't supposed to be worked on + * right now, but take care to adjust the timer + * properly. + */ + run_again(ifmgd, wk->timeout); continue; + } switch (wk->state) { default: |