linux/net/mac80211/vht.c
<<
>>
Prefs
   1/*
   2 * VHT handling
   3 *
   4 * Portions of this file
   5 * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11
  12#include <linux/ieee80211.h>
  13#include <linux/export.h>
  14#include <net/mac80211.h>
  15#include "ieee80211_i.h"
  16#include "rate.h"
  17
  18
  19static void __check_vhtcap_disable(struct ieee80211_sub_if_data *sdata,
  20                                   struct ieee80211_sta_vht_cap *vht_cap,
  21                                   u32 flag)
  22{
  23        __le32 le_flag = cpu_to_le32(flag);
  24
  25        if (sdata->u.mgd.vht_capa_mask.vht_cap_info & le_flag &&
  26            !(sdata->u.mgd.vht_capa.vht_cap_info & le_flag))
  27                vht_cap->cap &= ~flag;
  28}
  29
  30void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata,
  31                                      struct ieee80211_sta_vht_cap *vht_cap)
  32{
  33        int i;
  34        u16 rxmcs_mask, rxmcs_cap, rxmcs_n, txmcs_mask, txmcs_cap, txmcs_n;
  35
  36        if (!vht_cap->vht_supported)
  37                return;
  38
  39        if (sdata->vif.type != NL80211_IFTYPE_STATION)
  40                return;
  41
  42        __check_vhtcap_disable(sdata, vht_cap,
  43                               IEEE80211_VHT_CAP_RXLDPC);
  44        __check_vhtcap_disable(sdata, vht_cap,
  45                               IEEE80211_VHT_CAP_SHORT_GI_80);
  46        __check_vhtcap_disable(sdata, vht_cap,
  47                               IEEE80211_VHT_CAP_SHORT_GI_160);
  48        __check_vhtcap_disable(sdata, vht_cap,
  49                               IEEE80211_VHT_CAP_TXSTBC);
  50        __check_vhtcap_disable(sdata, vht_cap,
  51                               IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
  52        __check_vhtcap_disable(sdata, vht_cap,
  53                               IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
  54        __check_vhtcap_disable(sdata, vht_cap,
  55                               IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN);
  56        __check_vhtcap_disable(sdata, vht_cap,
  57                               IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN);
  58
  59        /* Allow user to decrease AMPDU length exponent */
  60        if (sdata->u.mgd.vht_capa_mask.vht_cap_info &
  61            cpu_to_le32(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK)) {
  62                u32 cap, n;
  63
  64                n = le32_to_cpu(sdata->u.mgd.vht_capa.vht_cap_info) &
  65                        IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
  66                n >>= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
  67                cap = vht_cap->cap & IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
  68                cap >>= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
  69
  70                if (n < cap) {
  71                        vht_cap->cap &=
  72                                ~IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
  73                        vht_cap->cap |=
  74                                n << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
  75                }
  76        }
  77
  78        /* Allow the user to decrease MCSes */
  79        rxmcs_mask =
  80                le16_to_cpu(sdata->u.mgd.vht_capa_mask.supp_mcs.rx_mcs_map);
  81        rxmcs_n = le16_to_cpu(sdata->u.mgd.vht_capa.supp_mcs.rx_mcs_map);
  82        rxmcs_n &= rxmcs_mask;
  83        rxmcs_cap = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map);
  84
  85        txmcs_mask =
  86                le16_to_cpu(sdata->u.mgd.vht_capa_mask.supp_mcs.tx_mcs_map);
  87        txmcs_n = le16_to_cpu(sdata->u.mgd.vht_capa.supp_mcs.tx_mcs_map);
  88        txmcs_n &= txmcs_mask;
  89        txmcs_cap = le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map);
  90        for (i = 0; i < 8; i++) {
  91                u8 m, n, c;
  92
  93                m = (rxmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
  94                n = (rxmcs_n >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
  95                c = (rxmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
  96
  97                if (m && ((c != IEEE80211_VHT_MCS_NOT_SUPPORTED && n < c) ||
  98                          n == IEEE80211_VHT_MCS_NOT_SUPPORTED)) {
  99                        rxmcs_cap &= ~(3 << 2*i);
 100                        rxmcs_cap |= (rxmcs_n & (3 << 2*i));
 101                }
 102
 103                m = (txmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
 104                n = (txmcs_n >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
 105                c = (txmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
 106
 107                if (m && ((c != IEEE80211_VHT_MCS_NOT_SUPPORTED && n < c) ||
 108                          n == IEEE80211_VHT_MCS_NOT_SUPPORTED)) {
 109                        txmcs_cap &= ~(3 << 2*i);
 110                        txmcs_cap |= (txmcs_n & (3 << 2*i));
 111                }
 112        }
 113        vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(rxmcs_cap);
 114        vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(txmcs_cap);
 115}
 116
 117void
 118ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
 119                                    struct ieee80211_supported_band *sband,
 120                                    const struct ieee80211_vht_cap *vht_cap_ie,
 121                                    struct sta_info *sta)
 122{
 123        struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap;
 124        struct ieee80211_sta_vht_cap own_cap;
 125        u32 cap_info, i;
 126        bool have_80mhz;
 127
 128        memset(vht_cap, 0, sizeof(*vht_cap));
 129
 130        if (!sta->sta.ht_cap.ht_supported)
 131                return;
 132
 133        if (!vht_cap_ie || !sband->vht_cap.vht_supported)
 134                return;
 135
 136        /* Allow VHT if at least one channel on the sband supports 80 MHz */
 137        have_80mhz = false;
 138        for (i = 0; i < sband->n_channels; i++) {
 139                if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED |
 140                                                IEEE80211_CHAN_NO_80MHZ))
 141                        continue;
 142
 143                have_80mhz = true;
 144                break;
 145        }
 146
 147        if (!have_80mhz)
 148                return;
 149
 150        /*
 151         * A VHT STA must support 40 MHz, but if we verify that here
 152         * then we break a few things - some APs (e.g. Netgear R6300v2
 153         * and others based on the BCM4360 chipset) will unset this
 154         * capability bit when operating in 20 MHz.
 155         */
 156
 157        vht_cap->vht_supported = true;
 158
 159        own_cap = sband->vht_cap;
 160        /*
 161         * If user has specified capability overrides, take care
 162         * of that if the station we're setting up is the AP that
 163         * we advertised a restricted capability set to. Override
 164         * our own capabilities and then use those below.
 165         */
 166        if (sdata->vif.type == NL80211_IFTYPE_STATION &&
 167            !test_sta_flag(sta, WLAN_STA_TDLS_PEER))
 168                ieee80211_apply_vhtcap_overrides(sdata, &own_cap);
 169
 170        /* take some capabilities as-is */
 171        cap_info = le32_to_cpu(vht_cap_ie->vht_cap_info);
 172        vht_cap->cap = cap_info;
 173        vht_cap->cap &= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 |
 174                        IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
 175                        IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
 176                        IEEE80211_VHT_CAP_RXLDPC |
 177                        IEEE80211_VHT_CAP_VHT_TXOP_PS |
 178                        IEEE80211_VHT_CAP_HTC_VHT |
 179                        IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
 180                        IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB |
 181                        IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB |
 182                        IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
 183                        IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
 184
 185        /* and some based on our own capabilities */
 186        switch (own_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
 187        case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
 188                vht_cap->cap |= cap_info &
 189                                IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
 190                break;
 191        case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
 192                vht_cap->cap |= cap_info &
 193                                IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
 194                break;
 195        default:
 196                /* nothing */
 197                break;
 198        }
 199
 200        /* symmetric capabilities */
 201        vht_cap->cap |= cap_info & own_cap.cap &
 202                        (IEEE80211_VHT_CAP_SHORT_GI_80 |
 203                         IEEE80211_VHT_CAP_SHORT_GI_160);
 204
 205        /* remaining ones */
 206        if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)
 207                vht_cap->cap |= cap_info &
 208                                (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
 209                                 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK);
 210
 211        if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)
 212                vht_cap->cap |= cap_info &
 213                                (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
 214                                 IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK);
 215
 216        if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)
 217                vht_cap->cap |= cap_info &
 218                                IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
 219
 220        if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)
 221                vht_cap->cap |= cap_info &
 222                                IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
 223
 224        if (own_cap.cap & IEEE80211_VHT_CAP_TXSTBC)
 225                vht_cap->cap |= cap_info & IEEE80211_VHT_CAP_RXSTBC_MASK;
 226
 227        if (own_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK)
 228                vht_cap->cap |= cap_info & IEEE80211_VHT_CAP_TXSTBC;
 229
 230        /* Copy peer MCS info, the driver might need them. */
 231        memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs,
 232               sizeof(struct ieee80211_vht_mcs_info));
 233
 234        /* but also restrict MCSes */
 235        for (i = 0; i < 8; i++) {
 236                u16 own_rx, own_tx, peer_rx, peer_tx;
 237
 238                own_rx = le16_to_cpu(own_cap.vht_mcs.rx_mcs_map);
 239                own_rx = (own_rx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
 240
 241                own_tx = le16_to_cpu(own_cap.vht_mcs.tx_mcs_map);
 242                own_tx = (own_tx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
 243
 244                peer_rx = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map);
 245                peer_rx = (peer_rx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
 246
 247                peer_tx = le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map);
 248                peer_tx = (peer_tx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
 249
 250                if (peer_tx != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
 251                        if (own_rx == IEEE80211_VHT_MCS_NOT_SUPPORTED)
 252                                peer_tx = IEEE80211_VHT_MCS_NOT_SUPPORTED;
 253                        else if (own_rx < peer_tx)
 254                                peer_tx = own_rx;
 255                }
 256
 257                if (peer_rx != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
 258                        if (own_tx == IEEE80211_VHT_MCS_NOT_SUPPORTED)
 259                                peer_rx = IEEE80211_VHT_MCS_NOT_SUPPORTED;
 260                        else if (own_tx < peer_rx)
 261                                peer_rx = own_tx;
 262                }
 263
 264                vht_cap->vht_mcs.rx_mcs_map &=
 265                        ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << i * 2);
 266                vht_cap->vht_mcs.rx_mcs_map |= cpu_to_le16(peer_rx << i * 2);
 267
 268                vht_cap->vht_mcs.tx_mcs_map &=
 269                        ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << i * 2);
 270                vht_cap->vht_mcs.tx_mcs_map |= cpu_to_le16(peer_tx << i * 2);
 271        }
 272
 273        /* finally set up the bandwidth */
 274        switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
 275        case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
 276        case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
 277                sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
 278                break;
 279        default:
 280                sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80;
 281        }
 282
 283        sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta);
 284
 285        /* If HT IE reported 3839 bytes only, stay with that size. */
 286        if (sta->sta.max_amsdu_len == IEEE80211_MAX_MPDU_LEN_HT_3839)
 287                return;
 288
 289        switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) {
 290        case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
 291                sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454;
 292                break;
 293        case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
 294                sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_7991;
 295                break;
 296        case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895:
 297        default:
 298                sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_3895;
 299                break;
 300        }
 301}
 302
 303enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta)
 304{
 305        struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap;
 306        u32 cap_width;
 307
 308        if (!vht_cap->vht_supported)
 309                return sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
 310                                IEEE80211_STA_RX_BW_40 :
 311                                IEEE80211_STA_RX_BW_20;
 312
 313        cap_width = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
 314
 315        if (cap_width == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ ||
 316            cap_width == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
 317                return IEEE80211_STA_RX_BW_160;
 318
 319        return IEEE80211_STA_RX_BW_80;
 320}
 321
 322enum nl80211_chan_width ieee80211_sta_cap_chan_bw(struct sta_info *sta)
 323{
 324        struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap;
 325        u32 cap_width;
 326
 327        if (!vht_cap->vht_supported) {
 328                if (!sta->sta.ht_cap.ht_supported)
 329                        return NL80211_CHAN_WIDTH_20_NOHT;
 330
 331                return sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
 332                                NL80211_CHAN_WIDTH_40 : NL80211_CHAN_WIDTH_20;
 333        }
 334
 335        cap_width = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
 336
 337        if (cap_width == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)
 338                return NL80211_CHAN_WIDTH_160;
 339        else if (cap_width == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
 340                return NL80211_CHAN_WIDTH_80P80;
 341
 342        return NL80211_CHAN_WIDTH_80;
 343}
 344
 345enum ieee80211_sta_rx_bandwidth
 346ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width)
 347{
 348        switch (width) {
 349        case NL80211_CHAN_WIDTH_20_NOHT:
 350        case NL80211_CHAN_WIDTH_20:
 351                return IEEE80211_STA_RX_BW_20;
 352        case NL80211_CHAN_WIDTH_40:
 353                return IEEE80211_STA_RX_BW_40;
 354        case NL80211_CHAN_WIDTH_80:
 355                return IEEE80211_STA_RX_BW_80;
 356        case NL80211_CHAN_WIDTH_160:
 357        case NL80211_CHAN_WIDTH_80P80:
 358                return IEEE80211_STA_RX_BW_160;
 359        default:
 360                WARN_ON_ONCE(1);
 361                return IEEE80211_STA_RX_BW_20;
 362        }
 363}
 364
 365enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta)
 366{
 367        struct ieee80211_sub_if_data *sdata = sta->sdata;
 368        enum ieee80211_sta_rx_bandwidth bw;
 369        enum nl80211_chan_width bss_width = sdata->vif.bss_conf.chandef.width;
 370
 371        bw = ieee80211_sta_cap_rx_bw(sta);
 372        bw = min(bw, sta->cur_max_bandwidth);
 373        bw = min(bw, ieee80211_chan_width_to_rx_bw(bss_width));
 374
 375        return bw;
 376}
 377
 378void ieee80211_sta_set_rx_nss(struct sta_info *sta)
 379{
 380        u8 ht_rx_nss = 0, vht_rx_nss = 0;
 381
 382        /* if we received a notification already don't overwrite it */
 383        if (sta->sta.rx_nss)
 384                return;
 385
 386        if (sta->sta.ht_cap.ht_supported) {
 387                if (sta->sta.ht_cap.mcs.rx_mask[0])
 388                        ht_rx_nss++;
 389                if (sta->sta.ht_cap.mcs.rx_mask[1])
 390                        ht_rx_nss++;
 391                if (sta->sta.ht_cap.mcs.rx_mask[2])
 392                        ht_rx_nss++;
 393                if (sta->sta.ht_cap.mcs.rx_mask[3])
 394                        ht_rx_nss++;
 395                /* FIXME: consider rx_highest? */
 396        }
 397
 398        if (sta->sta.vht_cap.vht_supported) {
 399                int i;
 400                u16 rx_mcs_map;
 401
 402                rx_mcs_map = le16_to_cpu(sta->sta.vht_cap.vht_mcs.rx_mcs_map);
 403
 404                for (i = 7; i >= 0; i--) {
 405                        u8 mcs = (rx_mcs_map >> (2 * i)) & 3;
 406
 407                        if (mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
 408                                vht_rx_nss = i + 1;
 409                                break;
 410                        }
 411                }
 412                /* FIXME: consider rx_highest? */
 413        }
 414
 415        ht_rx_nss = max(ht_rx_nss, vht_rx_nss);
 416        sta->sta.rx_nss = max_t(u8, 1, ht_rx_nss);
 417}
 418
 419u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
 420                                  struct sta_info *sta, u8 opmode,
 421                                  enum ieee80211_band band)
 422{
 423        struct ieee80211_local *local = sdata->local;
 424        struct ieee80211_supported_band *sband;
 425        enum ieee80211_sta_rx_bandwidth new_bw;
 426        u32 changed = 0;
 427        u8 nss;
 428
 429        sband = local->hw.wiphy->bands[band];
 430
 431        /* ignore - no support for BF yet */
 432        if (opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)
 433                return 0;
 434
 435        nss = opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK;
 436        nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT;
 437        nss += 1;
 438
 439        if (sta->sta.rx_nss != nss) {
 440                sta->sta.rx_nss = nss;
 441                changed |= IEEE80211_RC_NSS_CHANGED;
 442        }
 443
 444        switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) {
 445        case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ:
 446                sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_20;
 447                break;
 448        case IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ:
 449                sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_40;
 450                break;
 451        case IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ:
 452                sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80;
 453                break;
 454        case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ:
 455                sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
 456                break;
 457        }
 458
 459        new_bw = ieee80211_sta_cur_vht_bw(sta);
 460        if (new_bw != sta->sta.bandwidth) {
 461                sta->sta.bandwidth = new_bw;
 462                changed |= IEEE80211_RC_BW_CHANGED;
 463        }
 464
 465        return changed;
 466}
 467
 468void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata,
 469                                 struct ieee80211_mgmt *mgmt)
 470{
 471        struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
 472
 473        if (!sdata->vif.mu_mimo_owner)
 474                return;
 475
 476        if (!memcmp(mgmt->u.action.u.vht_group_notif.position,
 477                    bss_conf->mu_group.position, WLAN_USER_POSITION_LEN) &&
 478            !memcmp(mgmt->u.action.u.vht_group_notif.membership,
 479                    bss_conf->mu_group.membership, WLAN_MEMBERSHIP_LEN))
 480                return;
 481
 482        memcpy(bss_conf->mu_group.membership,
 483               mgmt->u.action.u.vht_group_notif.membership,
 484               WLAN_MEMBERSHIP_LEN);
 485        memcpy(bss_conf->mu_group.position,
 486               mgmt->u.action.u.vht_group_notif.position,
 487               WLAN_USER_POSITION_LEN);
 488
 489        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_MU_GROUPS);
 490}
 491
 492void ieee80211_update_mu_groups(struct ieee80211_vif *vif,
 493                                const u8 *membership, const u8 *position)
 494{
 495        struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
 496
 497        if (WARN_ON_ONCE(!vif->mu_mimo_owner))
 498                return;
 499
 500        memcpy(bss_conf->mu_group.membership, membership, WLAN_MEMBERSHIP_LEN);
 501        memcpy(bss_conf->mu_group.position, position, WLAN_USER_POSITION_LEN);
 502}
 503EXPORT_SYMBOL_GPL(ieee80211_update_mu_groups);
 504
 505void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
 506                                 struct sta_info *sta, u8 opmode,
 507                                 enum ieee80211_band band)
 508{
 509        struct ieee80211_local *local = sdata->local;
 510        struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
 511
 512        u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, opmode, band);
 513
 514        if (changed > 0)
 515                rate_control_rate_update(local, sband, sta, changed);
 516}
 517
 518void ieee80211_get_vht_mask_from_cap(__le16 vht_cap,
 519                                     u16 vht_mask[NL80211_VHT_NSS_MAX])
 520{
 521        int i;
 522        u16 mask, cap = le16_to_cpu(vht_cap);
 523
 524        for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
 525                mask = (cap >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
 526                switch (mask) {
 527                case IEEE80211_VHT_MCS_SUPPORT_0_7:
 528                        vht_mask[i] = 0x00FF;
 529                        break;
 530                case IEEE80211_VHT_MCS_SUPPORT_0_8:
 531                        vht_mask[i] = 0x01FF;
 532                        break;
 533                case IEEE80211_VHT_MCS_SUPPORT_0_9:
 534                        vht_mask[i] = 0x03FF;
 535                        break;
 536                case IEEE80211_VHT_MCS_NOT_SUPPORTED:
 537                default:
 538                        vht_mask[i] = 0;
 539                        break;
 540                }
 541        }
 542}
 543