aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/rate.h
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2015-03-05 10:10:08 -0500
committerJohannes Berg <johannes.berg@intel.com>2015-04-20 07:05:29 -0400
commit35c347ac53040daba955fa06fcd5f909bee85017 (patch)
treed41370616c36e6c522bba88a0f254fa4a52454fa /net/mac80211/rate.h
parent48bf6beddf455b0cb605915081f3428960a6224e (diff)
mac80211: lock rate control
Both minstrel (reported by Sven Eckelmann) and the iwlwifi rate control aren't properly taking concurrency into account. It's likely that the same is true for other rate control algorithms. In the case of minstrel this manifests itself in crashes when an update and other data access are run concurrently, for example when the stations change bandwidth or similar. In iwlwifi, this can cause firmware crashes. Since fixing all rate control algorithms will be very difficult, just provide locking for invocations. This protects the internal data structures the algorithms maintain. I've manipulated hostapd to test this, by having it change its advertised bandwidth roughly ever 150ms. At the same time, I'm running a flood ping between the client and the AP, which causes this race of update vs. get_rate/status to easily happen on the client. With this change, the system survives this test. Reported-by: Sven Eckelmann <sven@open-mesh.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/rate.h')
-rw-r--r--net/mac80211/rate.h14
1 files changed, 11 insertions, 3 deletions
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index 38652f09feaf..25c9be5dd7fd 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -42,10 +42,12 @@ static inline void rate_control_tx_status(struct ieee80211_local *local,
42 if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) 42 if (!ref || !test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
43 return; 43 return;
44 44
45 spin_lock_bh(&sta->rate_ctrl_lock);
45 if (ref->ops->tx_status) 46 if (ref->ops->tx_status)
46 ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); 47 ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb);
47 else 48 else
48 ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info); 49 ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info);
50 spin_unlock_bh(&sta->rate_ctrl_lock);
49} 51}
50 52
51static inline void 53static inline void
@@ -64,7 +66,9 @@ rate_control_tx_status_noskb(struct ieee80211_local *local,
64 if (WARN_ON_ONCE(!ref->ops->tx_status_noskb)) 66 if (WARN_ON_ONCE(!ref->ops->tx_status_noskb))
65 return; 67 return;
66 68
69 spin_lock_bh(&sta->rate_ctrl_lock);
67 ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info); 70 ref->ops->tx_status_noskb(ref->priv, sband, ista, priv_sta, info);
71 spin_unlock_bh(&sta->rate_ctrl_lock);
68} 72}
69 73
70static inline void rate_control_rate_init(struct sta_info *sta) 74static inline void rate_control_rate_init(struct sta_info *sta)
@@ -91,8 +95,10 @@ static inline void rate_control_rate_init(struct sta_info *sta)
91 95
92 sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; 96 sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band];
93 97
98 spin_lock_bh(&sta->rate_ctrl_lock);
94 ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista, 99 ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista,
95 priv_sta); 100 priv_sta);
101 spin_unlock_bh(&sta->rate_ctrl_lock);
96 rcu_read_unlock(); 102 rcu_read_unlock();
97 set_sta_flag(sta, WLAN_STA_RATE_CONTROL); 103 set_sta_flag(sta, WLAN_STA_RATE_CONTROL);
98} 104}
@@ -115,18 +121,20 @@ static inline void rate_control_rate_update(struct ieee80211_local *local,
115 return; 121 return;
116 } 122 }
117 123
124 spin_lock_bh(&sta->rate_ctrl_lock);
118 ref->ops->rate_update(ref->priv, sband, &chanctx_conf->def, 125 ref->ops->rate_update(ref->priv, sband, &chanctx_conf->def,
119 ista, priv_sta, changed); 126 ista, priv_sta, changed);
127 spin_unlock_bh(&sta->rate_ctrl_lock);
120 rcu_read_unlock(); 128 rcu_read_unlock();
121 } 129 }
122 drv_sta_rc_update(local, sta->sdata, &sta->sta, changed); 130 drv_sta_rc_update(local, sta->sdata, &sta->sta, changed);
123} 131}
124 132
125static inline void *rate_control_alloc_sta(struct rate_control_ref *ref, 133static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,
126 struct ieee80211_sta *sta, 134 struct sta_info *sta, gfp_t gfp)
127 gfp_t gfp)
128{ 135{
129 return ref->ops->alloc_sta(ref->priv, sta, gfp); 136 spin_lock_init(&sta->rate_ctrl_lock);
137 return ref->ops->alloc_sta(ref->priv, &sta->sta, gfp);
130} 138}
131 139
132static inline void rate_control_free_sta(struct sta_info *sta) 140static inline void rate_control_free_sta(struct sta_info *sta)