aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/cfg80211.h4
-rw-r--r--net/wireless/core.c24
-rw-r--r--net/wireless/core.h14
-rw-r--r--net/wireless/util.c5
4 files changed, 47 insertions, 0 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index e030c6af86dd..f0d213dd8fe7 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1499,6 +1499,8 @@ struct cfg80211_gtk_rekey_data {
1499 * interfaces are active this callback should reject the configuration. 1499 * interfaces are active this callback should reject the configuration.
1500 * If no interfaces are active or the device is down, the channel should 1500 * If no interfaces are active or the device is down, the channel should
1501 * be stored for when a monitor interface becomes active. 1501 * be stored for when a monitor interface becomes active.
1502 * @set_monitor_enabled: Notify driver that there are only monitor
1503 * interfaces running.
1502 * @get_channel: Get the current operating channel, should return %NULL if 1504 * @get_channel: Get the current operating channel, should return %NULL if
1503 * there's no single defined operating channel if for example the 1505 * there's no single defined operating channel if for example the
1504 * device implements channel hopping for multi-channel virtual interfaces. 1506 * device implements channel hopping for multi-channel virtual interfaces.
@@ -1817,6 +1819,8 @@ struct cfg80211_ops {
1817 struct ethtool_stats *stats, u64 *data); 1819 struct ethtool_stats *stats, u64 *data);
1818 void (*get_et_strings)(struct wiphy *wiphy, struct net_device *dev, 1820 void (*get_et_strings)(struct wiphy *wiphy, struct net_device *dev,
1819 u32 sset, u8 *data); 1821 u32 sset, u8 *data);
1822
1823 void (*set_monitor_enabled)(struct wiphy *wiphy, bool enabled);
1820}; 1824};
1821 1825
1822/* 1826/*
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 = {
717 .name = "wlan", 717 .name = "wlan",
718}; 718};
719 719
720void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
721 enum nl80211_iftype iftype, int num)
722{
723 bool has_monitors_only_old = cfg80211_has_monitors_only(rdev);
724 bool has_monitors_only_new;
725
726 ASSERT_RDEV_LOCK(rdev);
727
728 rdev->num_running_ifaces += num;
729 if (iftype == NL80211_IFTYPE_MONITOR)
730 rdev->num_running_monitor_ifaces += num;
731
732 has_monitors_only_new = cfg80211_has_monitors_only(rdev);
733 if (has_monitors_only_new != has_monitors_only_old)
734 rdev->ops->set_monitor_enabled(&rdev->wiphy,
735 has_monitors_only_new);
736}
737
720static int cfg80211_netdev_notifier_call(struct notifier_block *nb, 738static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
721 unsigned long state, 739 unsigned long state,
722 void *ndev) 740 void *ndev)
@@ -820,6 +838,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
820 break; 838 break;
821 case NETDEV_DOWN: 839 case NETDEV_DOWN:
822 dev_hold(dev); 840 dev_hold(dev);
841 cfg80211_lock_rdev(rdev);
842 cfg80211_update_iface_num(rdev, wdev->iftype, -1);
843 cfg80211_unlock_rdev(rdev);
823 queue_work(cfg80211_wq, &wdev->cleanup_work); 844 queue_work(cfg80211_wq, &wdev->cleanup_work);
824 break; 845 break;
825 case NETDEV_UP: 846 case NETDEV_UP:
@@ -927,6 +948,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
927 ret = cfg80211_can_add_interface(rdev, wdev->iftype); 948 ret = cfg80211_can_add_interface(rdev, wdev->iftype);
928 if (ret) 949 if (ret)
929 return notifier_from_errno(ret); 950 return notifier_from_errno(ret);
951 cfg80211_lock_rdev(rdev);
952 cfg80211_update_iface_num(rdev, wdev->iftype, 1);
953 cfg80211_unlock_rdev(rdev);
930 break; 954 break;
931 } 955 }
932 956
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 {
56 56
57 u32 ap_beacons_nlpid; 57 u32 ap_beacons_nlpid;
58 58
59 int num_running_ifaces;
60 int num_running_monitor_ifaces;
61
59 /* BSSes/scanning */ 62 /* BSSes/scanning */
60 spinlock_t bss_lock; 63 spinlock_t bss_lock;
61 struct list_head bss_list; 64 struct list_head bss_list;
@@ -197,6 +200,14 @@ static inline void wdev_unlock(struct wireless_dev *wdev)
197#define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx) 200#define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx)
198#define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) 201#define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx)
199 202
203static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev)
204{
205 ASSERT_RDEV_LOCK(rdev);
206
207 return rdev->num_running_ifaces == rdev->num_running_monitor_ifaces &&
208 rdev->num_running_ifaces > 0;
209}
210
200enum cfg80211_event_type { 211enum cfg80211_event_type {
201 EVENT_CONNECT_RESULT, 212 EVENT_CONNECT_RESULT,
202 EVENT_ROAMED, 213 EVENT_ROAMED,
@@ -444,6 +455,9 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
444int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, 455int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
445 u32 beacon_int); 456 u32 beacon_int);
446 457
458void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
459 enum nl80211_iftype iftype, int num);
460
447#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS 461#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
448#define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) 462#define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond)
449#else 463#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,
871 } 871 }
872 } 872 }
873 873
874 if (!err && ntype != otype && netif_running(dev)) {
875 cfg80211_update_iface_num(rdev, ntype, 1);
876 cfg80211_update_iface_num(rdev, otype, -1);
877 }
878
874 return err; 879 return err;
875} 880}
876 881