mac80211: add ieee80211_vif_change_bandwidth
authorJohannes Berg <johannes.berg@intel.com>
Thu, 7 Feb 2013 20:37:29 +0000 (21:37 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 15 Feb 2013 08:41:36 +0000 (09:41 +0100)
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>
include/net/mac80211.h
net/mac80211/chan.c
net/mac80211/ieee80211_i.h

index b7fb311e83f40fe33c9d7366740131f86a91218b..54e2add8429f86b3b96cff8aba11c122be9c2f4a 100644 (file)
@@ -215,6 +215,9 @@ struct ieee80211_chanctx_conf {
  *     changed (currently only in P2P client mode, GO mode will be later)
  * @BSS_CHANGED_DTIM_PERIOD: the DTIM period value was changed (set when
  *     it becomes valid, managed mode only)
+ * @BSS_CHANGED_BANDWIDTH: The bandwidth used by this interface changed,
+ *     note that this is only called when it changes after the channel
+ *     context had been assigned.
  */
 enum ieee80211_bss_change {
        BSS_CHANGED_ASSOC               = 1<<0,
@@ -238,6 +241,7 @@ enum ieee80211_bss_change {
        BSS_CHANGED_TXPOWER             = 1<<18,
        BSS_CHANGED_P2P_PS              = 1<<19,
        BSS_CHANGED_DTIM_PERIOD         = 1<<20,
+       BSS_CHANGED_BANDWIDTH           = 1<<21,
 
        /* when adding here, make sure to change ieee80211_reconfig */
 };
index 78dbb371f16e7df2841b47c41c1f0ed074218577..78c0d90dd641e459dcec9972be0d97634d58a5c6 100644 (file)
@@ -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));
index 892bac64a189d058d9344fd9a447ae3307b5b03b..d1074442f1b54bb1a47a706018e1492e41445573 100644 (file)
@@ -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,