aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/cfg.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/cfg.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/cfg.c')
-rw-r--r--net/mac80211/cfg.c110
1 files changed, 56 insertions, 54 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 6ac49231efa9..e9ba6fcc0e45 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -136,7 +136,6 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
136 struct ieee80211_sub_if_data *sdata; 136 struct ieee80211_sub_if_data *sdata;
137 struct sta_info *sta = NULL; 137 struct sta_info *sta = NULL;
138 enum ieee80211_key_alg alg; 138 enum ieee80211_key_alg alg;
139 int ret;
140 struct ieee80211_key *key; 139 struct ieee80211_key *key;
141 140
142 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 141 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -170,12 +169,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
170 169
171 ieee80211_key_link(key, sdata, sta); 170 ieee80211_key_link(key, sdata, sta);
172 171
173 ret = 0; 172 return 0;
174
175 if (sta)
176 sta_info_put(sta);
177
178 return ret;
179} 173}
180 174
181static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, 175static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
@@ -184,7 +178,6 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
184 struct ieee80211_sub_if_data *sdata; 178 struct ieee80211_sub_if_data *sdata;
185 struct sta_info *sta; 179 struct sta_info *sta;
186 int ret; 180 int ret;
187 struct ieee80211_key *key;
188 181
189 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 182 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
190 183
@@ -195,21 +188,18 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
195 188
196 ret = 0; 189 ret = 0;
197 if (sta->key) { 190 if (sta->key) {
198 key = sta->key; 191 ieee80211_key_free(sta->key);
199 ieee80211_key_free(key);
200 WARN_ON(sta->key); 192 WARN_ON(sta->key);
201 } else 193 } else
202 ret = -ENOENT; 194 ret = -ENOENT;
203 195
204 sta_info_put(sta);
205 return ret; 196 return ret;
206 } 197 }
207 198
208 if (!sdata->keys[key_idx]) 199 if (!sdata->keys[key_idx])
209 return -ENOENT; 200 return -ENOENT;
210 201
211 key = sdata->keys[key_idx]; 202 ieee80211_key_free(sdata->keys[key_idx]);
212 ieee80211_key_free(key);
213 WARN_ON(sdata->keys[key_idx]); 203 WARN_ON(sdata->keys[key_idx]);
214 204
215 return 0; 205 return 0;
@@ -292,8 +282,6 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
292 err = 0; 282 err = 0;
293 283
294 out: 284 out:
295 if (sta)
296 sta_info_put(sta);
297 return err; 285 return err;
298} 286}
299 287
@@ -311,7 +299,7 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,
311 299
312static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) 300static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
313{ 301{
314 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 302 struct ieee80211_sub_if_data *sdata = sta->sdata;
315 303
316 sinfo->filled = STATION_INFO_INACTIVE_TIME | 304 sinfo->filled = STATION_INFO_INACTIVE_TIME |
317 STATION_INFO_RX_BYTES | 305 STATION_INFO_RX_BYTES |
@@ -340,16 +328,20 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
340{ 328{
341 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 329 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
342 struct sta_info *sta; 330 struct sta_info *sta;
331 int ret = -ENOENT;
332
333 rcu_read_lock();
343 334
344 sta = sta_info_get_by_idx(local, idx, dev); 335 sta = sta_info_get_by_idx(local, idx, dev);
345 if (!sta) 336 if (sta) {
346 return -ENOENT; 337 ret = 0;
338 memcpy(mac, sta->addr, ETH_ALEN);
339 sta_set_sinfo(sta, sinfo);
340 }
347 341
348 memcpy(mac, sta->addr, ETH_ALEN); 342 rcu_read_unlock();
349 sta_set_sinfo(sta, sinfo);
350 sta_info_put(sta);
351 343
352 return 0; 344 return ret;
353} 345}
354 346
355static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, 347static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
@@ -357,16 +349,21 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
357{ 349{
358 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 350 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
359 struct sta_info *sta; 351 struct sta_info *sta;
352 int ret = -ENOENT;
360 353
361 sta = sta_info_get(local, mac); 354 rcu_read_lock();
362 if (!sta)
363 return -ENOENT;
364 355
365 /* XXX: verify sta->dev == dev */ 356 /* XXX: verify sta->dev == dev */
366 sta_set_sinfo(sta, sinfo);
367 sta_info_put(sta);
368 357
369 return 0; 358 sta = sta_info_get(local, mac);
359 if (sta) {
360 ret = 0;
361 sta_set_sinfo(sta, sinfo);
362 }
363
364 rcu_read_unlock();
365
366 return ret;
370} 367}
371 368
372/* 369/*
@@ -559,8 +556,8 @@ static void ieee80211_send_layer2_update(struct sta_info *sta)
559 msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ 556 msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
560 msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ 557 msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */
561 558
562 skb->dev = sta->dev; 559 skb->dev = sta->sdata->dev;
563 skb->protocol = eth_type_trans(skb, sta->dev); 560 skb->protocol = eth_type_trans(skb, sta->sdata->dev);
564 memset(skb->cb, 0, sizeof(skb->cb)); 561 memset(skb->cb, 0, sizeof(skb->cb));
565 netif_rx(skb); 562 netif_rx(skb);
566} 563}
@@ -572,7 +569,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
572 u32 rates; 569 u32 rates;
573 int i, j; 570 int i, j;
574 struct ieee80211_supported_band *sband; 571 struct ieee80211_supported_band *sband;
575 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); 572 struct ieee80211_sub_if_data *sdata = sta->sdata;
576 573
577 if (params->station_flags & STATION_FLAG_CHANGED) { 574 if (params->station_flags & STATION_FLAG_CHANGED) {
578 sta->flags &= ~WLAN_STA_AUTHORIZED; 575 sta->flags &= ~WLAN_STA_AUTHORIZED;
@@ -644,14 +641,13 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
644 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 641 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
645 642
646 if (ieee80211_vif_is_mesh(&sdata->vif)) 643 if (ieee80211_vif_is_mesh(&sdata->vif))
647 sta = mesh_plink_add(mac, DEFAULT_RATES, dev); 644 sta = mesh_plink_add(mac, DEFAULT_RATES, sdata);
648 else 645 else
649 sta = sta_info_add(local, dev, mac, GFP_KERNEL); 646 sta = sta_info_add(sdata, mac);
650 647
651 if (IS_ERR(sta)) 648 if (IS_ERR(sta))
652 return PTR_ERR(sta); 649 return PTR_ERR(sta);
653 650
654 sta->dev = sdata->dev;
655 if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN || 651 if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
656 sdata->vif.type == IEEE80211_IF_TYPE_AP) 652 sdata->vif.type == IEEE80211_IF_TYPE_AP)
657 ieee80211_send_layer2_update(sta); 653 ieee80211_send_layer2_update(sta);
@@ -662,15 +658,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
662 658
663 rate_control_rate_init(sta, local); 659 rate_control_rate_init(sta, local);
664 660
665 sta_info_put(sta);
666
667 return 0; 661 return 0;
668} 662}
669 663
670static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, 664static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
671 u8 *mac) 665 u8 *mac)
672{ 666{
673 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 667 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
668 struct ieee80211_local *local = sdata->local;
674 struct sta_info *sta; 669 struct sta_info *sta;
675 670
676 if (mac) { 671 if (mac) {
@@ -679,10 +674,14 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
679 if (!sta) 674 if (!sta)
680 return -ENOENT; 675 return -ENOENT;
681 676
682 sta_info_free(sta); 677 sta_info_unlink(&sta);
683 sta_info_put(sta); 678
679 if (sta) {
680 synchronize_rcu();
681 sta_info_destroy(sta);
682 }
684 } else 683 } else
685 sta_info_flush(local, dev); 684 sta_info_flush(local, sdata);
686 685
687 return 0; 686 return 0;
688} 687}
@@ -701,21 +700,19 @@ static int ieee80211_change_station(struct wiphy *wiphy,
701 if (!sta) 700 if (!sta)
702 return -ENOENT; 701 return -ENOENT;
703 702
704 if (params->vlan && params->vlan != sta->dev) { 703 if (params->vlan && params->vlan != sta->sdata->dev) {
705 vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); 704 vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
706 705
707 if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN || 706 if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
708 vlansdata->vif.type != IEEE80211_IF_TYPE_AP) 707 vlansdata->vif.type != IEEE80211_IF_TYPE_AP)
709 return -EINVAL; 708 return -EINVAL;
710 709
711 sta->dev = params->vlan; 710 sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
712 ieee80211_send_layer2_update(sta); 711 ieee80211_send_layer2_update(sta);
713 } 712 }
714 713
715 sta_apply_parameters(local, sta, params); 714 sta_apply_parameters(local, sta, params);
716 715
717 sta_info_put(sta);
718
719 return 0; 716 return 0;
720} 717}
721 718
@@ -735,23 +732,26 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
735 if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) 732 if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
736 return -ENOTSUPP; 733 return -ENOTSUPP;
737 734
735 rcu_read_lock();
738 sta = sta_info_get(local, next_hop); 736 sta = sta_info_get(local, next_hop);
739 if (!sta) 737 if (!sta) {
738 rcu_read_unlock();
740 return -ENOENT; 739 return -ENOENT;
740 }
741 741
742 err = mesh_path_add(dst, dev); 742 err = mesh_path_add(dst, dev);
743 if (err) 743 if (err) {
744 rcu_read_unlock();
744 return err; 745 return err;
746 }
745 747
746 rcu_read_lock();
747 mpath = mesh_path_lookup(dst, dev); 748 mpath = mesh_path_lookup(dst, dev);
748 if (!mpath) { 749 if (!mpath) {
749 rcu_read_unlock(); 750 rcu_read_unlock();
750 sta_info_put(sta);
751 return -ENXIO; 751 return -ENXIO;
752 } 752 }
753 mesh_path_fix_nexthop(mpath, sta); 753 mesh_path_fix_nexthop(mpath, sta);
754 sta_info_put(sta); 754
755 rcu_read_unlock(); 755 rcu_read_unlock();
756 return 0; 756 return 0;
757} 757}
@@ -760,7 +760,7 @@ static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
760 u8 *dst) 760 u8 *dst)
761{ 761{
762 if (dst) 762 if (dst)
763 return mesh_path_del(dst, dev); 763 return mesh_path_del(dst, dev, false);
764 764
765 mesh_path_flush(dev); 765 mesh_path_flush(dev);
766 return 0; 766 return 0;
@@ -781,20 +781,22 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
781 if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) 781 if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
782 return -ENOTSUPP; 782 return -ENOTSUPP;
783 783
784 rcu_read_lock();
785
784 sta = sta_info_get(local, next_hop); 786 sta = sta_info_get(local, next_hop);
785 if (!sta) 787 if (!sta) {
788 rcu_read_unlock();
786 return -ENOENT; 789 return -ENOENT;
790 }
787 791
788 rcu_read_lock();
789 mpath = mesh_path_lookup(dst, dev); 792 mpath = mesh_path_lookup(dst, dev);
790 if (!mpath) { 793 if (!mpath) {
791 rcu_read_unlock(); 794 rcu_read_unlock();
792 sta_info_put(sta);
793 return -ENOENT; 795 return -ENOENT;
794 } 796 }
795 797
796 mesh_path_fix_nexthop(mpath, sta); 798 mesh_path_fix_nexthop(mpath, sta);
797 sta_info_put(sta); 799
798 rcu_read_unlock(); 800 rcu_read_unlock();
799 return 0; 801 return 0;
800} 802}