aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorBob Copeland <me@bobcopeland.com>2014-06-04 09:27:31 -0400
committerJohannes Berg <johannes.berg@intel.com>2014-06-23 05:05:27 -0400
commit2b470c39e895dfde5413b0a85fac928a353de48d (patch)
tree9f890c8927fbfb4bae1e252b77caace4793f008d /net
parent5ac2e35030113ed881ce9ad413d80f13ffe5b5a0 (diff)
mac80211: remove ignore_plink_timer flag
The mesh_plink code is doing some interesting things with the ignore_plink_timer flag. It seems the original intent was to handle this race: cpu 0 cpu 1 ----- ----- start timer handler for state X acquire sta_lock change state from X to Y mod_timer() / del_timer() release sta_lock acquire sta_lock execute state Y timer too soon However, using the mod_timer()/del_timer() return values to detect these cases is broken. As a result, timers get ignored unnecessarily, and stations can get stuck in the peering state machine. Instead, we can detect the case by looking at the timer expiration. In the case of del_timer, just ignore the timers in the following (LISTEN/ESTAB) states since they won't have timers anyway. Signed-off-by: Bob Copeland <me@bobcopeland.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/mesh_plink.c30
-rw-r--r--net/mac80211/sta_info.h2
2 files changed, 23 insertions, 9 deletions
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index e8f60aa2e848..63b874101b27 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -551,11 +551,30 @@ static void mesh_plink_timer(unsigned long data)
551 return; 551 return;
552 552
553 spin_lock_bh(&sta->lock); 553 spin_lock_bh(&sta->lock);
554 if (sta->ignore_plink_timer) { 554
555 sta->ignore_plink_timer = false; 555 /* If a timer fires just before a state transition on another CPU,
556 * we may have already extended the timeout and changed state by the
557 * time we've acquired the lock and arrived here. In that case,
558 * skip this timer and wait for the new one.
559 */
560 if (time_before(jiffies, sta->plink_timer.expires)) {
561 mpl_dbg(sta->sdata,
562 "Ignoring timer for %pM in state %s (timer adjusted)",
563 sta->sta.addr, mplstates[sta->plink_state]);
556 spin_unlock_bh(&sta->lock); 564 spin_unlock_bh(&sta->lock);
557 return; 565 return;
558 } 566 }
567
568 /* del_timer() and handler may race when entering these states */
569 if (sta->plink_state == NL80211_PLINK_LISTEN ||
570 sta->plink_state == NL80211_PLINK_ESTAB) {
571 mpl_dbg(sta->sdata,
572 "Ignoring timer for %pM in state %s (timer deleted)",
573 sta->sta.addr, mplstates[sta->plink_state]);
574 spin_unlock_bh(&sta->lock);
575 return;
576 }
577
559 mpl_dbg(sta->sdata, 578 mpl_dbg(sta->sdata,
560 "Mesh plink timer for %pM fired on state %s\n", 579 "Mesh plink timer for %pM fired on state %s\n",
561 sta->sta.addr, mplstates[sta->plink_state]); 580 sta->sta.addr, mplstates[sta->plink_state]);
@@ -773,9 +792,7 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,
773 break; 792 break;
774 case CNF_ACPT: 793 case CNF_ACPT:
775 sta->plink_state = NL80211_PLINK_CNF_RCVD; 794 sta->plink_state = NL80211_PLINK_CNF_RCVD;
776 if (!mod_plink_timer(sta, 795 mod_plink_timer(sta, mshcfg->dot11MeshConfirmTimeout);
777 mshcfg->dot11MeshConfirmTimeout))
778 sta->ignore_plink_timer = true;
779 break; 796 break;
780 default: 797 default:
781 break; 798 break;
@@ -834,8 +851,7 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,
834 case NL80211_PLINK_HOLDING: 851 case NL80211_PLINK_HOLDING:
835 switch (event) { 852 switch (event) {
836 case CLS_ACPT: 853 case CLS_ACPT:
837 if (del_timer(&sta->plink_timer)) 854 del_timer(&sta->plink_timer);
838 sta->ignore_plink_timer = 1;
839 mesh_plink_fsm_restart(sta); 855 mesh_plink_fsm_restart(sta);
840 break; 856 break;
841 case OPN_ACPT: 857 case OPN_ACPT:
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index dee0b645b34c..159cac903ce8 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -306,7 +306,6 @@ struct ieee80211_tx_latency_stat {
306 * @plid: Peer link ID 306 * @plid: Peer link ID
307 * @reason: Cancel reason on PLINK_HOLDING state 307 * @reason: Cancel reason on PLINK_HOLDING state
308 * @plink_retries: Retries in establishment 308 * @plink_retries: Retries in establishment
309 * @ignore_plink_timer: ignore the peer-link timer (used internally)
310 * @plink_state: peer link state 309 * @plink_state: peer link state
311 * @plink_timeout: timeout of peer link 310 * @plink_timeout: timeout of peer link
312 * @plink_timer: peer link watch timer 311 * @plink_timer: peer link watch timer
@@ -421,7 +420,6 @@ struct sta_info {
421 u16 plid; 420 u16 plid;
422 u16 reason; 421 u16 reason;
423 u8 plink_retries; 422 u8 plink_retries;
424 bool ignore_plink_timer;
425 enum nl80211_plink_state plink_state; 423 enum nl80211_plink_state plink_state;
426 u32 plink_timeout; 424 u32 plink_timeout;
427 struct timer_list plink_timer; 425 struct timer_list plink_timer;