aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/rc80211_pid_algo.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-02-25 10:27:46 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-03-06 15:30:46 -0500
commitd0709a65181beb787ef3f58cfe45536a2bb254c8 (patch)
tree29e5f36583b0e0a3f11b291347e57672eab41dad /net/mac80211/rc80211_pid_algo.c
parent5cf121c3cdb955583bf0c5d28c992b7968a4aa1a (diff)
mac80211: RCU-ify STA info structure access
This makes access to the STA hash table/list use RCU to protect against freeing of items. However, it's not a true RCU, the copy step is missing: whenever somebody changes a STA item it is simply updated. This is an existing race condition that is now somewhat understandable. This patch also fixes the race key freeing vs. STA destruction by making sure that sta_info_destroy() is always called under RTNL and frees the key. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/rc80211_pid_algo.c')
-rw-r--r--net/mac80211/rc80211_pid_algo.c25
1 files changed, 14 insertions, 11 deletions
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c
index 217c0f487bba..a1993161de99 100644
--- a/net/mac80211/rc80211_pid_algo.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -77,7 +77,7 @@ static void rate_control_pid_adjust_rate(struct ieee80211_local *local,
77 int cur_sorted, new_sorted, probe, tmp, n_bitrates, band; 77 int cur_sorted, new_sorted, probe, tmp, n_bitrates, band;
78 int cur = sta->txrate_idx; 78 int cur = sta->txrate_idx;
79 79
80 sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 80 sdata = sta->sdata;
81 sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 81 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
82 band = sband->band; 82 band = sband->band;
83 n_bitrates = sband->n_bitrates; 83 n_bitrates = sband->n_bitrates;
@@ -149,7 +149,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
149 struct sta_info *sta) 149 struct sta_info *sta)
150{ 150{
151#ifdef CONFIG_MAC80211_MESH 151#ifdef CONFIG_MAC80211_MESH
152 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 152 struct ieee80211_sub_if_data *sdata = sta->sdata;
153#endif 153#endif
154 struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv; 154 struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv;
155 struct rc_pid_rateinfo *rinfo = pinfo->rinfo; 155 struct rc_pid_rateinfo *rinfo = pinfo->rinfo;
@@ -249,23 +249,25 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
249 unsigned long period; 249 unsigned long period;
250 struct ieee80211_supported_band *sband; 250 struct ieee80211_supported_band *sband;
251 251
252 rcu_read_lock();
253
252 sta = sta_info_get(local, hdr->addr1); 254 sta = sta_info_get(local, hdr->addr1);
253 sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 255 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
254 256
255 if (!sta) 257 if (!sta)
256 return; 258 goto unlock;
257 259
258 /* Don't update the state if we're not controlling the rate. */ 260 /* Don't update the state if we're not controlling the rate. */
259 sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 261 sdata = sta->sdata;
260 if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { 262 if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
261 sta->txrate_idx = sdata->bss->max_ratectrl_rateidx; 263 sta->txrate_idx = sdata->bss->max_ratectrl_rateidx;
262 return; 264 goto unlock;
263 } 265 }
264 266
265 /* Ignore all frames that were sent with a different rate than the rate 267 /* Ignore all frames that were sent with a different rate than the rate
266 * we currently advise mac80211 to use. */ 268 * we currently advise mac80211 to use. */
267 if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx]) 269 if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx])
268 goto ignore; 270 goto unlock;
269 271
270 spinfo = sta->rate_ctrl_priv; 272 spinfo = sta->rate_ctrl_priv;
271 spinfo->tx_num_xmit++; 273 spinfo->tx_num_xmit++;
@@ -303,8 +305,8 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
303 if (time_after(jiffies, spinfo->last_sample + period)) 305 if (time_after(jiffies, spinfo->last_sample + period))
304 rate_control_pid_sample(pinfo, local, sta); 306 rate_control_pid_sample(pinfo, local, sta);
305 307
306ignore: 308 unlock:
307 sta_info_put(sta); 309 rcu_read_unlock();
308} 310}
309 311
310static void rate_control_pid_get_rate(void *priv, struct net_device *dev, 312static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
@@ -319,6 +321,8 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
319 int rateidx; 321 int rateidx;
320 u16 fc; 322 u16 fc;
321 323
324 rcu_read_lock();
325
322 sta = sta_info_get(local, hdr->addr1); 326 sta = sta_info_get(local, hdr->addr1);
323 327
324 /* Send management frames and broadcast/multicast data using lowest 328 /* Send management frames and broadcast/multicast data using lowest
@@ -327,8 +331,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
327 if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || 331 if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
328 is_multicast_ether_addr(hdr->addr1) || !sta) { 332 is_multicast_ether_addr(hdr->addr1) || !sta) {
329 sel->rate = rate_lowest(local, sband, sta); 333 sel->rate = rate_lowest(local, sband, sta);
330 if (sta) 334 rcu_read_unlock();
331 sta_info_put(sta);
332 return; 335 return;
333 } 336 }
334 337
@@ -344,7 +347,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
344 347
345 sta->last_txrate_idx = rateidx; 348 sta->last_txrate_idx = rateidx;
346 349
347 sta_info_put(sta); 350 rcu_read_unlock();
348 351
349 sel->rate = &sband->bitrates[rateidx]; 352 sel->rate = &sband->bitrates[rateidx];
350 353