aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-02-07 21:37:29 +0100
committerJohannes Berg <johannes.berg@intel.com>2013-02-15 09:41:36 +0100
commit2c9b735982ee8a2d34e7eeb3e26b683f81872fdb (patch)
treef2f0f0b741aa0b1ffaa2a95c0533d1eeba745868 /net
parentf2d9330ee820b01e2b1caf46370bc7963d259908 (diff)
mac80211: add ieee80211_vif_change_bandwidth
For HT and VHT the current bandwidth can change, add the function ieee80211_vif_change_bandwidth() to take care of this. It returns a failure if the new bandwidth isn't compatible with the existing channel context, the caller has to handle that. When it happens, also inform the driver that the bandwidth changed for this virtual interface (no drivers would actually care today though.) Changing to/from HT/VHT isn't allowed though. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/chan.c49
-rw-r--r--net/mac80211/ieee80211_i.h4
2 files changed, 53 insertions, 0 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 78dbb371f16..78c0d90dd64 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -375,6 +375,55 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
return ret;
}
+int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
+ const struct cfg80211_chan_def *chandef,
+ u32 *changed)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_chanctx_conf *conf;
+ struct ieee80211_chanctx *ctx;
+ int ret;
+
+ if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
+ IEEE80211_CHAN_DISABLED))
+ return -EINVAL;
+
+ mutex_lock(&local->chanctx_mtx);
+ if (cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef)) {
+ ret = 0;
+ goto out;
+ }
+
+ if (chandef->width == NL80211_CHAN_WIDTH_20_NOHT ||
+ sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+ lockdep_is_held(&local->chanctx_mtx));
+ if (!conf) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ctx = container_of(conf, struct ieee80211_chanctx, conf);
+ if (!cfg80211_chandef_compatible(&conf->def, chandef)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ sdata->vif.bss_conf.chandef = *chandef;
+
+ ieee80211_recalc_chanctx_chantype(local, ctx);
+
+ *changed |= BSS_CHANGED_BANDWIDTH;
+ ret = 0;
+ out:
+ mutex_unlock(&local->chanctx_mtx);
+ return ret;
+}
+
void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
{
WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 892bac64a18..d1074442f1b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1613,6 +1613,10 @@ int __must_check
ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode);
+int __must_check
+ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
+ const struct cfg80211_chan_def *chandef,
+ u32 *changed);
void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,