diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-02-25 10:27:47 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-03-06 15:30:47 -0500 |
commit | 73651ee6396c499ccb59ebc84c9274db01ed026d (patch) | |
tree | 1d59027cbdaec732f3e1378770cbf7b42b48cd70 /net/mac80211/cfg.c | |
parent | d0709a65181beb787ef3f58cfe45536a2bb254c8 (diff) |
mac80211: split sta_info_add
sta_info_add() has two functions: allocating a station info
structure and inserting it into the hash table/list. Splitting
these two functions allows allocating with GFP_KERNEL in many
places instead of GFP_ATOMIC which is now required by the RCU
protection. Additionally, in many places RCU protection is now
no longer needed at all because between sta_info_alloc() and
sta_info_insert() the caller owns the structure.
This fixes a few race conditions with setting initial flags
and similar, but not all (see comments in ieee80211_sta.c and
cfg.c). More documentation on the existing races will be in
a follow-up patch.
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.c | 42 |
1 files changed, 33 insertions, 9 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e9ba6fcc0e45..6263cfc148c0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -571,6 +571,12 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
571 | struct ieee80211_supported_band *sband; | 571 | struct ieee80211_supported_band *sband; |
572 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 572 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
573 | 573 | ||
574 | /* | ||
575 | * FIXME: updating the flags is racy when this function is | ||
576 | * called from ieee80211_change_station(), this will | ||
577 | * be resolved in a future patch. | ||
578 | */ | ||
579 | |||
574 | if (params->station_flags & STATION_FLAG_CHANGED) { | 580 | if (params->station_flags & STATION_FLAG_CHANGED) { |
575 | sta->flags &= ~WLAN_STA_AUTHORIZED; | 581 | sta->flags &= ~WLAN_STA_AUTHORIZED; |
576 | if (params->station_flags & STATION_FLAG_AUTHORIZED) | 582 | if (params->station_flags & STATION_FLAG_AUTHORIZED) |
@@ -585,6 +591,13 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
585 | sta->flags |= WLAN_STA_WME; | 591 | sta->flags |= WLAN_STA_WME; |
586 | } | 592 | } |
587 | 593 | ||
594 | /* | ||
595 | * FIXME: updating the following information is racy when this | ||
596 | * function is called from ieee80211_change_station(). | ||
597 | * However, all this information should be static so | ||
598 | * maybe we should just reject attemps to change it. | ||
599 | */ | ||
600 | |||
588 | if (params->aid) { | 601 | if (params->aid) { |
589 | sta->aid = params->aid; | 602 | sta->aid = params->aid; |
590 | if (sta->aid > IEEE80211_MAX_AID) | 603 | if (sta->aid > IEEE80211_MAX_AID) |
@@ -626,6 +639,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
626 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 639 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
627 | struct sta_info *sta; | 640 | struct sta_info *sta; |
628 | struct ieee80211_sub_if_data *sdata; | 641 | struct ieee80211_sub_if_data *sdata; |
642 | int err; | ||
629 | 643 | ||
630 | /* Prevent a race with changing the rate control algorithm */ | 644 | /* Prevent a race with changing the rate control algorithm */ |
631 | if (!netif_running(dev)) | 645 | if (!netif_running(dev)) |
@@ -641,16 +655,11 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
641 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 655 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
642 | 656 | ||
643 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 657 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
644 | sta = mesh_plink_add(mac, DEFAULT_RATES, sdata); | 658 | sta = mesh_plink_alloc(sdata, mac, DEFAULT_RATES, GFP_KERNEL); |
645 | else | 659 | else |
646 | sta = sta_info_add(sdata, mac); | 660 | sta = sta_info_alloc(sdata, mac, GFP_KERNEL); |
647 | 661 | if (!sta) | |
648 | if (IS_ERR(sta)) | 662 | return -ENOMEM; |
649 | return PTR_ERR(sta); | ||
650 | |||
651 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN || | ||
652 | sdata->vif.type == IEEE80211_IF_TYPE_AP) | ||
653 | ieee80211_send_layer2_update(sta); | ||
654 | 663 | ||
655 | sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; | 664 | sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; |
656 | 665 | ||
@@ -658,6 +667,21 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
658 | 667 | ||
659 | rate_control_rate_init(sta, local); | 668 | rate_control_rate_init(sta, local); |
660 | 669 | ||
670 | rcu_read_lock(); | ||
671 | |||
672 | err = sta_info_insert(sta); | ||
673 | if (err) { | ||
674 | sta_info_destroy(sta); | ||
675 | rcu_read_unlock(); | ||
676 | return err; | ||
677 | } | ||
678 | |||
679 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN || | ||
680 | sdata->vif.type == IEEE80211_IF_TYPE_AP) | ||
681 | ieee80211_send_layer2_update(sta); | ||
682 | |||
683 | rcu_read_unlock(); | ||
684 | |||
661 | return 0; | 685 | return 0; |
662 | } | 686 | } |
663 | 687 | ||