Skip to content

Commit

Permalink
cfg80211: fix locking regression in monitor channel tracking
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johannes Berg committed Jul 4, 2012
1 parent a1845fc commit c5a7e58
Show file tree
Hide file tree
Showing 2 changed files with 5 additions and 7 deletions.
8 changes: 2 additions & 6 deletions net/wireless/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
bool has_monitors_only_old = cfg80211_has_monitors_only(rdev);
bool has_monitors_only_new;

ASSERT_RDEV_LOCK(rdev);
ASSERT_RTNL();

rdev->num_running_ifaces += num;
if (iftype == NL80211_IFTYPE_MONITOR)
Expand Down Expand Up @@ -888,10 +888,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
wdev->beacon_interval = 0;
break;
case NETDEV_DOWN:
dev_hold(dev);
cfg80211_lock_rdev(rdev);
cfg80211_update_iface_num(rdev, wdev->iftype, -1);
cfg80211_unlock_rdev(rdev);
dev_hold(dev);
queue_work(cfg80211_wq, &wdev->cleanup_work);
break;
case NETDEV_UP:
Expand Down Expand Up @@ -1001,9 +999,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
mutex_unlock(&rdev->devlist_mtx);
if (ret)
return notifier_from_errno(ret);
cfg80211_lock_rdev(rdev);
cfg80211_update_iface_num(rdev, wdev->iftype, 1);
cfg80211_unlock_rdev(rdev);
break;
}

Expand Down
4 changes: 3 additions & 1 deletion net/wireless/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <linux/debugfs.h>
#include <linux/rfkill.h>
#include <linux/workqueue.h>
#include <linux/rtnetlink.h>
#include <net/genetlink.h>
#include <net/cfg80211.h>
#include "reg.h"
Expand Down Expand Up @@ -56,6 +57,7 @@ struct cfg80211_registered_device {

u32 ap_beacons_nlpid;

/* protected by RTNL only */
int num_running_ifaces;
int num_running_monitor_ifaces;

Expand Down Expand Up @@ -205,7 +207,7 @@ static inline void wdev_unlock(struct wireless_dev *wdev)

static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev)
{
ASSERT_RDEV_LOCK(rdev);
ASSERT_RTNL();

return rdev->num_running_ifaces == rdev->num_running_monitor_ifaces &&
rdev->num_running_ifaces > 0;
Expand Down

0 comments on commit c5a7e58

Please sign in to comment.