return;
 
        spin_lock_bh(&sta->lock);
-       if (sta->ignore_plink_timer) {
-               sta->ignore_plink_timer = false;
+
+       /* If a timer fires just before a state transition on another CPU,
+        * we may have already extended the timeout and changed state by the
+        * time we've acquired the lock and arrived  here.  In that case,
+        * skip this timer and wait for the new one.
+        */
+       if (time_before(jiffies, sta->plink_timer.expires)) {
+               mpl_dbg(sta->sdata,
+                       "Ignoring timer for %pM in state %s (timer adjusted)",
+                       sta->sta.addr, mplstates[sta->plink_state]);
                spin_unlock_bh(&sta->lock);
                return;
        }
+
+       /* del_timer() and handler may race when entering these states */
+       if (sta->plink_state == NL80211_PLINK_LISTEN ||
+           sta->plink_state == NL80211_PLINK_ESTAB) {
+               mpl_dbg(sta->sdata,
+                       "Ignoring timer for %pM in state %s (timer deleted)",
+                       sta->sta.addr, mplstates[sta->plink_state]);
+               spin_unlock_bh(&sta->lock);
+               return;
+       }
+
        mpl_dbg(sta->sdata,
                "Mesh plink timer for %pM fired on state %s\n",
                sta->sta.addr, mplstates[sta->plink_state]);
                        break;
                case CNF_ACPT:
                        sta->plink_state = NL80211_PLINK_CNF_RCVD;
-                       if (!mod_plink_timer(sta,
-                                            mshcfg->dot11MeshConfirmTimeout))
-                               sta->ignore_plink_timer = true;
+                       mod_plink_timer(sta, mshcfg->dot11MeshConfirmTimeout);
                        break;
                default:
                        break;
        case NL80211_PLINK_HOLDING:
                switch (event) {
                case CLS_ACPT:
-                       if (del_timer(&sta->plink_timer))
-                               sta->ignore_plink_timer = 1;
+                       del_timer(&sta->plink_timer);
                        mesh_plink_fsm_restart(sta);
                        break;
                case OPN_ACPT:
 
  * @plid: Peer link ID
  * @reason: Cancel reason on PLINK_HOLDING state
  * @plink_retries: Retries in establishment
- * @ignore_plink_timer: ignore the peer-link timer (used internally)
  * @plink_state: peer link state
  * @plink_timeout: timeout of peer link
  * @plink_timer: peer link watch timer
        u16 plid;
        u16 reason;
        u8 plink_retries;
-       bool ignore_plink_timer;
        enum nl80211_plink_state plink_state;
        u32 plink_timeout;
        struct timer_list plink_timer;