aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/core.c')
-rw-r--r--net/wireless/core.c84
1 files changed, 82 insertions, 2 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 907f62c80e28..eb60410ae588 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -373,6 +373,14 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
if (WARN_ON(!c->num_different_channels))
return -EINVAL;
+ /*
+ * Put a sane limit on maximum number of different
+ * channels to simplify channel accounting code.
+ */
+ if (WARN_ON(c->num_different_channels >
+ CFG80211_MAX_NUM_DIFFERENT_CHANNELS))
+ return -EINVAL;
+
if (WARN_ON(!c->n_limits))
return -EINVAL;
@@ -421,9 +429,11 @@ int wiphy_register(struct wiphy *wiphy)
int i;
u16 ifmodes = wiphy->interface_modes;
+#ifdef CONFIG_PM
if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
!(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY)))
return -EINVAL;
+#endif
if (WARN_ON(wiphy->ap_sme_capa &&
!(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME)))
@@ -458,8 +468,14 @@ int wiphy_register(struct wiphy *wiphy)
continue;
sband->band = band;
-
- if (WARN_ON(!sband->n_channels || !sband->n_bitrates))
+ if (WARN_ON(!sband->n_channels))
+ return -EINVAL;
+ /*
+ * on 60gHz band, there are no legacy rates, so
+ * n_bitrates is 0
+ */
+ if (WARN_ON(band != IEEE80211_BAND_60GHZ &&
+ !sband->n_bitrates))
return -EINVAL;
/*
@@ -500,12 +516,14 @@ int wiphy_register(struct wiphy *wiphy)
return -EINVAL;
}
+#ifdef CONFIG_PM
if (rdev->wiphy.wowlan.n_patterns) {
if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len ||
rdev->wiphy.wowlan.pattern_min_len >
rdev->wiphy.wowlan.pattern_max_len))
return -EINVAL;
}
+#endif
/* check and set up bitrates */
ieee80211_set_bitrate_flags(wiphy);
@@ -713,6 +731,61 @@ static struct device_type wiphy_type = {
.name = "wlan",
};
+static struct ieee80211_channel *
+cfg80211_get_any_chan(struct cfg80211_registered_device *rdev)
+{
+ struct ieee80211_supported_band *sband;
+ int i;
+
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
+ sband = rdev->wiphy.bands[i];
+ if (sband && sband->n_channels > 0)
+ return &sband->channels[0];
+ }
+
+ return NULL;
+}
+
+static void cfg80211_init_mon_chan(struct cfg80211_registered_device *rdev)
+{
+ struct ieee80211_channel *chan;
+
+ chan = cfg80211_get_any_chan(rdev);
+ if (WARN_ON(!chan))
+ return;
+
+ mutex_lock(&rdev->devlist_mtx);
+ WARN_ON(cfg80211_set_monitor_channel(rdev, chan->center_freq,
+ NL80211_CHAN_NO_HT));
+ mutex_unlock(&rdev->devlist_mtx);
+}
+
+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_RTNL();
+
+ 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);
+
+ if (!has_monitors_only_new) {
+ rdev->monitor_channel = NULL;
+ rdev->monitor_channel_type = NL80211_CHAN_NO_HT;
+ } else {
+ cfg80211_init_mon_chan(rdev);
+ }
+ }
+}
+
static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
unsigned long state,
void *ndev)
@@ -806,12 +879,16 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
case NL80211_IFTYPE_MESH_POINT:
cfg80211_leave_mesh(rdev, dev);
break;
+ case NL80211_IFTYPE_AP:
+ cfg80211_stop_ap(rdev, dev);
+ break;
default:
break;
}
wdev->beacon_interval = 0;
break;
case NETDEV_DOWN:
+ cfg80211_update_iface_num(rdev, wdev->iftype, -1);
dev_hold(dev);
queue_work(cfg80211_wq, &wdev->cleanup_work);
break;
@@ -917,9 +994,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
return notifier_from_errno(-EOPNOTSUPP);
if (rfkill_blocked(rdev->rfkill))
return notifier_from_errno(-ERFKILL);
+ mutex_lock(&rdev->devlist_mtx);
ret = cfg80211_can_add_interface(rdev, wdev->iftype);
+ mutex_unlock(&rdev->devlist_mtx);
if (ret)
return notifier_from_errno(ret);
+ cfg80211_update_iface_num(rdev, wdev->iftype, 1);
break;
}