#include <net/cfg80211.h>
 #include "ieee80211_i.h"
 #include "driver-ops.h"
+#include "rate.h"
 
 static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
                                          struct ieee80211_chanctx *ctx)
        drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_MIN_WIDTH);
 }
 
+static void ieee80211_chan_bw_change(struct ieee80211_local *local,
+                                    struct ieee80211_chanctx *ctx)
+{
+       struct sta_info *sta;
+       struct ieee80211_supported_band *sband =
+               local->hw.wiphy->bands[ctx->conf.def.chan->band];
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sta, &local->sta_list,
+                               list) {
+               enum ieee80211_sta_rx_bandwidth new_sta_bw;
+
+               if (!ieee80211_sdata_running(sta->sdata))
+                       continue;
+
+               if (rcu_access_pointer(sta->sdata->vif.chanctx_conf) !=
+                   &ctx->conf)
+                       continue;
+
+               new_sta_bw = ieee80211_sta_cur_vht_bw(sta);
+               if (new_sta_bw == sta->sta.bandwidth)
+                       continue;
+
+               sta->sta.bandwidth = new_sta_bw;
+               rate_control_rate_update(local, sband, sta,
+                                        IEEE80211_RC_BW_CHANGED);
+       }
+       rcu_read_unlock();
+}
+
 static void ieee80211_change_chanctx(struct ieee80211_local *local,
                                     struct ieee80211_chanctx *ctx,
                                     const struct cfg80211_chan_def *chandef)
 {
+       enum nl80211_chan_width width;
+
        if (cfg80211_chandef_identical(&ctx->conf.def, chandef)) {
                ieee80211_recalc_chanctx_min_def(local, ctx);
                return;
 
        WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef));
 
+       width = ctx->conf.def.width;
        ctx->conf.def = *chandef;
+
+       /* expected to handle only 20/40/80/160 channel widths */
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_20_NOHT:
+       case NL80211_CHAN_WIDTH_20:
+       case NL80211_CHAN_WIDTH_40:
+       case NL80211_CHAN_WIDTH_80:
+       case NL80211_CHAN_WIDTH_80P80:
+       case NL80211_CHAN_WIDTH_160:
+               break;
+       default:
+               WARN_ON(1);
+       }
+
+       if (chandef->width < width)
+               ieee80211_chan_bw_change(local, ctx);
+
        drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH);
        ieee80211_recalc_chanctx_min_def(local, ctx);
 
                local->_oper_chandef = *chandef;
                ieee80211_hw_config(local, 0);
        }
+
+       if (chandef->width > width)
+               ieee80211_chan_bw_change(local, ctx);
 }
 
 static struct ieee80211_chanctx *
        if (WARN_ON(!chandef))
                return -EINVAL;
 
+       if (old_ctx->conf.def.width > new_ctx->conf.def.width)
+               ieee80211_chan_bw_change(local, new_ctx);
+
        ieee80211_change_chanctx(local, new_ctx, chandef);
 
+       if (old_ctx->conf.def.width < new_ctx->conf.def.width)
+               ieee80211_chan_bw_change(local, new_ctx);
+
        vif_chsw[0].vif = &sdata->vif;
        vif_chsw[0].old_ctx = &old_ctx->conf;
        vif_chsw[0].new_ctx = &new_ctx->conf;
                ieee80211_recalc_smps_chanctx(local, ctx);
                ieee80211_recalc_radar_chanctx(local, ctx);
                ieee80211_recalc_chanctx_min_def(local, ctx);
+               ieee80211_chan_bw_change(local, ctx);
 
                list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs,
                                         reserved_chanctx_list) {