aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-07-04 07:28:18 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-07-04 07:30:23 -0400
commitc5a7e582490c423f0685e42ee5cfb7c6de81adb0 (patch)
tree6eda6d23264d9f434e6e92445168e55c16ea3300 /net/wireless
parenta1845fc7c552977e23fe552ad3f5c6c279e3d550 (diff)
cfg80211: fix locking regression in monitor channel tracking
Michal's monitor channel tracking introduce a locking problem as it locked the rdev lock inside the netdev notifier which isn't allowed as we might already hold it if we get there by removing an interface that is up. Fix this by relying only on the RTNL to protect the interface counters, the RTNL is always held in these code paths anyway. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/core.c8
-rw-r--r--net/wireless/core.h4
2 files changed, 5 insertions, 7 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index e13365f1fa63..eb60410ae588 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -766,7 +766,7 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
766 bool has_monitors_only_old = cfg80211_has_monitors_only(rdev); 766 bool has_monitors_only_old = cfg80211_has_monitors_only(rdev);
767 bool has_monitors_only_new; 767 bool has_monitors_only_new;
768 768
769 ASSERT_RDEV_LOCK(rdev); 769 ASSERT_RTNL();
770 770
771 rdev->num_running_ifaces += num; 771 rdev->num_running_ifaces += num;
772 if (iftype == NL80211_IFTYPE_MONITOR) 772 if (iftype == NL80211_IFTYPE_MONITOR)
@@ -888,10 +888,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
888 wdev->beacon_interval = 0; 888 wdev->beacon_interval = 0;
889 break; 889 break;
890 case NETDEV_DOWN: 890 case NETDEV_DOWN:
891 dev_hold(dev);
892 cfg80211_lock_rdev(rdev);
893 cfg80211_update_iface_num(rdev, wdev->iftype, -1); 891 cfg80211_update_iface_num(rdev, wdev->iftype, -1);
894 cfg80211_unlock_rdev(rdev); 892 dev_hold(dev);
895 queue_work(cfg80211_wq, &wdev->cleanup_work); 893 queue_work(cfg80211_wq, &wdev->cleanup_work);
896 break; 894 break;
897 case NETDEV_UP: 895 case NETDEV_UP:
@@ -1001,9 +999,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
1001 mutex_unlock(&rdev->devlist_mtx); 999 mutex_unlock(&rdev->devlist_mtx);
1002 if (ret) 1000 if (ret)
1003 return notifier_from_errno(ret); 1001 return notifier_from_errno(ret);
1004 cfg80211_lock_rdev(rdev);
1005 cfg80211_update_iface_num(rdev, wdev->iftype, 1); 1002 cfg80211_update_iface_num(rdev, wdev->iftype, 1);
1006 cfg80211_unlock_rdev(rdev);
1007 break; 1003 break;
1008 } 1004 }
1009 1005
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 81fef3ddb5a8..377dc394f48c 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -13,6 +13,7 @@
13#include <linux/debugfs.h> 13#include <linux/debugfs.h>
14#include <linux/rfkill.h> 14#include <linux/rfkill.h>
15#include <linux/workqueue.h> 15#include <linux/workqueue.h>
16#include <linux/rtnetlink.h>
16#include <net/genetlink.h> 17#include <net/genetlink.h>
17#include <net/cfg80211.h> 18#include <net/cfg80211.h>
18#include "reg.h" 19#include "reg.h"
@@ -56,6 +57,7 @@ struct cfg80211_registered_device {
56 57
57 u32 ap_beacons_nlpid; 58 u32 ap_beacons_nlpid;
58 59
60 /* protected by RTNL only */
59 int num_running_ifaces; 61 int num_running_ifaces;
60 int num_running_monitor_ifaces; 62 int num_running_monitor_ifaces;
61 63
@@ -205,7 +207,7 @@ static inline void wdev_unlock(struct wireless_dev *wdev)
205 207
206static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev) 208static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev)
207{ 209{
208 ASSERT_RDEV_LOCK(rdev); 210 ASSERT_RTNL();
209 211
210 return rdev->num_running_ifaces == rdev->num_running_monitor_ifaces && 212 return rdev->num_running_ifaces == rdev->num_running_monitor_ifaces &&
211 rdev->num_running_ifaces > 0; 213 rdev->num_running_ifaces > 0;