summaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/core.c24
-rw-r--r--net/wireless/core.h14
-rw-r--r--net/wireless/util.c5
3 files changed, 43 insertions, 0 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index c65f59c952c9..8412da7d0f25 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -717,6 +717,24 @@ static struct device_type wiphy_type = {
.name = "wlan",
};
+void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
+ enum nl80211_iftype iftype, int num)
+{
+ bool has_monitors_only_old = cfg80211_has_monitors_only(rdev);
+ bool has_monitors_only_new;
+
+ ASSERT_RDEV_LOCK(rdev);
+
+ rdev->num_running_ifaces += num;
+ if (iftype == NL80211_IFTYPE_MONITOR)
+ rdev->num_running_monitor_ifaces += num;
+
+ has_monitors_only_new = cfg80211_has_monitors_only(rdev);
+ if (has_monitors_only_new != has_monitors_only_old)
+ rdev->ops->set_monitor_enabled(&rdev->wiphy,
+ has_monitors_only_new);
+}
+
static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
unsigned long state,
void *ndev)
@@ -820,6 +838,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
break;
case NETDEV_DOWN:
dev_hold(dev);
+ cfg80211_lock_rdev(rdev);
+ cfg80211_update_iface_num(rdev, wdev->iftype, -1);
+ cfg80211_unlock_rdev(rdev);
queue_work(cfg80211_wq, &wdev->cleanup_work);
break;
case NETDEV_UP:
@@ -927,6 +948,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
ret = cfg80211_can_add_interface(rdev, wdev->iftype);
if (ret)
return notifier_from_errno(ret);
+ cfg80211_lock_rdev(rdev);
+ cfg80211_update_iface_num(rdev, wdev->iftype, 1);
+ cfg80211_unlock_rdev(rdev);
break;
}
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 56f18c2eb919..99acd51343b1 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -56,6 +56,9 @@ struct cfg80211_registered_device {
u32 ap_beacons_nlpid;
+ int num_running_ifaces;
+ int num_running_monitor_ifaces;
+
/* BSSes/scanning */
spinlock_t bss_lock;
struct list_head bss_list;
@@ -197,6 +200,14 @@ static inline void wdev_unlock(struct wireless_dev *wdev)
#define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx)
#define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx)
+static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev)
+{
+ ASSERT_RDEV_LOCK(rdev);
+
+ return rdev->num_running_ifaces == rdev->num_running_monitor_ifaces &&
+ rdev->num_running_ifaces > 0;
+}
+
enum cfg80211_event_type {
EVENT_CONNECT_RESULT,
EVENT_ROAMED,
@@ -444,6 +455,9 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
u32 beacon_int);
+void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
+ enum nl80211_iftype iftype, int num);
+
#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
#define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond)
#else
diff --git a/net/wireless/util.c b/net/wireless/util.c
index fc948d0a53f3..9b92ec57d07b 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -871,6 +871,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
}
}
+ if (!err && ntype != otype && netif_running(dev)) {
+ cfg80211_update_iface_num(rdev, ntype, 1);
+ cfg80211_update_iface_num(rdev, otype, -1);
+ }
+
return err;
}