Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * mac80211 - channel management
0004  * Copyright 2020 - 2022 Intel Corporation
0005  */
0006 
0007 #include <linux/nl80211.h>
0008 #include <linux/export.h>
0009 #include <linux/rtnetlink.h>
0010 #include <net/cfg80211.h>
0011 #include "ieee80211_i.h"
0012 #include "driver-ops.h"
0013 #include "rate.h"
0014 
0015 static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
0016                       struct ieee80211_chanctx *ctx)
0017 {
0018     struct ieee80211_link_data *link;
0019     int num = 0;
0020 
0021     lockdep_assert_held(&local->chanctx_mtx);
0022 
0023     list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list)
0024         num++;
0025 
0026     return num;
0027 }
0028 
0029 static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local,
0030                       struct ieee80211_chanctx *ctx)
0031 {
0032     struct ieee80211_link_data *link;
0033     int num = 0;
0034 
0035     lockdep_assert_held(&local->chanctx_mtx);
0036 
0037     list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list)
0038         num++;
0039 
0040     return num;
0041 }
0042 
0043 int ieee80211_chanctx_refcount(struct ieee80211_local *local,
0044                    struct ieee80211_chanctx *ctx)
0045 {
0046     return ieee80211_chanctx_num_assigned(local, ctx) +
0047            ieee80211_chanctx_num_reserved(local, ctx);
0048 }
0049 
0050 static int ieee80211_num_chanctx(struct ieee80211_local *local)
0051 {
0052     struct ieee80211_chanctx *ctx;
0053     int num = 0;
0054 
0055     lockdep_assert_held(&local->chanctx_mtx);
0056 
0057     list_for_each_entry(ctx, &local->chanctx_list, list)
0058         num++;
0059 
0060     return num;
0061 }
0062 
0063 static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
0064 {
0065     lockdep_assert_held(&local->chanctx_mtx);
0066     return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
0067 }
0068 
0069 static struct ieee80211_chanctx *
0070 ieee80211_link_get_chanctx(struct ieee80211_link_data *link)
0071 {
0072     struct ieee80211_local *local __maybe_unused = link->sdata->local;
0073     struct ieee80211_chanctx_conf *conf;
0074 
0075     conf = rcu_dereference_protected(link->conf->chanctx_conf,
0076                      lockdep_is_held(&local->chanctx_mtx));
0077     if (!conf)
0078         return NULL;
0079 
0080     return container_of(conf, struct ieee80211_chanctx, conf);
0081 }
0082 
0083 static const struct cfg80211_chan_def *
0084 ieee80211_chanctx_reserved_chandef(struct ieee80211_local *local,
0085                    struct ieee80211_chanctx *ctx,
0086                    const struct cfg80211_chan_def *compat)
0087 {
0088     struct ieee80211_link_data *link;
0089 
0090     lockdep_assert_held(&local->chanctx_mtx);
0091 
0092     list_for_each_entry(link, &ctx->reserved_links,
0093                 reserved_chanctx_list) {
0094         if (!compat)
0095             compat = &link->reserved_chandef;
0096 
0097         compat = cfg80211_chandef_compatible(&link->reserved_chandef,
0098                              compat);
0099         if (!compat)
0100             break;
0101     }
0102 
0103     return compat;
0104 }
0105 
0106 static const struct cfg80211_chan_def *
0107 ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,
0108                        struct ieee80211_chanctx *ctx,
0109                        const struct cfg80211_chan_def *compat)
0110 {
0111     struct ieee80211_link_data *link;
0112 
0113     lockdep_assert_held(&local->chanctx_mtx);
0114 
0115     list_for_each_entry(link, &ctx->assigned_links,
0116                 assigned_chanctx_list) {
0117         struct ieee80211_bss_conf *link_conf = link->conf;
0118 
0119         if (link->reserved_chanctx)
0120             continue;
0121 
0122         if (!compat)
0123             compat = &link_conf->chandef;
0124 
0125         compat = cfg80211_chandef_compatible(
0126                 &link_conf->chandef, compat);
0127         if (!compat)
0128             break;
0129     }
0130 
0131     return compat;
0132 }
0133 
0134 static const struct cfg80211_chan_def *
0135 ieee80211_chanctx_combined_chandef(struct ieee80211_local *local,
0136                    struct ieee80211_chanctx *ctx,
0137                    const struct cfg80211_chan_def *compat)
0138 {
0139     lockdep_assert_held(&local->chanctx_mtx);
0140 
0141     compat = ieee80211_chanctx_reserved_chandef(local, ctx, compat);
0142     if (!compat)
0143         return NULL;
0144 
0145     compat = ieee80211_chanctx_non_reserved_chandef(local, ctx, compat);
0146     if (!compat)
0147         return NULL;
0148 
0149     return compat;
0150 }
0151 
0152 static bool
0153 ieee80211_chanctx_can_reserve_chandef(struct ieee80211_local *local,
0154                       struct ieee80211_chanctx *ctx,
0155                       const struct cfg80211_chan_def *def)
0156 {
0157     lockdep_assert_held(&local->chanctx_mtx);
0158 
0159     if (ieee80211_chanctx_combined_chandef(local, ctx, def))
0160         return true;
0161 
0162     if (!list_empty(&ctx->reserved_links) &&
0163         ieee80211_chanctx_reserved_chandef(local, ctx, def))
0164         return true;
0165 
0166     return false;
0167 }
0168 
0169 static struct ieee80211_chanctx *
0170 ieee80211_find_reservation_chanctx(struct ieee80211_local *local,
0171                    const struct cfg80211_chan_def *chandef,
0172                    enum ieee80211_chanctx_mode mode)
0173 {
0174     struct ieee80211_chanctx *ctx;
0175 
0176     lockdep_assert_held(&local->chanctx_mtx);
0177 
0178     if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
0179         return NULL;
0180 
0181     list_for_each_entry(ctx, &local->chanctx_list, list) {
0182         if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
0183             continue;
0184 
0185         if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
0186             continue;
0187 
0188         if (!ieee80211_chanctx_can_reserve_chandef(local, ctx,
0189                                chandef))
0190             continue;
0191 
0192         return ctx;
0193     }
0194 
0195     return NULL;
0196 }
0197 
0198 static enum nl80211_chan_width ieee80211_get_sta_bw(struct sta_info *sta,
0199                             unsigned int link_id)
0200 {
0201     enum ieee80211_sta_rx_bandwidth width;
0202     struct link_sta_info *link_sta;
0203 
0204     link_sta = rcu_dereference(sta->link[link_id]);
0205 
0206     /* no effect if this STA has no presence on this link */
0207     if (!link_sta)
0208         return NL80211_CHAN_WIDTH_20_NOHT;
0209 
0210     width = ieee80211_sta_cap_rx_bw(link_sta);
0211 
0212     switch (width) {
0213     case IEEE80211_STA_RX_BW_20:
0214         if (link_sta->pub->ht_cap.ht_supported)
0215             return NL80211_CHAN_WIDTH_20;
0216         else
0217             return NL80211_CHAN_WIDTH_20_NOHT;
0218     case IEEE80211_STA_RX_BW_40:
0219         return NL80211_CHAN_WIDTH_40;
0220     case IEEE80211_STA_RX_BW_80:
0221         return NL80211_CHAN_WIDTH_80;
0222     case IEEE80211_STA_RX_BW_160:
0223         /*
0224          * This applied for both 160 and 80+80. since we use
0225          * the returned value to consider degradation of
0226          * ctx->conf.min_def, we have to make sure to take
0227          * the bigger one (NL80211_CHAN_WIDTH_160).
0228          * Otherwise we might try degrading even when not
0229          * needed, as the max required sta_bw returned (80+80)
0230          * might be smaller than the configured bw (160).
0231          */
0232         return NL80211_CHAN_WIDTH_160;
0233     case IEEE80211_STA_RX_BW_320:
0234         return NL80211_CHAN_WIDTH_320;
0235     default:
0236         WARN_ON(1);
0237         return NL80211_CHAN_WIDTH_20;
0238     }
0239 }
0240 
0241 static enum nl80211_chan_width
0242 ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata,
0243                   unsigned int link_id)
0244 {
0245     enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
0246     struct sta_info *sta;
0247 
0248     list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
0249         if (sdata != sta->sdata &&
0250             !(sta->sdata->bss && sta->sdata->bss == sdata->bss))
0251             continue;
0252 
0253         max_bw = max(max_bw, ieee80211_get_sta_bw(sta, link_id));
0254     }
0255 
0256     return max_bw;
0257 }
0258 
0259 static enum nl80211_chan_width
0260 ieee80211_get_chanctx_vif_max_required_bw(struct ieee80211_sub_if_data *sdata,
0261                       struct ieee80211_chanctx_conf *conf)
0262 {
0263     enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
0264     struct ieee80211_vif *vif = &sdata->vif;
0265     int link_id;
0266 
0267     rcu_read_lock();
0268     for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
0269         enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT;
0270         struct ieee80211_bss_conf *link_conf =
0271             rcu_dereference(sdata->vif.link_conf[link_id]);
0272 
0273         if (!link_conf)
0274             continue;
0275 
0276         if (rcu_access_pointer(link_conf->chanctx_conf) != conf)
0277             continue;
0278 
0279         switch (vif->type) {
0280         case NL80211_IFTYPE_AP:
0281         case NL80211_IFTYPE_AP_VLAN:
0282             width = ieee80211_get_max_required_bw(sdata, link_id);
0283             break;
0284         case NL80211_IFTYPE_STATION:
0285             /*
0286              * The ap's sta->bandwidth is not set yet at this
0287              * point, so take the width from the chandef, but
0288              * account also for TDLS peers
0289              */
0290             width = max(link_conf->chandef.width,
0291                     ieee80211_get_max_required_bw(sdata, link_id));
0292             break;
0293         case NL80211_IFTYPE_P2P_DEVICE:
0294         case NL80211_IFTYPE_NAN:
0295             continue;
0296         case NL80211_IFTYPE_ADHOC:
0297         case NL80211_IFTYPE_MESH_POINT:
0298         case NL80211_IFTYPE_OCB:
0299             width = link_conf->chandef.width;
0300             break;
0301         case NL80211_IFTYPE_WDS:
0302         case NL80211_IFTYPE_UNSPECIFIED:
0303         case NUM_NL80211_IFTYPES:
0304         case NL80211_IFTYPE_MONITOR:
0305         case NL80211_IFTYPE_P2P_CLIENT:
0306         case NL80211_IFTYPE_P2P_GO:
0307             WARN_ON_ONCE(1);
0308         }
0309 
0310         max_bw = max(max_bw, width);
0311     }
0312     rcu_read_unlock();
0313 
0314     return max_bw;
0315 }
0316 
0317 static enum nl80211_chan_width
0318 ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
0319                       struct ieee80211_chanctx_conf *conf)
0320 {
0321     struct ieee80211_sub_if_data *sdata;
0322     enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
0323 
0324     rcu_read_lock();
0325     list_for_each_entry_rcu(sdata, &local->interfaces, list) {
0326         enum nl80211_chan_width width;
0327 
0328         if (!ieee80211_sdata_running(sdata))
0329             continue;
0330 
0331         width = ieee80211_get_chanctx_vif_max_required_bw(sdata, conf);
0332 
0333         max_bw = max(max_bw, width);
0334     }
0335 
0336     /* use the configured bandwidth in case of monitor interface */
0337     sdata = rcu_dereference(local->monitor_sdata);
0338     if (sdata &&
0339         rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == conf)
0340         max_bw = max(max_bw, conf->def.width);
0341 
0342     rcu_read_unlock();
0343 
0344     return max_bw;
0345 }
0346 
0347 /*
0348  * recalc the min required chan width of the channel context, which is
0349  * the max of min required widths of all the interfaces bound to this
0350  * channel context.
0351  */
0352 static u32 _ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
0353                          struct ieee80211_chanctx *ctx)
0354 {
0355     enum nl80211_chan_width max_bw;
0356     struct cfg80211_chan_def min_def;
0357 
0358     lockdep_assert_held(&local->chanctx_mtx);
0359 
0360     /* don't optimize non-20MHz based and radar_enabled confs */
0361     if (ctx->conf.def.width == NL80211_CHAN_WIDTH_5 ||
0362         ctx->conf.def.width == NL80211_CHAN_WIDTH_10 ||
0363         ctx->conf.def.width == NL80211_CHAN_WIDTH_1 ||
0364         ctx->conf.def.width == NL80211_CHAN_WIDTH_2 ||
0365         ctx->conf.def.width == NL80211_CHAN_WIDTH_4 ||
0366         ctx->conf.def.width == NL80211_CHAN_WIDTH_8 ||
0367         ctx->conf.def.width == NL80211_CHAN_WIDTH_16 ||
0368         ctx->conf.radar_enabled) {
0369         ctx->conf.min_def = ctx->conf.def;
0370         return 0;
0371     }
0372 
0373     max_bw = ieee80211_get_chanctx_max_required_bw(local, &ctx->conf);
0374 
0375     /* downgrade chandef up to max_bw */
0376     min_def = ctx->conf.def;
0377     while (min_def.width > max_bw)
0378         ieee80211_chandef_downgrade(&min_def);
0379 
0380     if (cfg80211_chandef_identical(&ctx->conf.min_def, &min_def))
0381         return 0;
0382 
0383     ctx->conf.min_def = min_def;
0384     if (!ctx->driver_present)
0385         return 0;
0386 
0387     return IEEE80211_CHANCTX_CHANGE_MIN_WIDTH;
0388 }
0389 
0390 /* calling this function is assuming that station vif is updated to
0391  * lates changes by calling ieee80211_link_update_chandef
0392  */
0393 static void ieee80211_chan_bw_change(struct ieee80211_local *local,
0394                      struct ieee80211_chanctx *ctx,
0395                      bool narrowed)
0396 {
0397     struct sta_info *sta;
0398     struct ieee80211_supported_band *sband =
0399         local->hw.wiphy->bands[ctx->conf.def.chan->band];
0400 
0401     rcu_read_lock();
0402     list_for_each_entry_rcu(sta, &local->sta_list,
0403                 list) {
0404         struct ieee80211_sub_if_data *sdata = sta->sdata;
0405         enum ieee80211_sta_rx_bandwidth new_sta_bw;
0406         unsigned int link_id;
0407 
0408         if (!ieee80211_sdata_running(sta->sdata))
0409             continue;
0410 
0411         for (link_id = 0; link_id < ARRAY_SIZE(sta->sdata->link); link_id++) {
0412             struct ieee80211_bss_conf *link_conf =
0413                 rcu_dereference(sdata->vif.link_conf[link_id]);
0414             struct link_sta_info *link_sta;
0415 
0416             if (!link_conf)
0417                 continue;
0418 
0419             if (rcu_access_pointer(link_conf->chanctx_conf) != &ctx->conf)
0420                 continue;
0421 
0422             link_sta = rcu_dereference(sta->link[link_id]);
0423             if (!link_sta)
0424                 continue;
0425 
0426             new_sta_bw = ieee80211_sta_cur_vht_bw(link_sta);
0427 
0428             /* nothing change */
0429             if (new_sta_bw == link_sta->pub->bandwidth)
0430                 continue;
0431 
0432             /* vif changed to narrow BW and narrow BW for station wasn't
0433              * requested or vise versa */
0434             if ((new_sta_bw < link_sta->pub->bandwidth) == !narrowed)
0435                 continue;
0436 
0437             link_sta->pub->bandwidth = new_sta_bw;
0438             rate_control_rate_update(local, sband, sta, link_id,
0439                          IEEE80211_RC_BW_CHANGED);
0440         }
0441     }
0442     rcu_read_unlock();
0443 }
0444 
0445 /*
0446  * recalc the min required chan width of the channel context, which is
0447  * the max of min required widths of all the interfaces bound to this
0448  * channel context.
0449  */
0450 void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
0451                       struct ieee80211_chanctx *ctx)
0452 {
0453     u32 changed = _ieee80211_recalc_chanctx_min_def(local, ctx);
0454 
0455     if (!changed)
0456         return;
0457 
0458     /* check is BW narrowed */
0459     ieee80211_chan_bw_change(local, ctx, true);
0460 
0461     drv_change_chanctx(local, ctx, changed);
0462 
0463     /* check is BW wider */
0464     ieee80211_chan_bw_change(local, ctx, false);
0465 }
0466 
0467 static void ieee80211_change_chanctx(struct ieee80211_local *local,
0468                      struct ieee80211_chanctx *ctx,
0469                      struct ieee80211_chanctx *old_ctx,
0470                      const struct cfg80211_chan_def *chandef)
0471 {
0472     u32 changed;
0473 
0474     /* expected to handle only 20/40/80/160/320 channel widths */
0475     switch (chandef->width) {
0476     case NL80211_CHAN_WIDTH_20_NOHT:
0477     case NL80211_CHAN_WIDTH_20:
0478     case NL80211_CHAN_WIDTH_40:
0479     case NL80211_CHAN_WIDTH_80:
0480     case NL80211_CHAN_WIDTH_80P80:
0481     case NL80211_CHAN_WIDTH_160:
0482     case NL80211_CHAN_WIDTH_320:
0483         break;
0484     default:
0485         WARN_ON(1);
0486     }
0487 
0488     /* Check maybe BW narrowed - we do this _before_ calling recalc_chanctx_min_def
0489      * due to maybe not returning from it, e.g in case new context was added
0490      * first time with all parameters up to date.
0491      */
0492     ieee80211_chan_bw_change(local, old_ctx, true);
0493 
0494     if (cfg80211_chandef_identical(&ctx->conf.def, chandef)) {
0495         ieee80211_recalc_chanctx_min_def(local, ctx);
0496         return;
0497     }
0498 
0499     WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef));
0500 
0501     ctx->conf.def = *chandef;
0502 
0503     /* check if min chanctx also changed */
0504     changed = IEEE80211_CHANCTX_CHANGE_WIDTH |
0505           _ieee80211_recalc_chanctx_min_def(local, ctx);
0506     drv_change_chanctx(local, ctx, changed);
0507 
0508     if (!local->use_chanctx) {
0509         local->_oper_chandef = *chandef;
0510         ieee80211_hw_config(local, 0);
0511     }
0512 
0513     /* check is BW wider */
0514     ieee80211_chan_bw_change(local, old_ctx, false);
0515 }
0516 
0517 static struct ieee80211_chanctx *
0518 ieee80211_find_chanctx(struct ieee80211_local *local,
0519                const struct cfg80211_chan_def *chandef,
0520                enum ieee80211_chanctx_mode mode)
0521 {
0522     struct ieee80211_chanctx *ctx;
0523 
0524     lockdep_assert_held(&local->chanctx_mtx);
0525 
0526     if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
0527         return NULL;
0528 
0529     list_for_each_entry(ctx, &local->chanctx_list, list) {
0530         const struct cfg80211_chan_def *compat;
0531 
0532         if (ctx->replace_state != IEEE80211_CHANCTX_REPLACE_NONE)
0533             continue;
0534 
0535         if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
0536             continue;
0537 
0538         compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef);
0539         if (!compat)
0540             continue;
0541 
0542         compat = ieee80211_chanctx_reserved_chandef(local, ctx,
0543                                 compat);
0544         if (!compat)
0545             continue;
0546 
0547         ieee80211_change_chanctx(local, ctx, ctx, compat);
0548 
0549         return ctx;
0550     }
0551 
0552     return NULL;
0553 }
0554 
0555 bool ieee80211_is_radar_required(struct ieee80211_local *local)
0556 {
0557     struct ieee80211_sub_if_data *sdata;
0558 
0559     lockdep_assert_held(&local->mtx);
0560 
0561     rcu_read_lock();
0562     list_for_each_entry_rcu(sdata, &local->interfaces, list) {
0563         unsigned int link_id;
0564 
0565         for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
0566             struct ieee80211_link_data *link;
0567 
0568             link = rcu_dereference(sdata->link[link_id]);
0569 
0570             if (link && link->radar_required) {
0571                 rcu_read_unlock();
0572                 return true;
0573             }
0574         }
0575     }
0576     rcu_read_unlock();
0577 
0578     return false;
0579 }
0580 
0581 static bool
0582 ieee80211_chanctx_radar_required(struct ieee80211_local *local,
0583                  struct ieee80211_chanctx *ctx)
0584 {
0585     struct ieee80211_chanctx_conf *conf = &ctx->conf;
0586     struct ieee80211_sub_if_data *sdata;
0587     bool required = false;
0588 
0589     lockdep_assert_held(&local->chanctx_mtx);
0590     lockdep_assert_held(&local->mtx);
0591 
0592     rcu_read_lock();
0593     list_for_each_entry_rcu(sdata, &local->interfaces, list) {
0594         unsigned int link_id;
0595 
0596         if (!ieee80211_sdata_running(sdata))
0597             continue;
0598         for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
0599             struct ieee80211_link_data *link;
0600 
0601             link = rcu_dereference(sdata->link[link_id]);
0602             if (!link)
0603                 continue;
0604 
0605             if (rcu_access_pointer(link->conf->chanctx_conf) != conf)
0606                 continue;
0607             if (!link->radar_required)
0608                 continue;
0609             required = true;
0610             break;
0611         }
0612 
0613         if (required)
0614             break;
0615     }
0616     rcu_read_unlock();
0617 
0618     return required;
0619 }
0620 
0621 static struct ieee80211_chanctx *
0622 ieee80211_alloc_chanctx(struct ieee80211_local *local,
0623             const struct cfg80211_chan_def *chandef,
0624             enum ieee80211_chanctx_mode mode)
0625 {
0626     struct ieee80211_chanctx *ctx;
0627 
0628     lockdep_assert_held(&local->chanctx_mtx);
0629 
0630     ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
0631     if (!ctx)
0632         return NULL;
0633 
0634     INIT_LIST_HEAD(&ctx->assigned_links);
0635     INIT_LIST_HEAD(&ctx->reserved_links);
0636     ctx->conf.def = *chandef;
0637     ctx->conf.rx_chains_static = 1;
0638     ctx->conf.rx_chains_dynamic = 1;
0639     ctx->mode = mode;
0640     ctx->conf.radar_enabled = false;
0641     ieee80211_recalc_chanctx_min_def(local, ctx);
0642 
0643     return ctx;
0644 }
0645 
0646 static int ieee80211_add_chanctx(struct ieee80211_local *local,
0647                  struct ieee80211_chanctx *ctx)
0648 {
0649     u32 changed;
0650     int err;
0651 
0652     lockdep_assert_held(&local->mtx);
0653     lockdep_assert_held(&local->chanctx_mtx);
0654 
0655     if (!local->use_chanctx)
0656         local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
0657 
0658     /* turn idle off *before* setting channel -- some drivers need that */
0659     changed = ieee80211_idle_off(local);
0660     if (changed)
0661         ieee80211_hw_config(local, changed);
0662 
0663     if (!local->use_chanctx) {
0664         local->_oper_chandef = ctx->conf.def;
0665         ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
0666     } else {
0667         err = drv_add_chanctx(local, ctx);
0668         if (err) {
0669             ieee80211_recalc_idle(local);
0670             return err;
0671         }
0672     }
0673 
0674     return 0;
0675 }
0676 
0677 static struct ieee80211_chanctx *
0678 ieee80211_new_chanctx(struct ieee80211_local *local,
0679               const struct cfg80211_chan_def *chandef,
0680               enum ieee80211_chanctx_mode mode)
0681 {
0682     struct ieee80211_chanctx *ctx;
0683     int err;
0684 
0685     lockdep_assert_held(&local->mtx);
0686     lockdep_assert_held(&local->chanctx_mtx);
0687 
0688     ctx = ieee80211_alloc_chanctx(local, chandef, mode);
0689     if (!ctx)
0690         return ERR_PTR(-ENOMEM);
0691 
0692     err = ieee80211_add_chanctx(local, ctx);
0693     if (err) {
0694         kfree(ctx);
0695         return ERR_PTR(err);
0696     }
0697 
0698     list_add_rcu(&ctx->list, &local->chanctx_list);
0699     return ctx;
0700 }
0701 
0702 static void ieee80211_del_chanctx(struct ieee80211_local *local,
0703                   struct ieee80211_chanctx *ctx)
0704 {
0705     lockdep_assert_held(&local->chanctx_mtx);
0706 
0707     if (!local->use_chanctx) {
0708         struct cfg80211_chan_def *chandef = &local->_oper_chandef;
0709         /* S1G doesn't have 20MHz, so get the correct width for the
0710          * current channel.
0711          */
0712         if (chandef->chan->band == NL80211_BAND_S1GHZ)
0713             chandef->width =
0714                 ieee80211_s1g_channel_width(chandef->chan);
0715         else
0716             chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
0717         chandef->center_freq1 = chandef->chan->center_freq;
0718         chandef->freq1_offset = chandef->chan->freq_offset;
0719         chandef->center_freq2 = 0;
0720 
0721         /* NOTE: Disabling radar is only valid here for
0722          * single channel context. To be sure, check it ...
0723          */
0724         WARN_ON(local->hw.conf.radar_enabled &&
0725             !list_empty(&local->chanctx_list));
0726 
0727         local->hw.conf.radar_enabled = false;
0728 
0729         ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
0730     } else {
0731         drv_remove_chanctx(local, ctx);
0732     }
0733 
0734     ieee80211_recalc_idle(local);
0735 }
0736 
0737 static void ieee80211_free_chanctx(struct ieee80211_local *local,
0738                    struct ieee80211_chanctx *ctx)
0739 {
0740     lockdep_assert_held(&local->chanctx_mtx);
0741 
0742     WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0);
0743 
0744     list_del_rcu(&ctx->list);
0745     ieee80211_del_chanctx(local, ctx);
0746     kfree_rcu(ctx, rcu_head);
0747 }
0748 
0749 void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
0750                        struct ieee80211_chanctx *ctx)
0751 {
0752     struct ieee80211_chanctx_conf *conf = &ctx->conf;
0753     struct ieee80211_sub_if_data *sdata;
0754     const struct cfg80211_chan_def *compat = NULL;
0755     struct sta_info *sta;
0756 
0757     lockdep_assert_held(&local->chanctx_mtx);
0758 
0759     rcu_read_lock();
0760     list_for_each_entry_rcu(sdata, &local->interfaces, list) {
0761         int link_id;
0762 
0763         if (!ieee80211_sdata_running(sdata))
0764             continue;
0765 
0766         if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
0767             continue;
0768 
0769         for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
0770             struct ieee80211_bss_conf *link_conf =
0771                 rcu_dereference(sdata->vif.link_conf[link_id]);
0772 
0773             if (!link_conf)
0774                 continue;
0775 
0776             if (rcu_access_pointer(link_conf->chanctx_conf) != conf)
0777                 continue;
0778 
0779             if (!compat)
0780                 compat = &link_conf->chandef;
0781 
0782             compat = cfg80211_chandef_compatible(&link_conf->chandef,
0783                                  compat);
0784             if (WARN_ON_ONCE(!compat))
0785                 break;
0786         }
0787     }
0788 
0789     /* TDLS peers can sometimes affect the chandef width */
0790     list_for_each_entry_rcu(sta, &local->sta_list, list) {
0791         if (!sta->uploaded ||
0792             !test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW) ||
0793             !test_sta_flag(sta, WLAN_STA_AUTHORIZED) ||
0794             !sta->tdls_chandef.chan)
0795             continue;
0796 
0797         compat = cfg80211_chandef_compatible(&sta->tdls_chandef,
0798                              compat);
0799         if (WARN_ON_ONCE(!compat))
0800             break;
0801     }
0802     rcu_read_unlock();
0803 
0804     if (!compat)
0805         return;
0806 
0807     ieee80211_change_chanctx(local, ctx, ctx, compat);
0808 }
0809 
0810 static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
0811                        struct ieee80211_chanctx *chanctx)
0812 {
0813     bool radar_enabled;
0814 
0815     lockdep_assert_held(&local->chanctx_mtx);
0816     /* for ieee80211_is_radar_required */
0817     lockdep_assert_held(&local->mtx);
0818 
0819     radar_enabled = ieee80211_chanctx_radar_required(local, chanctx);
0820 
0821     if (radar_enabled == chanctx->conf.radar_enabled)
0822         return;
0823 
0824     chanctx->conf.radar_enabled = radar_enabled;
0825 
0826     if (!local->use_chanctx) {
0827         local->hw.conf.radar_enabled = chanctx->conf.radar_enabled;
0828         ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
0829     }
0830 
0831     drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
0832 }
0833 
0834 static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
0835                      struct ieee80211_chanctx *new_ctx)
0836 {
0837     struct ieee80211_sub_if_data *sdata = link->sdata;
0838     struct ieee80211_local *local = sdata->local;
0839     struct ieee80211_chanctx_conf *conf;
0840     struct ieee80211_chanctx *curr_ctx = NULL;
0841     int ret = 0;
0842 
0843     if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_NAN))
0844         return -ENOTSUPP;
0845 
0846     conf = rcu_dereference_protected(link->conf->chanctx_conf,
0847                      lockdep_is_held(&local->chanctx_mtx));
0848 
0849     if (conf) {
0850         curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
0851 
0852         drv_unassign_vif_chanctx(local, sdata, link->conf, curr_ctx);
0853         conf = NULL;
0854         list_del(&link->assigned_chanctx_list);
0855     }
0856 
0857     if (new_ctx) {
0858         ret = drv_assign_vif_chanctx(local, sdata, link->conf, new_ctx);
0859         if (ret)
0860             goto out;
0861 
0862         conf = &new_ctx->conf;
0863         list_add(&link->assigned_chanctx_list,
0864              &new_ctx->assigned_links);
0865     }
0866 
0867 out:
0868     rcu_assign_pointer(link->conf->chanctx_conf, conf);
0869 
0870     sdata->vif.cfg.idle = !conf;
0871 
0872     if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) {
0873         ieee80211_recalc_chanctx_chantype(local, curr_ctx);
0874         ieee80211_recalc_smps_chanctx(local, curr_ctx);
0875         ieee80211_recalc_radar_chanctx(local, curr_ctx);
0876         ieee80211_recalc_chanctx_min_def(local, curr_ctx);
0877     }
0878 
0879     if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
0880         ieee80211_recalc_txpower(sdata, false);
0881         ieee80211_recalc_chanctx_min_def(local, new_ctx);
0882     }
0883 
0884     if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
0885         sdata->vif.type != NL80211_IFTYPE_MONITOR)
0886         ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_IDLE);
0887 
0888     ieee80211_check_fast_xmit_iface(sdata);
0889 
0890     return ret;
0891 }
0892 
0893 void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
0894                    struct ieee80211_chanctx *chanctx)
0895 {
0896     struct ieee80211_sub_if_data *sdata;
0897     u8 rx_chains_static, rx_chains_dynamic;
0898 
0899     lockdep_assert_held(&local->chanctx_mtx);
0900 
0901     rx_chains_static = 1;
0902     rx_chains_dynamic = 1;
0903 
0904     rcu_read_lock();
0905     list_for_each_entry_rcu(sdata, &local->interfaces, list) {
0906         u8 needed_static, needed_dynamic;
0907         unsigned int link_id;
0908 
0909         if (!ieee80211_sdata_running(sdata))
0910             continue;
0911 
0912         switch (sdata->vif.type) {
0913         case NL80211_IFTYPE_STATION:
0914             if (!sdata->u.mgd.associated)
0915                 continue;
0916             break;
0917         case NL80211_IFTYPE_AP:
0918         case NL80211_IFTYPE_ADHOC:
0919         case NL80211_IFTYPE_MESH_POINT:
0920         case NL80211_IFTYPE_OCB:
0921             break;
0922         default:
0923             continue;
0924         }
0925 
0926         for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) {
0927             struct ieee80211_link_data *link;
0928 
0929             link = rcu_dereference(sdata->link[link_id]);
0930 
0931             if (!link)
0932                 continue;
0933 
0934             if (rcu_access_pointer(link->conf->chanctx_conf) != &chanctx->conf)
0935                 continue;
0936 
0937             switch (link->smps_mode) {
0938             default:
0939                 WARN_ONCE(1, "Invalid SMPS mode %d\n",
0940                       link->smps_mode);
0941                 fallthrough;
0942             case IEEE80211_SMPS_OFF:
0943                 needed_static = link->needed_rx_chains;
0944                 needed_dynamic = link->needed_rx_chains;
0945                 break;
0946             case IEEE80211_SMPS_DYNAMIC:
0947                 needed_static = 1;
0948                 needed_dynamic = link->needed_rx_chains;
0949                 break;
0950             case IEEE80211_SMPS_STATIC:
0951                 needed_static = 1;
0952                 needed_dynamic = 1;
0953                 break;
0954             }
0955 
0956             rx_chains_static = max(rx_chains_static, needed_static);
0957             rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic);
0958         }
0959     }
0960 
0961     /* Disable SMPS for the monitor interface */
0962     sdata = rcu_dereference(local->monitor_sdata);
0963     if (sdata &&
0964         rcu_access_pointer(sdata->vif.bss_conf.chanctx_conf) == &chanctx->conf)
0965         rx_chains_dynamic = rx_chains_static = local->rx_chains;
0966 
0967     rcu_read_unlock();
0968 
0969     if (!local->use_chanctx) {
0970         if (rx_chains_static > 1)
0971             local->smps_mode = IEEE80211_SMPS_OFF;
0972         else if (rx_chains_dynamic > 1)
0973             local->smps_mode = IEEE80211_SMPS_DYNAMIC;
0974         else
0975             local->smps_mode = IEEE80211_SMPS_STATIC;
0976         ieee80211_hw_config(local, 0);
0977     }
0978 
0979     if (rx_chains_static == chanctx->conf.rx_chains_static &&
0980         rx_chains_dynamic == chanctx->conf.rx_chains_dynamic)
0981         return;
0982 
0983     chanctx->conf.rx_chains_static = rx_chains_static;
0984     chanctx->conf.rx_chains_dynamic = rx_chains_dynamic;
0985     drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS);
0986 }
0987 
0988 static void
0989 __ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,
0990                        bool clear)
0991 {
0992     struct ieee80211_sub_if_data *sdata = link->sdata;
0993     unsigned int link_id = link->link_id;
0994     struct ieee80211_bss_conf *link_conf = link->conf;
0995     struct ieee80211_local *local __maybe_unused = sdata->local;
0996     struct ieee80211_sub_if_data *vlan;
0997     struct ieee80211_chanctx_conf *conf;
0998 
0999     if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
1000         return;
1001 
1002     lockdep_assert_held(&local->mtx);
1003 
1004     /* Check that conf exists, even when clearing this function
1005      * must be called with the AP's channel context still there
1006      * as it would otherwise cause VLANs to have an invalid
1007      * channel context pointer for a while, possibly pointing
1008      * to a channel context that has already been freed.
1009      */
1010     conf = rcu_dereference_protected(link_conf->chanctx_conf,
1011                      lockdep_is_held(&local->chanctx_mtx));
1012     WARN_ON(!conf);
1013 
1014     if (clear)
1015         conf = NULL;
1016 
1017     rcu_read_lock();
1018     list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
1019         struct ieee80211_bss_conf *vlan_conf;
1020 
1021         vlan_conf = rcu_dereference(vlan->vif.link_conf[link_id]);
1022         if (WARN_ON(!vlan_conf))
1023             continue;
1024 
1025         rcu_assign_pointer(vlan_conf->chanctx_conf, conf);
1026     }
1027     rcu_read_unlock();
1028 }
1029 
1030 void ieee80211_link_copy_chanctx_to_vlans(struct ieee80211_link_data *link,
1031                       bool clear)
1032 {
1033     struct ieee80211_local *local = link->sdata->local;
1034 
1035     mutex_lock(&local->chanctx_mtx);
1036 
1037     __ieee80211_link_copy_chanctx_to_vlans(link, clear);
1038 
1039     mutex_unlock(&local->chanctx_mtx);
1040 }
1041 
1042 int ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link)
1043 {
1044     struct ieee80211_sub_if_data *sdata = link->sdata;
1045     struct ieee80211_chanctx *ctx = link->reserved_chanctx;
1046 
1047     lockdep_assert_held(&sdata->local->chanctx_mtx);
1048 
1049     if (WARN_ON(!ctx))
1050         return -EINVAL;
1051 
1052     list_del(&link->reserved_chanctx_list);
1053     link->reserved_chanctx = NULL;
1054 
1055     if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) {
1056         if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) {
1057             if (WARN_ON(!ctx->replace_ctx))
1058                 return -EINVAL;
1059 
1060             WARN_ON(ctx->replace_ctx->replace_state !=
1061                     IEEE80211_CHANCTX_WILL_BE_REPLACED);
1062             WARN_ON(ctx->replace_ctx->replace_ctx != ctx);
1063 
1064             ctx->replace_ctx->replace_ctx = NULL;
1065             ctx->replace_ctx->replace_state =
1066                     IEEE80211_CHANCTX_REPLACE_NONE;
1067 
1068             list_del_rcu(&ctx->list);
1069             kfree_rcu(ctx, rcu_head);
1070         } else {
1071             ieee80211_free_chanctx(sdata->local, ctx);
1072         }
1073     }
1074 
1075     return 0;
1076 }
1077 
1078 int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link,
1079                    const struct cfg80211_chan_def *chandef,
1080                    enum ieee80211_chanctx_mode mode,
1081                    bool radar_required)
1082 {
1083     struct ieee80211_sub_if_data *sdata = link->sdata;
1084     struct ieee80211_local *local = sdata->local;
1085     struct ieee80211_chanctx *new_ctx, *curr_ctx, *ctx;
1086 
1087     lockdep_assert_held(&local->chanctx_mtx);
1088 
1089     curr_ctx = ieee80211_link_get_chanctx(link);
1090     if (curr_ctx && local->use_chanctx && !local->ops->switch_vif_chanctx)
1091         return -ENOTSUPP;
1092 
1093     new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
1094     if (!new_ctx) {
1095         if (ieee80211_can_create_new_chanctx(local)) {
1096             new_ctx = ieee80211_new_chanctx(local, chandef, mode);
1097             if (IS_ERR(new_ctx))
1098                 return PTR_ERR(new_ctx);
1099         } else {
1100             if (!curr_ctx ||
1101                 (curr_ctx->replace_state ==
1102                  IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
1103                 !list_empty(&curr_ctx->reserved_links)) {
1104                 /*
1105                  * Another link already requested this context
1106                  * for a reservation. Find another one hoping
1107                  * all links assigned to it will also switch
1108                  * soon enough.
1109                  *
1110                  * TODO: This needs a little more work as some
1111                  * cases (more than 2 chanctx capable devices)
1112                  * may fail which could otherwise succeed
1113                  * provided some channel context juggling was
1114                  * performed.
1115                  *
1116                  * Consider ctx1..3, link1..6, each ctx has 2
1117                  * links. link1 and link2 from ctx1 request new
1118                  * different chandefs starting 2 in-place
1119                  * reserations with ctx4 and ctx5 replacing
1120                  * ctx1 and ctx2 respectively. Next link5 and
1121                  * link6 from ctx3 reserve ctx4. If link3 and
1122                  * link4 remain on ctx2 as they are then this
1123                  * fails unless `replace_ctx` from ctx5 is
1124                  * replaced with ctx3.
1125                  */
1126                 list_for_each_entry(ctx, &local->chanctx_list,
1127                             list) {
1128                     if (ctx->replace_state !=
1129                         IEEE80211_CHANCTX_REPLACE_NONE)
1130                         continue;
1131 
1132                     if (!list_empty(&ctx->reserved_links))
1133                         continue;
1134 
1135                     curr_ctx = ctx;
1136                     break;
1137                 }
1138             }
1139 
1140             /*
1141              * If that's true then all available contexts already
1142              * have reservations and cannot be used.
1143              */
1144             if (!curr_ctx ||
1145                 (curr_ctx->replace_state ==
1146                  IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
1147                 !list_empty(&curr_ctx->reserved_links))
1148                 return -EBUSY;
1149 
1150             new_ctx = ieee80211_alloc_chanctx(local, chandef, mode);
1151             if (!new_ctx)
1152                 return -ENOMEM;
1153 
1154             new_ctx->replace_ctx = curr_ctx;
1155             new_ctx->replace_state =
1156                     IEEE80211_CHANCTX_REPLACES_OTHER;
1157 
1158             curr_ctx->replace_ctx = new_ctx;
1159             curr_ctx->replace_state =
1160                     IEEE80211_CHANCTX_WILL_BE_REPLACED;
1161 
1162             list_add_rcu(&new_ctx->list, &local->chanctx_list);
1163         }
1164     }
1165 
1166     list_add(&link->reserved_chanctx_list, &new_ctx->reserved_links);
1167     link->reserved_chanctx = new_ctx;
1168     link->reserved_chandef = *chandef;
1169     link->reserved_radar_required = radar_required;
1170     link->reserved_ready = false;
1171 
1172     return 0;
1173 }
1174 
1175 static void
1176 ieee80211_link_chanctx_reservation_complete(struct ieee80211_link_data *link)
1177 {
1178     struct ieee80211_sub_if_data *sdata = link->sdata;
1179 
1180     switch (sdata->vif.type) {
1181     case NL80211_IFTYPE_ADHOC:
1182     case NL80211_IFTYPE_AP:
1183     case NL80211_IFTYPE_MESH_POINT:
1184     case NL80211_IFTYPE_OCB:
1185         ieee80211_queue_work(&sdata->local->hw,
1186                      &link->csa_finalize_work);
1187         break;
1188     case NL80211_IFTYPE_STATION:
1189         ieee80211_queue_work(&sdata->local->hw,
1190                      &link->u.mgd.chswitch_work);
1191         break;
1192     case NL80211_IFTYPE_UNSPECIFIED:
1193     case NL80211_IFTYPE_AP_VLAN:
1194     case NL80211_IFTYPE_WDS:
1195     case NL80211_IFTYPE_MONITOR:
1196     case NL80211_IFTYPE_P2P_CLIENT:
1197     case NL80211_IFTYPE_P2P_GO:
1198     case NL80211_IFTYPE_P2P_DEVICE:
1199     case NL80211_IFTYPE_NAN:
1200     case NUM_NL80211_IFTYPES:
1201         WARN_ON(1);
1202         break;
1203     }
1204 }
1205 
1206 static void
1207 ieee80211_link_update_chandef(struct ieee80211_link_data *link,
1208                   const struct cfg80211_chan_def *chandef)
1209 {
1210     struct ieee80211_sub_if_data *sdata = link->sdata;
1211     unsigned int link_id = link->link_id;
1212     struct ieee80211_sub_if_data *vlan;
1213 
1214     link->conf->chandef = *chandef;
1215 
1216     if (sdata->vif.type != NL80211_IFTYPE_AP)
1217         return;
1218 
1219     rcu_read_lock();
1220     list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
1221         struct ieee80211_bss_conf *vlan_conf;
1222 
1223         vlan_conf = rcu_dereference(vlan->vif.link_conf[link_id]);
1224         if (WARN_ON(!vlan_conf))
1225             continue;
1226 
1227         vlan_conf->chandef = *chandef;
1228     }
1229     rcu_read_unlock();
1230 }
1231 
1232 static int
1233 ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
1234 {
1235     struct ieee80211_sub_if_data *sdata = link->sdata;
1236     struct ieee80211_bss_conf *link_conf = link->conf;
1237     struct ieee80211_local *local = sdata->local;
1238     struct ieee80211_vif_chanctx_switch vif_chsw[1] = {};
1239     struct ieee80211_chanctx *old_ctx, *new_ctx;
1240     const struct cfg80211_chan_def *chandef;
1241     u32 changed = 0;
1242     int err;
1243 
1244     lockdep_assert_held(&local->mtx);
1245     lockdep_assert_held(&local->chanctx_mtx);
1246 
1247     new_ctx = link->reserved_chanctx;
1248     old_ctx = ieee80211_link_get_chanctx(link);
1249 
1250     if (WARN_ON(!link->reserved_ready))
1251         return -EBUSY;
1252 
1253     if (WARN_ON(!new_ctx))
1254         return -EINVAL;
1255 
1256     if (WARN_ON(!old_ctx))
1257         return -EINVAL;
1258 
1259     if (WARN_ON(new_ctx->replace_state ==
1260             IEEE80211_CHANCTX_REPLACES_OTHER))
1261         return -EINVAL;
1262 
1263     chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx,
1264                 &link->reserved_chandef);
1265     if (WARN_ON(!chandef))
1266         return -EINVAL;
1267 
1268     if (link_conf->chandef.width != link->reserved_chandef.width)
1269         changed = BSS_CHANGED_BANDWIDTH;
1270 
1271     ieee80211_link_update_chandef(link, &link->reserved_chandef);
1272 
1273     ieee80211_change_chanctx(local, new_ctx, old_ctx, chandef);
1274 
1275     vif_chsw[0].vif = &sdata->vif;
1276     vif_chsw[0].old_ctx = &old_ctx->conf;
1277     vif_chsw[0].new_ctx = &new_ctx->conf;
1278     vif_chsw[0].link_conf = link->conf;
1279 
1280     list_del(&link->reserved_chanctx_list);
1281     link->reserved_chanctx = NULL;
1282 
1283     err = drv_switch_vif_chanctx(local, vif_chsw, 1,
1284                      CHANCTX_SWMODE_REASSIGN_VIF);
1285     if (err) {
1286         if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
1287             ieee80211_free_chanctx(local, new_ctx);
1288 
1289         goto out;
1290     }
1291 
1292     list_move(&link->assigned_chanctx_list, &new_ctx->assigned_links);
1293     rcu_assign_pointer(link_conf->chanctx_conf, &new_ctx->conf);
1294 
1295     if (sdata->vif.type == NL80211_IFTYPE_AP)
1296         __ieee80211_link_copy_chanctx_to_vlans(link, false);
1297 
1298     ieee80211_check_fast_xmit_iface(sdata);
1299 
1300     if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
1301         ieee80211_free_chanctx(local, old_ctx);
1302 
1303     ieee80211_recalc_chanctx_min_def(local, new_ctx);
1304     ieee80211_recalc_smps_chanctx(local, new_ctx);
1305     ieee80211_recalc_radar_chanctx(local, new_ctx);
1306 
1307     if (changed)
1308         ieee80211_link_info_change_notify(sdata, link, changed);
1309 
1310 out:
1311     ieee80211_link_chanctx_reservation_complete(link);
1312     return err;
1313 }
1314 
1315 static int
1316 ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link)
1317 {
1318     struct ieee80211_sub_if_data *sdata = link->sdata;
1319     struct ieee80211_local *local = sdata->local;
1320     struct ieee80211_chanctx *old_ctx, *new_ctx;
1321     const struct cfg80211_chan_def *chandef;
1322     int err;
1323 
1324     old_ctx = ieee80211_link_get_chanctx(link);
1325     new_ctx = link->reserved_chanctx;
1326 
1327     if (WARN_ON(!link->reserved_ready))
1328         return -EINVAL;
1329 
1330     if (WARN_ON(old_ctx))
1331         return -EINVAL;
1332 
1333     if (WARN_ON(!new_ctx))
1334         return -EINVAL;
1335 
1336     if (WARN_ON(new_ctx->replace_state ==
1337             IEEE80211_CHANCTX_REPLACES_OTHER))
1338         return -EINVAL;
1339 
1340     chandef = ieee80211_chanctx_non_reserved_chandef(local, new_ctx,
1341                 &link->reserved_chandef);
1342     if (WARN_ON(!chandef))
1343         return -EINVAL;
1344 
1345     ieee80211_change_chanctx(local, new_ctx, new_ctx, chandef);
1346 
1347     list_del(&link->reserved_chanctx_list);
1348     link->reserved_chanctx = NULL;
1349 
1350     err = ieee80211_assign_link_chanctx(link, new_ctx);
1351     if (err) {
1352         if (ieee80211_chanctx_refcount(local, new_ctx) == 0)
1353             ieee80211_free_chanctx(local, new_ctx);
1354 
1355         goto out;
1356     }
1357 
1358 out:
1359     ieee80211_link_chanctx_reservation_complete(link);
1360     return err;
1361 }
1362 
1363 static bool
1364 ieee80211_link_has_in_place_reservation(struct ieee80211_link_data *link)
1365 {
1366     struct ieee80211_sub_if_data *sdata = link->sdata;
1367     struct ieee80211_chanctx *old_ctx, *new_ctx;
1368 
1369     lockdep_assert_held(&sdata->local->chanctx_mtx);
1370 
1371     new_ctx = link->reserved_chanctx;
1372     old_ctx = ieee80211_link_get_chanctx(link);
1373 
1374     if (!old_ctx)
1375         return false;
1376 
1377     if (WARN_ON(!new_ctx))
1378         return false;
1379 
1380     if (old_ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED)
1381         return false;
1382 
1383     if (new_ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1384         return false;
1385 
1386     return true;
1387 }
1388 
1389 static int ieee80211_chsw_switch_hwconf(struct ieee80211_local *local,
1390                     struct ieee80211_chanctx *new_ctx)
1391 {
1392     const struct cfg80211_chan_def *chandef;
1393 
1394     lockdep_assert_held(&local->mtx);
1395     lockdep_assert_held(&local->chanctx_mtx);
1396 
1397     chandef = ieee80211_chanctx_reserved_chandef(local, new_ctx, NULL);
1398     if (WARN_ON(!chandef))
1399         return -EINVAL;
1400 
1401     local->hw.conf.radar_enabled = new_ctx->conf.radar_enabled;
1402     local->_oper_chandef = *chandef;
1403     ieee80211_hw_config(local, 0);
1404 
1405     return 0;
1406 }
1407 
1408 static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local,
1409                       int n_vifs)
1410 {
1411     struct ieee80211_vif_chanctx_switch *vif_chsw;
1412     struct ieee80211_link_data *link;
1413     struct ieee80211_chanctx *ctx, *old_ctx;
1414     int i, err;
1415 
1416     lockdep_assert_held(&local->mtx);
1417     lockdep_assert_held(&local->chanctx_mtx);
1418 
1419     vif_chsw = kcalloc(n_vifs, sizeof(vif_chsw[0]), GFP_KERNEL);
1420     if (!vif_chsw)
1421         return -ENOMEM;
1422 
1423     i = 0;
1424     list_for_each_entry(ctx, &local->chanctx_list, list) {
1425         if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1426             continue;
1427 
1428         if (WARN_ON(!ctx->replace_ctx)) {
1429             err = -EINVAL;
1430             goto out;
1431         }
1432 
1433         list_for_each_entry(link, &ctx->reserved_links,
1434                     reserved_chanctx_list) {
1435             if (!ieee80211_link_has_in_place_reservation(link))
1436                 continue;
1437 
1438             old_ctx = ieee80211_link_get_chanctx(link);
1439             vif_chsw[i].vif = &link->sdata->vif;
1440             vif_chsw[i].old_ctx = &old_ctx->conf;
1441             vif_chsw[i].new_ctx = &ctx->conf;
1442             vif_chsw[i].link_conf = link->conf;
1443 
1444             i++;
1445         }
1446     }
1447 
1448     err = drv_switch_vif_chanctx(local, vif_chsw, n_vifs,
1449                      CHANCTX_SWMODE_SWAP_CONTEXTS);
1450 
1451 out:
1452     kfree(vif_chsw);
1453     return err;
1454 }
1455 
1456 static int ieee80211_chsw_switch_ctxs(struct ieee80211_local *local)
1457 {
1458     struct ieee80211_chanctx *ctx;
1459     int err;
1460 
1461     lockdep_assert_held(&local->mtx);
1462     lockdep_assert_held(&local->chanctx_mtx);
1463 
1464     list_for_each_entry(ctx, &local->chanctx_list, list) {
1465         if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1466             continue;
1467 
1468         if (!list_empty(&ctx->replace_ctx->assigned_links))
1469             continue;
1470 
1471         ieee80211_del_chanctx(local, ctx->replace_ctx);
1472         err = ieee80211_add_chanctx(local, ctx);
1473         if (err)
1474             goto err;
1475     }
1476 
1477     return 0;
1478 
1479 err:
1480     WARN_ON(ieee80211_add_chanctx(local, ctx));
1481     list_for_each_entry_continue_reverse(ctx, &local->chanctx_list, list) {
1482         if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1483             continue;
1484 
1485         if (!list_empty(&ctx->replace_ctx->assigned_links))
1486             continue;
1487 
1488         ieee80211_del_chanctx(local, ctx);
1489         WARN_ON(ieee80211_add_chanctx(local, ctx->replace_ctx));
1490     }
1491 
1492     return err;
1493 }
1494 
1495 static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
1496 {
1497     struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx;
1498     struct ieee80211_chanctx *new_ctx = NULL;
1499     int err, n_assigned, n_reserved, n_ready;
1500     int n_ctx = 0, n_vifs_switch = 0, n_vifs_assign = 0, n_vifs_ctxless = 0;
1501 
1502     lockdep_assert_held(&local->mtx);
1503     lockdep_assert_held(&local->chanctx_mtx);
1504 
1505     /*
1506      * If there are 2 independent pairs of channel contexts performing
1507      * cross-switch of their vifs this code will still wait until both are
1508      * ready even though it could be possible to switch one before the
1509      * other is ready.
1510      *
1511      * For practical reasons and code simplicity just do a single huge
1512      * switch.
1513      */
1514 
1515     /*
1516      * Verify if the reservation is still feasible.
1517      *  - if it's not then disconnect
1518      *  - if it is but not all vifs necessary are ready then defer
1519      */
1520 
1521     list_for_each_entry(ctx, &local->chanctx_list, list) {
1522         struct ieee80211_link_data *link;
1523 
1524         if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1525             continue;
1526 
1527         if (WARN_ON(!ctx->replace_ctx)) {
1528             err = -EINVAL;
1529             goto err;
1530         }
1531 
1532         if (!local->use_chanctx)
1533             new_ctx = ctx;
1534 
1535         n_ctx++;
1536 
1537         n_assigned = 0;
1538         n_reserved = 0;
1539         n_ready = 0;
1540 
1541         list_for_each_entry(link, &ctx->replace_ctx->assigned_links,
1542                     assigned_chanctx_list) {
1543             n_assigned++;
1544             if (link->reserved_chanctx) {
1545                 n_reserved++;
1546                 if (link->reserved_ready)
1547                     n_ready++;
1548             }
1549         }
1550 
1551         if (n_assigned != n_reserved) {
1552             if (n_ready == n_reserved) {
1553                 wiphy_info(local->hw.wiphy,
1554                        "channel context reservation cannot be finalized because some interfaces aren't switching\n");
1555                 err = -EBUSY;
1556                 goto err;
1557             }
1558 
1559             return -EAGAIN;
1560         }
1561 
1562         ctx->conf.radar_enabled = false;
1563         list_for_each_entry(link, &ctx->reserved_links,
1564                     reserved_chanctx_list) {
1565             if (ieee80211_link_has_in_place_reservation(link) &&
1566                 !link->reserved_ready)
1567                 return -EAGAIN;
1568 
1569             old_ctx = ieee80211_link_get_chanctx(link);
1570             if (old_ctx) {
1571                 if (old_ctx->replace_state ==
1572                     IEEE80211_CHANCTX_WILL_BE_REPLACED)
1573                     n_vifs_switch++;
1574                 else
1575                     n_vifs_assign++;
1576             } else {
1577                 n_vifs_ctxless++;
1578             }
1579 
1580             if (link->reserved_radar_required)
1581                 ctx->conf.radar_enabled = true;
1582         }
1583     }
1584 
1585     if (WARN_ON(n_ctx == 0) ||
1586         WARN_ON(n_vifs_switch == 0 &&
1587             n_vifs_assign == 0 &&
1588             n_vifs_ctxless == 0) ||
1589         WARN_ON(n_ctx > 1 && !local->use_chanctx) ||
1590         WARN_ON(!new_ctx && !local->use_chanctx)) {
1591         err = -EINVAL;
1592         goto err;
1593     }
1594 
1595     /*
1596      * All necessary vifs are ready. Perform the switch now depending on
1597      * reservations and driver capabilities.
1598      */
1599 
1600     if (local->use_chanctx) {
1601         if (n_vifs_switch > 0) {
1602             err = ieee80211_chsw_switch_vifs(local, n_vifs_switch);
1603             if (err)
1604                 goto err;
1605         }
1606 
1607         if (n_vifs_assign > 0 || n_vifs_ctxless > 0) {
1608             err = ieee80211_chsw_switch_ctxs(local);
1609             if (err)
1610                 goto err;
1611         }
1612     } else {
1613         err = ieee80211_chsw_switch_hwconf(local, new_ctx);
1614         if (err)
1615             goto err;
1616     }
1617 
1618     /*
1619      * Update all structures, values and pointers to point to new channel
1620      * context(s).
1621      */
1622     list_for_each_entry(ctx, &local->chanctx_list, list) {
1623         struct ieee80211_link_data *link, *link_tmp;
1624 
1625         if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1626             continue;
1627 
1628         if (WARN_ON(!ctx->replace_ctx)) {
1629             err = -EINVAL;
1630             goto err;
1631         }
1632 
1633         list_for_each_entry(link, &ctx->reserved_links,
1634                     reserved_chanctx_list) {
1635             struct ieee80211_sub_if_data *sdata = link->sdata;
1636             struct ieee80211_bss_conf *link_conf = link->conf;
1637             u32 changed = 0;
1638 
1639             if (!ieee80211_link_has_in_place_reservation(link))
1640                 continue;
1641 
1642             rcu_assign_pointer(link_conf->chanctx_conf,
1643                        &ctx->conf);
1644 
1645             if (sdata->vif.type == NL80211_IFTYPE_AP)
1646                 __ieee80211_link_copy_chanctx_to_vlans(link,
1647                                        false);
1648 
1649             ieee80211_check_fast_xmit_iface(sdata);
1650 
1651             link->radar_required = link->reserved_radar_required;
1652 
1653             if (link_conf->chandef.width != link->reserved_chandef.width)
1654                 changed = BSS_CHANGED_BANDWIDTH;
1655 
1656             ieee80211_link_update_chandef(link, &link->reserved_chandef);
1657             if (changed)
1658                 ieee80211_link_info_change_notify(sdata,
1659                                   link,
1660                                   changed);
1661 
1662             ieee80211_recalc_txpower(sdata, false);
1663         }
1664 
1665         ieee80211_recalc_chanctx_chantype(local, ctx);
1666         ieee80211_recalc_smps_chanctx(local, ctx);
1667         ieee80211_recalc_radar_chanctx(local, ctx);
1668         ieee80211_recalc_chanctx_min_def(local, ctx);
1669 
1670         list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
1671                      reserved_chanctx_list) {
1672             if (ieee80211_link_get_chanctx(link) != ctx)
1673                 continue;
1674 
1675             list_del(&link->reserved_chanctx_list);
1676             list_move(&link->assigned_chanctx_list,
1677                   &ctx->assigned_links);
1678             link->reserved_chanctx = NULL;
1679 
1680             ieee80211_link_chanctx_reservation_complete(link);
1681         }
1682 
1683         /*
1684          * This context might have been a dependency for an already
1685          * ready re-assign reservation interface that was deferred. Do
1686          * not propagate error to the caller though. The in-place
1687          * reservation for originally requested interface has already
1688          * succeeded at this point.
1689          */
1690         list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
1691                      reserved_chanctx_list) {
1692             if (WARN_ON(ieee80211_link_has_in_place_reservation(link)))
1693                 continue;
1694 
1695             if (WARN_ON(link->reserved_chanctx != ctx))
1696                 continue;
1697 
1698             if (!link->reserved_ready)
1699                 continue;
1700 
1701             if (ieee80211_link_get_chanctx(link))
1702                 err = ieee80211_link_use_reserved_reassign(link);
1703             else
1704                 err = ieee80211_link_use_reserved_assign(link);
1705 
1706             if (err) {
1707                 link_info(link,
1708                       "failed to finalize (re-)assign reservation (err=%d)\n",
1709                       err);
1710                 ieee80211_link_unreserve_chanctx(link);
1711                 cfg80211_stop_iface(local->hw.wiphy,
1712                             &link->sdata->wdev,
1713                             GFP_KERNEL);
1714             }
1715         }
1716     }
1717 
1718     /*
1719      * Finally free old contexts
1720      */
1721 
1722     list_for_each_entry_safe(ctx, ctx_tmp, &local->chanctx_list, list) {
1723         if (ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED)
1724             continue;
1725 
1726         ctx->replace_ctx->replace_ctx = NULL;
1727         ctx->replace_ctx->replace_state =
1728                 IEEE80211_CHANCTX_REPLACE_NONE;
1729 
1730         list_del_rcu(&ctx->list);
1731         kfree_rcu(ctx, rcu_head);
1732     }
1733 
1734     return 0;
1735 
1736 err:
1737     list_for_each_entry(ctx, &local->chanctx_list, list) {
1738         struct ieee80211_link_data *link, *link_tmp;
1739 
1740         if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
1741             continue;
1742 
1743         list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
1744                      reserved_chanctx_list) {
1745             ieee80211_link_unreserve_chanctx(link);
1746             ieee80211_link_chanctx_reservation_complete(link);
1747         }
1748     }
1749 
1750     return err;
1751 }
1752 
1753 static void __ieee80211_link_release_channel(struct ieee80211_link_data *link)
1754 {
1755     struct ieee80211_sub_if_data *sdata = link->sdata;
1756     struct ieee80211_bss_conf *link_conf = link->conf;
1757     struct ieee80211_local *local = sdata->local;
1758     struct ieee80211_chanctx_conf *conf;
1759     struct ieee80211_chanctx *ctx;
1760     bool use_reserved_switch = false;
1761 
1762     lockdep_assert_held(&local->chanctx_mtx);
1763 
1764     conf = rcu_dereference_protected(link_conf->chanctx_conf,
1765                      lockdep_is_held(&local->chanctx_mtx));
1766     if (!conf)
1767         return;
1768 
1769     ctx = container_of(conf, struct ieee80211_chanctx, conf);
1770 
1771     if (link->reserved_chanctx) {
1772         if (link->reserved_chanctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER &&
1773             ieee80211_chanctx_num_reserved(local, link->reserved_chanctx) > 1)
1774             use_reserved_switch = true;
1775 
1776         ieee80211_link_unreserve_chanctx(link);
1777     }
1778 
1779     ieee80211_assign_link_chanctx(link, NULL);
1780     if (ieee80211_chanctx_refcount(local, ctx) == 0)
1781         ieee80211_free_chanctx(local, ctx);
1782 
1783     link->radar_required = false;
1784 
1785     /* Unreserving may ready an in-place reservation. */
1786     if (use_reserved_switch)
1787         ieee80211_vif_use_reserved_switch(local);
1788 }
1789 
1790 int ieee80211_link_use_channel(struct ieee80211_link_data *link,
1791                    const struct cfg80211_chan_def *chandef,
1792                    enum ieee80211_chanctx_mode mode)
1793 {
1794     struct ieee80211_sub_if_data *sdata = link->sdata;
1795     struct ieee80211_local *local = sdata->local;
1796     struct ieee80211_chanctx *ctx;
1797     u8 radar_detect_width = 0;
1798     int ret;
1799 
1800     lockdep_assert_held(&local->mtx);
1801 
1802     mutex_lock(&local->chanctx_mtx);
1803 
1804     ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
1805                         chandef,
1806                         sdata->wdev.iftype);
1807     if (ret < 0)
1808         goto out;
1809     if (ret > 0)
1810         radar_detect_width = BIT(chandef->width);
1811 
1812     link->radar_required = ret;
1813 
1814     ret = ieee80211_check_combinations(sdata, chandef, mode,
1815                        radar_detect_width);
1816     if (ret < 0)
1817         goto out;
1818 
1819     __ieee80211_link_release_channel(link);
1820 
1821     ctx = ieee80211_find_chanctx(local, chandef, mode);
1822     if (!ctx)
1823         ctx = ieee80211_new_chanctx(local, chandef, mode);
1824     if (IS_ERR(ctx)) {
1825         ret = PTR_ERR(ctx);
1826         goto out;
1827     }
1828 
1829     ieee80211_link_update_chandef(link, chandef);
1830 
1831     ret = ieee80211_assign_link_chanctx(link, ctx);
1832     if (ret) {
1833         /* if assign fails refcount stays the same */
1834         if (ieee80211_chanctx_refcount(local, ctx) == 0)
1835             ieee80211_free_chanctx(local, ctx);
1836         goto out;
1837     }
1838 
1839     ieee80211_recalc_smps_chanctx(local, ctx);
1840     ieee80211_recalc_radar_chanctx(local, ctx);
1841  out:
1842     if (ret)
1843         link->radar_required = false;
1844 
1845     mutex_unlock(&local->chanctx_mtx);
1846     return ret;
1847 }
1848 
1849 int ieee80211_link_use_reserved_context(struct ieee80211_link_data *link)
1850 {
1851     struct ieee80211_sub_if_data *sdata = link->sdata;
1852     struct ieee80211_local *local = sdata->local;
1853     struct ieee80211_chanctx *new_ctx;
1854     struct ieee80211_chanctx *old_ctx;
1855     int err;
1856 
1857     lockdep_assert_held(&local->mtx);
1858     lockdep_assert_held(&local->chanctx_mtx);
1859 
1860     new_ctx = link->reserved_chanctx;
1861     old_ctx = ieee80211_link_get_chanctx(link);
1862 
1863     if (WARN_ON(!new_ctx))
1864         return -EINVAL;
1865 
1866     if (WARN_ON(new_ctx->replace_state ==
1867             IEEE80211_CHANCTX_WILL_BE_REPLACED))
1868         return -EINVAL;
1869 
1870     if (WARN_ON(link->reserved_ready))
1871         return -EINVAL;
1872 
1873     link->reserved_ready = true;
1874 
1875     if (new_ctx->replace_state == IEEE80211_CHANCTX_REPLACE_NONE) {
1876         if (old_ctx)
1877             return ieee80211_link_use_reserved_reassign(link);
1878 
1879         return ieee80211_link_use_reserved_assign(link);
1880     }
1881 
1882     /*
1883      * In-place reservation may need to be finalized now either if:
1884      *  a) sdata is taking part in the swapping itself and is the last one
1885      *  b) sdata has switched with a re-assign reservation to an existing
1886      *     context readying in-place switching of old_ctx
1887      *
1888      * In case of (b) do not propagate the error up because the requested
1889      * sdata already switched successfully. Just spill an extra warning.
1890      * The ieee80211_vif_use_reserved_switch() already stops all necessary
1891      * interfaces upon failure.
1892      */
1893     if ((old_ctx &&
1894          old_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
1895         new_ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) {
1896         err = ieee80211_vif_use_reserved_switch(local);
1897         if (err && err != -EAGAIN) {
1898             if (new_ctx->replace_state ==
1899                 IEEE80211_CHANCTX_REPLACES_OTHER)
1900                 return err;
1901 
1902             wiphy_info(local->hw.wiphy,
1903                    "depending in-place reservation failed (err=%d)\n",
1904                    err);
1905         }
1906     }
1907 
1908     return 0;
1909 }
1910 
1911 int ieee80211_link_change_bandwidth(struct ieee80211_link_data *link,
1912                     const struct cfg80211_chan_def *chandef,
1913                     u32 *changed)
1914 {
1915     struct ieee80211_sub_if_data *sdata = link->sdata;
1916     struct ieee80211_bss_conf *link_conf = link->conf;
1917     struct ieee80211_local *local = sdata->local;
1918     struct ieee80211_chanctx_conf *conf;
1919     struct ieee80211_chanctx *ctx;
1920     const struct cfg80211_chan_def *compat;
1921     int ret;
1922 
1923     if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
1924                      IEEE80211_CHAN_DISABLED))
1925         return -EINVAL;
1926 
1927     mutex_lock(&local->chanctx_mtx);
1928     if (cfg80211_chandef_identical(chandef, &link_conf->chandef)) {
1929         ret = 0;
1930         goto out;
1931     }
1932 
1933     if (chandef->width == NL80211_CHAN_WIDTH_20_NOHT ||
1934         link_conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT) {
1935         ret = -EINVAL;
1936         goto out;
1937     }
1938 
1939     conf = rcu_dereference_protected(link_conf->chanctx_conf,
1940                      lockdep_is_held(&local->chanctx_mtx));
1941     if (!conf) {
1942         ret = -EINVAL;
1943         goto out;
1944     }
1945 
1946     ctx = container_of(conf, struct ieee80211_chanctx, conf);
1947 
1948     compat = cfg80211_chandef_compatible(&conf->def, chandef);
1949     if (!compat) {
1950         ret = -EINVAL;
1951         goto out;
1952     }
1953 
1954     switch (ctx->replace_state) {
1955     case IEEE80211_CHANCTX_REPLACE_NONE:
1956         if (!ieee80211_chanctx_reserved_chandef(local, ctx, compat)) {
1957             ret = -EBUSY;
1958             goto out;
1959         }
1960         break;
1961     case IEEE80211_CHANCTX_WILL_BE_REPLACED:
1962         /* TODO: Perhaps the bandwidth change could be treated as a
1963          * reservation itself? */
1964         ret = -EBUSY;
1965         goto out;
1966     case IEEE80211_CHANCTX_REPLACES_OTHER:
1967         /* channel context that is going to replace another channel
1968          * context doesn't really exist and shouldn't be assigned
1969          * anywhere yet */
1970         WARN_ON(1);
1971         break;
1972     }
1973 
1974     ieee80211_link_update_chandef(link, chandef);
1975 
1976     ieee80211_recalc_chanctx_chantype(local, ctx);
1977 
1978     *changed |= BSS_CHANGED_BANDWIDTH;
1979     ret = 0;
1980  out:
1981     mutex_unlock(&local->chanctx_mtx);
1982     return ret;
1983 }
1984 
1985 void ieee80211_link_release_channel(struct ieee80211_link_data *link)
1986 {
1987     struct ieee80211_sub_if_data *sdata = link->sdata;
1988 
1989     mutex_lock(&sdata->local->chanctx_mtx);
1990     if (rcu_access_pointer(link->conf->chanctx_conf)) {
1991         lockdep_assert_held(&sdata->local->mtx);
1992         __ieee80211_link_release_channel(link);
1993     }
1994     mutex_unlock(&sdata->local->chanctx_mtx);
1995 }
1996 
1997 void ieee80211_link_vlan_copy_chanctx(struct ieee80211_link_data *link)
1998 {
1999     struct ieee80211_sub_if_data *sdata = link->sdata;
2000     unsigned int link_id = link->link_id;
2001     struct ieee80211_bss_conf *link_conf = link->conf;
2002     struct ieee80211_bss_conf *ap_conf;
2003     struct ieee80211_local *local = sdata->local;
2004     struct ieee80211_sub_if_data *ap;
2005     struct ieee80211_chanctx_conf *conf;
2006 
2007     if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->bss))
2008         return;
2009 
2010     ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
2011 
2012     mutex_lock(&local->chanctx_mtx);
2013 
2014     rcu_read_lock();
2015     ap_conf = rcu_dereference(ap->vif.link_conf[link_id]);
2016     conf = rcu_dereference_protected(ap_conf->chanctx_conf,
2017                      lockdep_is_held(&local->chanctx_mtx));
2018     rcu_assign_pointer(link_conf->chanctx_conf, conf);
2019     rcu_read_unlock();
2020     mutex_unlock(&local->chanctx_mtx);
2021 }
2022 
2023 void ieee80211_iter_chan_contexts_atomic(
2024     struct ieee80211_hw *hw,
2025     void (*iter)(struct ieee80211_hw *hw,
2026              struct ieee80211_chanctx_conf *chanctx_conf,
2027              void *data),
2028     void *iter_data)
2029 {
2030     struct ieee80211_local *local = hw_to_local(hw);
2031     struct ieee80211_chanctx *ctx;
2032 
2033     rcu_read_lock();
2034     list_for_each_entry_rcu(ctx, &local->chanctx_list, list)
2035         if (ctx->driver_present)
2036             iter(hw, &ctx->conf, iter_data);
2037     rcu_read_unlock();
2038 }
2039 EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic);