linux/net/mac80211/chan.c
<<
>>
Prefs
   1/*
   2 * mac80211 - channel management
   3 */
   4
   5#include <linux/nl80211.h>
   6#include <linux/export.h>
   7#include <linux/rtnetlink.h>
   8#include <net/cfg80211.h>
   9#include "ieee80211_i.h"
  10#include "driver-ops.h"
  11
  12static void ieee80211_change_chanctx(struct ieee80211_local *local,
  13                                     struct ieee80211_chanctx *ctx,
  14                                     const struct cfg80211_chan_def *chandef)
  15{
  16        if (cfg80211_chandef_identical(&ctx->conf.def, chandef))
  17                return;
  18
  19        WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef));
  20
  21        ctx->conf.def = *chandef;
  22        drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH);
  23
  24        if (!local->use_chanctx) {
  25                local->_oper_chandef = *chandef;
  26                ieee80211_hw_config(local, 0);
  27        }
  28}
  29
  30static struct ieee80211_chanctx *
  31ieee80211_find_chanctx(struct ieee80211_local *local,
  32                       const struct cfg80211_chan_def *chandef,
  33                       enum ieee80211_chanctx_mode mode)
  34{
  35        struct ieee80211_chanctx *ctx;
  36
  37        lockdep_assert_held(&local->chanctx_mtx);
  38
  39        if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
  40                return NULL;
  41
  42        list_for_each_entry(ctx, &local->chanctx_list, list) {
  43                const struct cfg80211_chan_def *compat;
  44
  45                if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
  46                        continue;
  47
  48                compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef);
  49                if (!compat)
  50                        continue;
  51
  52                ieee80211_change_chanctx(local, ctx, compat);
  53
  54                return ctx;
  55        }
  56
  57        return NULL;
  58}
  59
  60static bool ieee80211_is_radar_required(struct ieee80211_local *local)
  61{
  62        struct ieee80211_sub_if_data *sdata;
  63
  64        rcu_read_lock();
  65        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
  66                if (sdata->radar_required) {
  67                        rcu_read_unlock();
  68                        return true;
  69                }
  70        }
  71        rcu_read_unlock();
  72
  73        return false;
  74}
  75
  76static struct ieee80211_chanctx *
  77ieee80211_new_chanctx(struct ieee80211_local *local,
  78                      const struct cfg80211_chan_def *chandef,
  79                      enum ieee80211_chanctx_mode mode)
  80{
  81        struct ieee80211_chanctx *ctx;
  82        u32 changed;
  83        int err;
  84
  85        lockdep_assert_held(&local->chanctx_mtx);
  86
  87        ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL);
  88        if (!ctx)
  89                return ERR_PTR(-ENOMEM);
  90
  91        ctx->conf.def = *chandef;
  92        ctx->conf.rx_chains_static = 1;
  93        ctx->conf.rx_chains_dynamic = 1;
  94        ctx->mode = mode;
  95        ctx->conf.radar_enabled = ieee80211_is_radar_required(local);
  96        if (!local->use_chanctx)
  97                local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
  98
  99        /* acquire mutex to prevent idle from changing */
 100        mutex_lock(&local->mtx);
 101        /* turn idle off *before* setting channel -- some drivers need that */
 102        changed = ieee80211_idle_off(local);
 103        if (changed)
 104                ieee80211_hw_config(local, changed);
 105
 106        if (!local->use_chanctx) {
 107                local->_oper_chandef = *chandef;
 108                ieee80211_hw_config(local, 0);
 109        } else {
 110                err = drv_add_chanctx(local, ctx);
 111                if (err) {
 112                        kfree(ctx);
 113                        ctx = ERR_PTR(err);
 114
 115                        ieee80211_recalc_idle(local);
 116                        goto out;
 117                }
 118        }
 119
 120        /* and keep the mutex held until the new chanctx is on the list */
 121        list_add_rcu(&ctx->list, &local->chanctx_list);
 122
 123 out:
 124        mutex_unlock(&local->mtx);
 125
 126        return ctx;
 127}
 128
 129static void ieee80211_free_chanctx(struct ieee80211_local *local,
 130                                   struct ieee80211_chanctx *ctx)
 131{
 132        bool check_single_channel = false;
 133        lockdep_assert_held(&local->chanctx_mtx);
 134
 135        WARN_ON_ONCE(ctx->refcount != 0);
 136
 137        if (!local->use_chanctx) {
 138                struct cfg80211_chan_def *chandef = &local->_oper_chandef;
 139                chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
 140                chandef->center_freq1 = chandef->chan->center_freq;
 141                chandef->center_freq2 = 0;
 142
 143                /* NOTE: Disabling radar is only valid here for
 144                 * single channel context. To be sure, check it ...
 145                 */
 146                if (local->hw.conf.radar_enabled)
 147                        check_single_channel = true;
 148                local->hw.conf.radar_enabled = false;
 149
 150                ieee80211_hw_config(local, 0);
 151        } else {
 152                drv_remove_chanctx(local, ctx);
 153        }
 154
 155        list_del_rcu(&ctx->list);
 156        kfree_rcu(ctx, rcu_head);
 157
 158        /* throw a warning if this wasn't the only channel context. */
 159        WARN_ON(check_single_channel && !list_empty(&local->chanctx_list));
 160
 161        mutex_lock(&local->mtx);
 162        ieee80211_recalc_idle(local);
 163        mutex_unlock(&local->mtx);
 164}
 165
 166static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 167                                        struct ieee80211_chanctx *ctx)
 168{
 169        struct ieee80211_local *local = sdata->local;
 170        int ret;
 171
 172        lockdep_assert_held(&local->chanctx_mtx);
 173
 174        ret = drv_assign_vif_chanctx(local, sdata, ctx);
 175        if (ret)
 176                return ret;
 177
 178        rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
 179        ctx->refcount++;
 180
 181        ieee80211_recalc_txpower(sdata);
 182        sdata->vif.bss_conf.idle = false;
 183
 184        if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
 185            sdata->vif.type != NL80211_IFTYPE_MONITOR)
 186                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
 187
 188        return 0;
 189}
 190
 191static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
 192                                              struct ieee80211_chanctx *ctx)
 193{
 194        struct ieee80211_chanctx_conf *conf = &ctx->conf;
 195        struct ieee80211_sub_if_data *sdata;
 196        const struct cfg80211_chan_def *compat = NULL;
 197
 198        lockdep_assert_held(&local->chanctx_mtx);
 199
 200        rcu_read_lock();
 201        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 202
 203                if (!ieee80211_sdata_running(sdata))
 204                        continue;
 205                if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
 206                        continue;
 207
 208                if (!compat)
 209                        compat = &sdata->vif.bss_conf.chandef;
 210
 211                compat = cfg80211_chandef_compatible(
 212                                &sdata->vif.bss_conf.chandef, compat);
 213                if (!compat)
 214                        break;
 215        }
 216        rcu_read_unlock();
 217
 218        if (WARN_ON_ONCE(!compat))
 219                return;
 220
 221        ieee80211_change_chanctx(local, ctx, compat);
 222}
 223
 224static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 225                                           struct ieee80211_chanctx *ctx)
 226{
 227        struct ieee80211_local *local = sdata->local;
 228
 229        lockdep_assert_held(&local->chanctx_mtx);
 230
 231        ctx->refcount--;
 232        rcu_assign_pointer(sdata->vif.chanctx_conf, NULL);
 233
 234        sdata->vif.bss_conf.idle = true;
 235
 236        if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
 237            sdata->vif.type != NL80211_IFTYPE_MONITOR)
 238                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE);
 239
 240        drv_unassign_vif_chanctx(local, sdata, ctx);
 241
 242        if (ctx->refcount > 0) {
 243                ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
 244                ieee80211_recalc_smps_chanctx(local, ctx);
 245                ieee80211_recalc_radar_chanctx(local, ctx);
 246        }
 247}
 248
 249static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
 250{
 251        struct ieee80211_local *local = sdata->local;
 252        struct ieee80211_chanctx_conf *conf;
 253        struct ieee80211_chanctx *ctx;
 254
 255        lockdep_assert_held(&local->chanctx_mtx);
 256
 257        conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
 258                                         lockdep_is_held(&local->chanctx_mtx));
 259        if (!conf)
 260                return;
 261
 262        ctx = container_of(conf, struct ieee80211_chanctx, conf);
 263
 264        ieee80211_unassign_vif_chanctx(sdata, ctx);
 265        if (ctx->refcount == 0)
 266                ieee80211_free_chanctx(local, ctx);
 267}
 268
 269void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
 270                                    struct ieee80211_chanctx *chanctx)
 271{
 272        bool radar_enabled;
 273
 274        lockdep_assert_held(&local->chanctx_mtx);
 275
 276        radar_enabled = ieee80211_is_radar_required(local);
 277
 278        if (radar_enabled == chanctx->conf.radar_enabled)
 279                return;
 280
 281        chanctx->conf.radar_enabled = radar_enabled;
 282        local->radar_detect_enabled = chanctx->conf.radar_enabled;
 283
 284        if (!local->use_chanctx) {
 285                local->hw.conf.radar_enabled = chanctx->conf.radar_enabled;
 286                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 287        }
 288
 289        drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
 290}
 291
 292void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
 293                                   struct ieee80211_chanctx *chanctx)
 294{
 295        struct ieee80211_sub_if_data *sdata;
 296        u8 rx_chains_static, rx_chains_dynamic;
 297
 298        lockdep_assert_held(&local->chanctx_mtx);
 299
 300        rx_chains_static = 1;
 301        rx_chains_dynamic = 1;
 302
 303        rcu_read_lock();
 304        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 305                u8 needed_static, needed_dynamic;
 306
 307                if (!ieee80211_sdata_running(sdata))
 308                        continue;
 309
 310                if (rcu_access_pointer(sdata->vif.chanctx_conf) !=
 311                                                &chanctx->conf)
 312                        continue;
 313
 314                switch (sdata->vif.type) {
 315                case NL80211_IFTYPE_P2P_DEVICE:
 316                        continue;
 317                case NL80211_IFTYPE_STATION:
 318                        if (!sdata->u.mgd.associated)
 319                                continue;
 320                        break;
 321                case NL80211_IFTYPE_AP_VLAN:
 322                        continue;
 323                case NL80211_IFTYPE_AP:
 324                case NL80211_IFTYPE_ADHOC:
 325                case NL80211_IFTYPE_WDS:
 326                case NL80211_IFTYPE_MESH_POINT:
 327                        break;
 328                default:
 329                        WARN_ON_ONCE(1);
 330                }
 331
 332                switch (sdata->smps_mode) {
 333                default:
 334                        WARN_ONCE(1, "Invalid SMPS mode %d\n",
 335                                  sdata->smps_mode);
 336                        /* fall through */
 337                case IEEE80211_SMPS_OFF:
 338                        needed_static = sdata->needed_rx_chains;
 339                        needed_dynamic = sdata->needed_rx_chains;
 340                        break;
 341                case IEEE80211_SMPS_DYNAMIC:
 342                        needed_static = 1;
 343                        needed_dynamic = sdata->needed_rx_chains;
 344                        break;
 345                case IEEE80211_SMPS_STATIC:
 346                        needed_static = 1;
 347                        needed_dynamic = 1;
 348                        break;
 349                }
 350
 351                rx_chains_static = max(rx_chains_static, needed_static);
 352                rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic);
 353        }
 354        rcu_read_unlock();
 355
 356        if (!local->use_chanctx) {
 357                if (rx_chains_static > 1)
 358                        local->smps_mode = IEEE80211_SMPS_OFF;
 359                else if (rx_chains_dynamic > 1)
 360                        local->smps_mode = IEEE80211_SMPS_DYNAMIC;
 361                else
 362                        local->smps_mode = IEEE80211_SMPS_STATIC;
 363                ieee80211_hw_config(local, 0);
 364        }
 365
 366        if (rx_chains_static == chanctx->conf.rx_chains_static &&
 367            rx_chains_dynamic == chanctx->conf.rx_chains_dynamic)
 368                return;
 369
 370        chanctx->conf.rx_chains_static = rx_chains_static;
 371        chanctx->conf.rx_chains_dynamic = rx_chains_dynamic;
 372        drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS);
 373}
 374
 375int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 376                              const struct cfg80211_chan_def *chandef,
 377                              enum ieee80211_chanctx_mode mode)
 378{
 379        struct ieee80211_local *local = sdata->local;
 380        struct ieee80211_chanctx *ctx;
 381        int ret;
 382
 383        WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
 384
 385        mutex_lock(&local->chanctx_mtx);
 386        __ieee80211_vif_release_channel(sdata);
 387
 388        ctx = ieee80211_find_chanctx(local, chandef, mode);
 389        if (!ctx)
 390                ctx = ieee80211_new_chanctx(local, chandef, mode);
 391        if (IS_ERR(ctx)) {
 392                ret = PTR_ERR(ctx);
 393                goto out;
 394        }
 395
 396        sdata->vif.bss_conf.chandef = *chandef;
 397
 398        ret = ieee80211_assign_vif_chanctx(sdata, ctx);
 399        if (ret) {
 400                /* if assign fails refcount stays the same */
 401                if (ctx->refcount == 0)
 402                        ieee80211_free_chanctx(local, ctx);
 403                goto out;
 404        }
 405
 406        ieee80211_recalc_smps_chanctx(local, ctx);
 407        ieee80211_recalc_radar_chanctx(local, ctx);
 408 out:
 409        mutex_unlock(&local->chanctx_mtx);
 410        return ret;
 411}
 412
 413int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
 414                                 const struct cfg80211_chan_def *chandef,
 415                                 u32 *changed)
 416{
 417        struct ieee80211_local *local = sdata->local;
 418        struct ieee80211_chanctx_conf *conf;
 419        struct ieee80211_chanctx *ctx;
 420        int ret;
 421        u32 chanctx_changed = 0;
 422
 423        /* should never be called if not performing a channel switch. */
 424        if (WARN_ON(!sdata->vif.csa_active))
 425                return -EINVAL;
 426
 427        if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
 428                                     IEEE80211_CHAN_DISABLED))
 429                return -EINVAL;
 430
 431        mutex_lock(&local->chanctx_mtx);
 432        conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
 433                                         lockdep_is_held(&local->chanctx_mtx));
 434        if (!conf) {
 435                ret = -EINVAL;
 436                goto out;
 437        }
 438
 439        ctx = container_of(conf, struct ieee80211_chanctx, conf);
 440        if (ctx->refcount != 1) {
 441                ret = -EINVAL;
 442                goto out;
 443        }
 444
 445        if (sdata->vif.bss_conf.chandef.width != chandef->width) {
 446                chanctx_changed = IEEE80211_CHANCTX_CHANGE_WIDTH;
 447                *changed |= BSS_CHANGED_BANDWIDTH;
 448        }
 449
 450        sdata->vif.bss_conf.chandef = *chandef;
 451        ctx->conf.def = *chandef;
 452
 453        chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL;
 454        drv_change_chanctx(local, ctx, chanctx_changed);
 455
 456        if (!local->use_chanctx) {
 457                local->_oper_chandef = *chandef;
 458                ieee80211_hw_config(local, 0);
 459        }
 460
 461        ieee80211_recalc_chanctx_chantype(local, ctx);
 462        ieee80211_recalc_smps_chanctx(local, ctx);
 463        ieee80211_recalc_radar_chanctx(local, ctx);
 464
 465        ret = 0;
 466 out:
 467        mutex_unlock(&local->chanctx_mtx);
 468        return ret;
 469}
 470
 471int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
 472                                   const struct cfg80211_chan_def *chandef,
 473                                   u32 *changed)
 474{
 475        struct ieee80211_local *local = sdata->local;
 476        struct ieee80211_chanctx_conf *conf;
 477        struct ieee80211_chanctx *ctx;
 478        int ret;
 479
 480        if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
 481                                     IEEE80211_CHAN_DISABLED))
 482                return -EINVAL;
 483
 484        mutex_lock(&local->chanctx_mtx);
 485        if (cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef)) {
 486                ret = 0;
 487                goto out;
 488        }
 489
 490        if (chandef->width == NL80211_CHAN_WIDTH_20_NOHT ||
 491            sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) {
 492                ret = -EINVAL;
 493                goto out;
 494        }
 495
 496        conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
 497                                         lockdep_is_held(&local->chanctx_mtx));
 498        if (!conf) {
 499                ret = -EINVAL;
 500                goto out;
 501        }
 502
 503        ctx = container_of(conf, struct ieee80211_chanctx, conf);
 504        if (!cfg80211_chandef_compatible(&conf->def, chandef)) {
 505                ret = -EINVAL;
 506                goto out;
 507        }
 508
 509        sdata->vif.bss_conf.chandef = *chandef;
 510
 511        ieee80211_recalc_chanctx_chantype(local, ctx);
 512
 513        *changed |= BSS_CHANGED_BANDWIDTH;
 514        ret = 0;
 515 out:
 516        mutex_unlock(&local->chanctx_mtx);
 517        return ret;
 518}
 519
 520void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
 521{
 522        WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
 523
 524        mutex_lock(&sdata->local->chanctx_mtx);
 525        __ieee80211_vif_release_channel(sdata);
 526        mutex_unlock(&sdata->local->chanctx_mtx);
 527}
 528
 529void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata)
 530{
 531        struct ieee80211_local *local = sdata->local;
 532        struct ieee80211_sub_if_data *ap;
 533        struct ieee80211_chanctx_conf *conf;
 534
 535        if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->bss))
 536                return;
 537
 538        ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
 539
 540        mutex_lock(&local->chanctx_mtx);
 541
 542        conf = rcu_dereference_protected(ap->vif.chanctx_conf,
 543                                         lockdep_is_held(&local->chanctx_mtx));
 544        rcu_assign_pointer(sdata->vif.chanctx_conf, conf);
 545        mutex_unlock(&local->chanctx_mtx);
 546}
 547
 548void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
 549                                         bool clear)
 550{
 551        struct ieee80211_local *local = sdata->local;
 552        struct ieee80211_sub_if_data *vlan;
 553        struct ieee80211_chanctx_conf *conf;
 554
 555        ASSERT_RTNL();
 556
 557        if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
 558                return;
 559
 560        mutex_lock(&local->chanctx_mtx);
 561
 562        /*
 563         * Check that conf exists, even when clearing this function
 564         * must be called with the AP's channel context still there
 565         * as it would otherwise cause VLANs to have an invalid
 566         * channel context pointer for a while, possibly pointing
 567         * to a channel context that has already been freed.
 568         */
 569        conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
 570                                lockdep_is_held(&local->chanctx_mtx));
 571        WARN_ON(!conf);
 572
 573        if (clear)
 574                conf = NULL;
 575
 576        list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
 577                rcu_assign_pointer(vlan->vif.chanctx_conf, conf);
 578
 579        mutex_unlock(&local->chanctx_mtx);
 580}
 581
 582void ieee80211_iter_chan_contexts_atomic(
 583        struct ieee80211_hw *hw,
 584        void (*iter)(struct ieee80211_hw *hw,
 585                     struct ieee80211_chanctx_conf *chanctx_conf,
 586                     void *data),
 587        void *iter_data)
 588{
 589        struct ieee80211_local *local = hw_to_local(hw);
 590        struct ieee80211_chanctx *ctx;
 591
 592        rcu_read_lock();
 593        list_for_each_entry_rcu(ctx, &local->chanctx_list, list)
 594                if (ctx->driver_present)
 595                        iter(hw, &ctx->conf, iter_data);
 596        rcu_read_unlock();
 597}
 598EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic);
 599