diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2007-09-18 17:29:21 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:53:00 -0400 |
commit | 79010420cc3f78eab911598bfdd29c4b06a83e1f (patch) | |
tree | a9031164d7944f8aa90a455d297780b241f3d865 /net/mac80211/ieee80211_sta.c | |
parent | ea49c359f36d5b40bf033c45a08332cb73777aa2 (diff) |
[PATCH] mac80211: fix virtual interface locking
Florian Lohoff noticed a bug in mac80211: when bringing the
master interface down while other virtual interfaces are up
we call dev_close() under a spinlock which is not allowed.
This patch removes the sub_if_lock used by mac80211 in favour
of using an RCU list. All list manipulations are already done
under rtnl so are well protected against each other, and the
read-side locks we took in the RX and TX code are already in
RCU read-side critical sections.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Cc: Florian Lohoff <flo@rfc822.org>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Michal Piotrowski <michal.k.k.piotrowski@gmail.com>
Cc: Satyam Sharma <satyam@infradead.org>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/ieee80211_sta.c')
-rw-r--r-- | net/mac80211/ieee80211_sta.c | 12 |
1 files changed, 6 insertions, 6 deletions
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 17455c6a5229..651aaba1add4 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c | |||
@@ -2676,8 +2676,8 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) | |||
2676 | memset(&wrqu, 0, sizeof(wrqu)); | 2676 | memset(&wrqu, 0, sizeof(wrqu)); |
2677 | wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); | 2677 | wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); |
2678 | 2678 | ||
2679 | read_lock(&local->sub_if_lock); | 2679 | rcu_read_lock(); |
2680 | list_for_each_entry(sdata, &local->sub_if_list, list) { | 2680 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
2681 | 2681 | ||
2682 | /* No need to wake the master device. */ | 2682 | /* No need to wake the master device. */ |
2683 | if (sdata->dev == local->mdev) | 2683 | if (sdata->dev == local->mdev) |
@@ -2691,7 +2691,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) | |||
2691 | 2691 | ||
2692 | netif_wake_queue(sdata->dev); | 2692 | netif_wake_queue(sdata->dev); |
2693 | } | 2693 | } |
2694 | read_unlock(&local->sub_if_lock); | 2694 | rcu_read_unlock(); |
2695 | 2695 | ||
2696 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 2696 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
2697 | if (sdata->type == IEEE80211_IF_TYPE_IBSS) { | 2697 | if (sdata->type == IEEE80211_IF_TYPE_IBSS) { |
@@ -2828,8 +2828,8 @@ static int ieee80211_sta_start_scan(struct net_device *dev, | |||
2828 | 2828 | ||
2829 | local->sta_scanning = 1; | 2829 | local->sta_scanning = 1; |
2830 | 2830 | ||
2831 | read_lock(&local->sub_if_lock); | 2831 | rcu_read_lock(); |
2832 | list_for_each_entry(sdata, &local->sub_if_list, list) { | 2832 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
2833 | 2833 | ||
2834 | /* Don't stop the master interface, otherwise we can't transmit | 2834 | /* Don't stop the master interface, otherwise we can't transmit |
2835 | * probes! */ | 2835 | * probes! */ |
@@ -2841,7 +2841,7 @@ static int ieee80211_sta_start_scan(struct net_device *dev, | |||
2841 | (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)) | 2841 | (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)) |
2842 | ieee80211_send_nullfunc(local, sdata, 1); | 2842 | ieee80211_send_nullfunc(local, sdata, 1); |
2843 | } | 2843 | } |
2844 | read_unlock(&local->sub_if_lock); | 2844 | rcu_read_unlock(); |
2845 | 2845 | ||
2846 | if (ssid) { | 2846 | if (ssid) { |
2847 | local->scan_ssid_len = ssid_len; | 2847 | local->scan_ssid_len = ssid_len; |