diff options
Diffstat (limited to 'net/mac80211/mesh_plink.c')
-rw-r--r-- | net/mac80211/mesh_plink.c | 37 |
1 files changed, 29 insertions, 8 deletions
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index e8f60aa2e848..c47194d27149 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]); | ||
564 | spin_unlock_bh(&sta->lock); | ||
565 | return; | ||
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]); | ||
556 | spin_unlock_bh(&sta->lock); | 574 | spin_unlock_bh(&sta->lock); |
557 | return; | 575 | return; |
558 | } | 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: |
@@ -943,7 +959,8 @@ mesh_plink_get_event(struct ieee80211_sub_if_data *sdata, | |||
943 | if (!matches_local) | 959 | if (!matches_local) |
944 | event = CNF_RJCT; | 960 | event = CNF_RJCT; |
945 | if (!mesh_plink_free_count(sdata) || | 961 | if (!mesh_plink_free_count(sdata) || |
946 | (sta->llid != llid || sta->plid != plid)) | 962 | sta->llid != llid || |
963 | (sta->plid && sta->plid != plid)) | ||
947 | event = CNF_IGNR; | 964 | event = CNF_IGNR; |
948 | else | 965 | else |
949 | event = CNF_ACPT; | 966 | event = CNF_ACPT; |
@@ -1064,6 +1081,10 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, | |||
1064 | goto unlock_rcu; | 1081 | goto unlock_rcu; |
1065 | } | 1082 | } |
1066 | 1083 | ||
1084 | /* 802.11-2012 13.3.7.2 - update plid on CNF if not set */ | ||
1085 | if (!sta->plid && event == CNF_ACPT) | ||
1086 | sta->plid = plid; | ||
1087 | |||
1067 | changed |= mesh_plink_fsm(sdata, sta, event); | 1088 | changed |= mesh_plink_fsm(sdata, sta, event); |
1068 | 1089 | ||
1069 | unlock_rcu: | 1090 | unlock_rcu: |