aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ieee80211_rate.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/ieee80211_rate.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/ieee80211_rate.c')
-rw-r--r--net/mac80211/ieee80211_rate.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/net/mac80211/ieee80211_rate.c b/net/mac80211/ieee80211_rate.c
index ebe29b716b27..4de06f128d90 100644
--- a/net/mac80211/ieee80211_rate.c
+++ b/net/mac80211/ieee80211_rate.c
@@ -170,9 +170,12 @@ void rate_control_get_rate(struct net_device *dev,
170 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 170 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
171 struct rate_control_ref *ref = local->rate_ctrl; 171 struct rate_control_ref *ref = local->rate_ctrl;
172 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 172 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
173 struct sta_info *sta = sta_info_get(local, hdr->addr1); 173 struct sta_info *sta;
174 int i; 174 int i;
175 175
176 rcu_read_lock();
177 sta = sta_info_get(local, hdr->addr1);
178
176 memset(sel, 0, sizeof(struct rate_selection)); 179 memset(sel, 0, sizeof(struct rate_selection));
177 180
178 ref->ops->get_rate(ref->priv, dev, sband, skb, sel); 181 ref->ops->get_rate(ref->priv, dev, sband, skb, sel);
@@ -190,8 +193,7 @@ void rate_control_get_rate(struct net_device *dev,
190 } 193 }
191 } 194 }
192 195
193 if (sta) 196 rcu_read_unlock();
194 sta_info_put(sta);
195} 197}
196 198
197struct rate_control_ref *rate_control_get(struct rate_control_ref *ref) 199struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)