aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-07-26 14:55:08 +0200
committerJohannes Berg <johannes.berg@intel.com>2012-10-16 20:22:46 +0200
commitfe57d9f5c0a2c1ef97ba8cdc42cfda5743f287b8 (patch)
treea155a8bb9165b092703bec542aeaf0b707afa392 /net/mac80211
parentmac80211: check channel context methods (diff)
downloadlinux-dev-fe57d9f5c0a2c1ef97ba8cdc42cfda5743f287b8.tar.xz
linux-dev-fe57d9f5c0a2c1ef97ba8cdc42cfda5743f287b8.zip
mac80211: track whether to use channel contexts
Depending on the driver, channel contexts may be used or not. If they are used, the driver must have support for hardware scan and remain-on-channel; otherwise the driver must not advertise support for multiple channels. Also prohibit WDS type interfaces when channel contexts are to be used as there's no clear definition of which channel they use. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/cfg.c3
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/main.c22
-rw-r--r--net/mac80211/offchannel.c6
-rw-r--r--net/mac80211/scan.c4
5 files changed, 37 insertions, 0 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 05f3a313db88..70a5d262815f 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2189,6 +2189,9 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
lockdep_assert_held(&local->mtx);
+ if (local->use_chanctx && !local->ops->remain_on_channel)
+ return -EOPNOTSUPP;
+
roc = kzalloc(sizeof(*roc), GFP_KERNEL);
if (!roc)
return -ENOMEM;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9a058e58d53e..8fa00adcb8c0 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -882,6 +882,8 @@ struct ieee80211_local {
bool wiphy_ciphers_allocated;
+ bool use_chanctx;
+
/* protects the aggregated multicast list and filter calls */
spinlock_t filter_lock;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index d709a5d42f69..0dd1ea241c54 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -540,6 +540,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
struct ieee80211_local *local;
int priv_size, i;
struct wiphy *wiphy;
+ bool use_chanctx;
if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config ||
!ops->add_interface || !ops->remove_interface ||
@@ -555,6 +556,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
!!ops->unassign_vif_chanctx;
if (WARN_ON(i != 0 && i != 5))
return NULL;
+ use_chanctx = i == 5;
/* Ensure 32-byte alignment of our private data and hw private data.
* We use the wiphy priv data for both our ieee80211_local and for
@@ -606,6 +608,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
local->ops = ops;
+ local->use_chanctx = use_chanctx;
/* set up some defaults */
local->hw.queues = 1;
@@ -729,6 +732,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan)
return -EINVAL;
+ if (!local->use_chanctx) {
+ for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
+ const struct ieee80211_iface_combination *comb;
+
+ comb = &local->hw.wiphy->iface_combinations[i];
+
+ if (comb->num_different_channels > 1)
+ return -EINVAL;
+ }
+
+ /*
+ * WDS is currently prohibited when channel contexts are used
+ * because there's no clear definition of which channel WDS
+ * type interfaces use
+ */
+ if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS))
+ return -EINVAL;
+ }
+
/* Only HW csum features are currently compatible with mac80211 */
feature_whitelist = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_HW_CSUM;
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index 83608ac16780..9c52fc4a045e 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -107,6 +107,9 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
{
struct ieee80211_sub_if_data *sdata;
+ if (WARN_ON(local->use_chanctx))
+ return;
+
/*
* notify the AP about us leaving the channel and stop all
* STA interfaces.
@@ -145,6 +148,9 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
{
struct ieee80211_sub_if_data *sdata;
+ if (WARN_ON(local->use_chanctx))
+ return;
+
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index c4cdbde24fd3..fdaa505dab45 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -336,6 +336,10 @@ EXPORT_SYMBOL(ieee80211_scan_completed);
static int ieee80211_start_sw_scan(struct ieee80211_local *local)
{
+ /* Software scan is not supported in multi-channel cases */
+ if (local->use_chanctx)
+ return -EOPNOTSUPP;
+
/*
* Hardware/driver doesn't support hw_scan, so use software
* scanning instead. First send a nullfunc frame with power save