linux/net/mac80211/ht.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * HT handling
   4 *
   5 * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
   6 * Copyright 2002-2005, Instant802 Networks, Inc.
   7 * Copyright 2005-2006, Devicescape Software, Inc.
   8 * Copyright 2006-2007  Jiri Benc <jbenc@suse.cz>
   9 * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  10 * Copyright 2007-2010, Intel Corporation
  11 * Copyright 2017       Intel Deutschland GmbH
  12 */
  13
  14#include <linux/ieee80211.h>
  15#include <linux/export.h>
  16#include <net/mac80211.h>
  17#include "ieee80211_i.h"
  18#include "rate.h"
  19
  20static void __check_htcap_disable(struct ieee80211_ht_cap *ht_capa,
  21                                  struct ieee80211_ht_cap *ht_capa_mask,
  22                                  struct ieee80211_sta_ht_cap *ht_cap,
  23                                  u16 flag)
  24{
  25        __le16 le_flag = cpu_to_le16(flag);
  26        if (ht_capa_mask->cap_info & le_flag) {
  27                if (!(ht_capa->cap_info & le_flag))
  28                        ht_cap->cap &= ~flag;
  29        }
  30}
  31
  32static void __check_htcap_enable(struct ieee80211_ht_cap *ht_capa,
  33                                  struct ieee80211_ht_cap *ht_capa_mask,
  34                                  struct ieee80211_sta_ht_cap *ht_cap,
  35                                  u16 flag)
  36{
  37        __le16 le_flag = cpu_to_le16(flag);
  38
  39        if ((ht_capa_mask->cap_info & le_flag) &&
  40            (ht_capa->cap_info & le_flag))
  41                ht_cap->cap |= flag;
  42}
  43
  44void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
  45                                     struct ieee80211_sta_ht_cap *ht_cap)
  46{
  47        struct ieee80211_ht_cap *ht_capa, *ht_capa_mask;
  48        u8 *scaps, *smask;
  49        int i;
  50
  51        if (!ht_cap->ht_supported)
  52                return;
  53
  54        switch (sdata->vif.type) {
  55        case NL80211_IFTYPE_STATION:
  56                ht_capa = &sdata->u.mgd.ht_capa;
  57                ht_capa_mask = &sdata->u.mgd.ht_capa_mask;
  58                break;
  59        case NL80211_IFTYPE_ADHOC:
  60                ht_capa = &sdata->u.ibss.ht_capa;
  61                ht_capa_mask = &sdata->u.ibss.ht_capa_mask;
  62                break;
  63        default:
  64                WARN_ON_ONCE(1);
  65                return;
  66        }
  67
  68        scaps = (u8 *)(&ht_capa->mcs.rx_mask);
  69        smask = (u8 *)(&ht_capa_mask->mcs.rx_mask);
  70
  71        /* NOTE:  If you add more over-rides here, update register_hw
  72         * ht_capa_mod_mask logic in main.c as well.
  73         * And, if this method can ever change ht_cap.ht_supported, fix
  74         * the check in ieee80211_add_ht_ie.
  75         */
  76
  77        /* check for HT over-rides, MCS rates first. */
  78        for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
  79                u8 m = smask[i];
  80                ht_cap->mcs.rx_mask[i] &= ~m; /* turn off all masked bits */
  81                /* Add back rates that are supported */
  82                ht_cap->mcs.rx_mask[i] |= (m & scaps[i]);
  83        }
  84
  85        /* Force removal of HT-40 capabilities? */
  86        __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap,
  87                              IEEE80211_HT_CAP_SUP_WIDTH_20_40);
  88        __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap,
  89                              IEEE80211_HT_CAP_SGI_40);
  90
  91        /* Allow user to disable SGI-20 (SGI-40 is handled above) */
  92        __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap,
  93                              IEEE80211_HT_CAP_SGI_20);
  94
  95        /* Allow user to disable the max-AMSDU bit. */
  96        __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap,
  97                              IEEE80211_HT_CAP_MAX_AMSDU);
  98
  99        /* Allow user to disable LDPC */
 100        __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap,
 101                              IEEE80211_HT_CAP_LDPC_CODING);
 102
 103        /* Allow user to enable 40 MHz intolerant bit. */
 104        __check_htcap_enable(ht_capa, ht_capa_mask, ht_cap,
 105                             IEEE80211_HT_CAP_40MHZ_INTOLERANT);
 106
 107        /* Allow user to enable TX STBC bit  */
 108        __check_htcap_enable(ht_capa, ht_capa_mask, ht_cap,
 109                             IEEE80211_HT_CAP_TX_STBC);
 110
 111        /* Allow user to configure RX STBC bits */
 112        if (ht_capa_mask->cap_info & cpu_to_le16(IEEE80211_HT_CAP_RX_STBC))
 113                ht_cap->cap |= le16_to_cpu(ht_capa->cap_info) &
 114                                        IEEE80211_HT_CAP_RX_STBC;
 115
 116        /* Allow user to decrease AMPDU factor */
 117        if (ht_capa_mask->ampdu_params_info &
 118            IEEE80211_HT_AMPDU_PARM_FACTOR) {
 119                u8 n = ht_capa->ampdu_params_info &
 120                       IEEE80211_HT_AMPDU_PARM_FACTOR;
 121                if (n < ht_cap->ampdu_factor)
 122                        ht_cap->ampdu_factor = n;
 123        }
 124
 125        /* Allow the user to increase AMPDU density. */
 126        if (ht_capa_mask->ampdu_params_info &
 127            IEEE80211_HT_AMPDU_PARM_DENSITY) {
 128                u8 n = (ht_capa->ampdu_params_info &
 129                        IEEE80211_HT_AMPDU_PARM_DENSITY)
 130                        >> IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT;
 131                if (n > ht_cap->ampdu_density)
 132                        ht_cap->ampdu_density = n;
 133        }
 134}
 135
 136
 137bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
 138                                       struct ieee80211_supported_band *sband,
 139                                       const struct ieee80211_ht_cap *ht_cap_ie,
 140                                       struct sta_info *sta)
 141{
 142        struct ieee80211_sta_ht_cap ht_cap, own_cap;
 143        u8 ampdu_info, tx_mcs_set_cap;
 144        int i, max_tx_streams;
 145        bool changed;
 146        enum ieee80211_sta_rx_bandwidth bw;
 147        enum ieee80211_smps_mode smps_mode;
 148
 149        memset(&ht_cap, 0, sizeof(ht_cap));
 150
 151        if (!ht_cap_ie || !sband->ht_cap.ht_supported)
 152                goto apply;
 153
 154        ht_cap.ht_supported = true;
 155
 156        own_cap = sband->ht_cap;
 157
 158        /*
 159         * If user has specified capability over-rides, take care
 160         * of that if the station we're setting up is the AP or TDLS peer that
 161         * we advertised a restricted capability set to. Override
 162         * our own capabilities and then use those below.
 163         */
 164        if (sdata->vif.type == NL80211_IFTYPE_STATION ||
 165            sdata->vif.type == NL80211_IFTYPE_ADHOC)
 166                ieee80211_apply_htcap_overrides(sdata, &own_cap);
 167
 168        /*
 169         * The bits listed in this expression should be
 170         * the same for the peer and us, if the station
 171         * advertises more then we can't use those thus
 172         * we mask them out.
 173         */
 174        ht_cap.cap = le16_to_cpu(ht_cap_ie->cap_info) &
 175                (own_cap.cap | ~(IEEE80211_HT_CAP_LDPC_CODING |
 176                                 IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
 177                                 IEEE80211_HT_CAP_GRN_FLD |
 178                                 IEEE80211_HT_CAP_SGI_20 |
 179                                 IEEE80211_HT_CAP_SGI_40 |
 180                                 IEEE80211_HT_CAP_DSSSCCK40));
 181
 182        /*
 183         * The STBC bits are asymmetric -- if we don't have
 184         * TX then mask out the peer's RX and vice versa.
 185         */
 186        if (!(own_cap.cap & IEEE80211_HT_CAP_TX_STBC))
 187                ht_cap.cap &= ~IEEE80211_HT_CAP_RX_STBC;
 188        if (!(own_cap.cap & IEEE80211_HT_CAP_RX_STBC))
 189                ht_cap.cap &= ~IEEE80211_HT_CAP_TX_STBC;
 190
 191        ampdu_info = ht_cap_ie->ampdu_params_info;
 192        ht_cap.ampdu_factor =
 193                ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
 194        ht_cap.ampdu_density =
 195                (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
 196
 197        /* own MCS TX capabilities */
 198        tx_mcs_set_cap = own_cap.mcs.tx_params;
 199
 200        /* Copy peer MCS TX capabilities, the driver might need them. */
 201        ht_cap.mcs.tx_params = ht_cap_ie->mcs.tx_params;
 202
 203        /* can we TX with MCS rates? */
 204        if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED))
 205                goto apply;
 206
 207        /* Counting from 0, therefore +1 */
 208        if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF)
 209                max_tx_streams =
 210                        ((tx_mcs_set_cap & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
 211                                >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1;
 212        else
 213                max_tx_streams = IEEE80211_HT_MCS_TX_MAX_STREAMS;
 214
 215        /*
 216         * 802.11n-2009 20.3.5 / 20.6 says:
 217         * - indices 0 to 7 and 32 are single spatial stream
 218         * - 8 to 31 are multiple spatial streams using equal modulation
 219         *   [8..15 for two streams, 16..23 for three and 24..31 for four]
 220         * - remainder are multiple spatial streams using unequal modulation
 221         */
 222        for (i = 0; i < max_tx_streams; i++)
 223                ht_cap.mcs.rx_mask[i] =
 224                        own_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
 225
 226        if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
 227                for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
 228                     i < IEEE80211_HT_MCS_MASK_LEN; i++)
 229                        ht_cap.mcs.rx_mask[i] =
 230                                own_cap.mcs.rx_mask[i] &
 231                                        ht_cap_ie->mcs.rx_mask[i];
 232
 233        /* handle MCS rate 32 too */
 234        if (own_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
 235                ht_cap.mcs.rx_mask[32/8] |= 1;
 236
 237        /* set Rx highest rate */
 238        ht_cap.mcs.rx_highest = ht_cap_ie->mcs.rx_highest;
 239
 240        if (ht_cap.cap & IEEE80211_HT_CAP_MAX_AMSDU)
 241                sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_7935;
 242        else
 243                sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_3839;
 244
 245 apply:
 246        changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
 247
 248        memcpy(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
 249
 250        switch (sdata->vif.bss_conf.chandef.width) {
 251        default:
 252                WARN_ON_ONCE(1);
 253                /* fall through */
 254        case NL80211_CHAN_WIDTH_20_NOHT:
 255        case NL80211_CHAN_WIDTH_20:
 256                bw = IEEE80211_STA_RX_BW_20;
 257                break;
 258        case NL80211_CHAN_WIDTH_40:
 259        case NL80211_CHAN_WIDTH_80:
 260        case NL80211_CHAN_WIDTH_80P80:
 261        case NL80211_CHAN_WIDTH_160:
 262                bw = ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
 263                                IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
 264                break;
 265        }
 266
 267        sta->sta.bandwidth = bw;
 268
 269        sta->cur_max_bandwidth =
 270                ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
 271                                IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
 272
 273        switch ((ht_cap.cap & IEEE80211_HT_CAP_SM_PS)
 274                        >> IEEE80211_HT_CAP_SM_PS_SHIFT) {
 275        case WLAN_HT_CAP_SM_PS_INVALID:
 276        case WLAN_HT_CAP_SM_PS_STATIC:
 277                smps_mode = IEEE80211_SMPS_STATIC;
 278                break;
 279        case WLAN_HT_CAP_SM_PS_DYNAMIC:
 280                smps_mode = IEEE80211_SMPS_DYNAMIC;
 281                break;
 282        case WLAN_HT_CAP_SM_PS_DISABLED:
 283                smps_mode = IEEE80211_SMPS_OFF;
 284                break;
 285        }
 286
 287        if (smps_mode != sta->sta.smps_mode)
 288                changed = true;
 289        sta->sta.smps_mode = smps_mode;
 290
 291        return changed;
 292}
 293
 294void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
 295                                         enum ieee80211_agg_stop_reason reason)
 296{
 297        int i;
 298
 299        mutex_lock(&sta->ampdu_mlme.mtx);
 300        for (i = 0; i <  IEEE80211_NUM_TIDS; i++)
 301                ___ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
 302                                                WLAN_REASON_QSTA_LEAVE_QBSS,
 303                                                reason != AGG_STOP_DESTROY_STA &&
 304                                                reason != AGG_STOP_PEER_REQUEST);
 305
 306        for (i = 0; i <  IEEE80211_NUM_TIDS; i++)
 307                ___ieee80211_stop_tx_ba_session(sta, i, reason);
 308        mutex_unlock(&sta->ampdu_mlme.mtx);
 309
 310        /*
 311         * In case the tear down is part of a reconfigure due to HW restart
 312         * request, it is possible that the low level driver requested to stop
 313         * the BA session, so handle it to properly clean tid_tx data.
 314         */
 315        if(reason == AGG_STOP_DESTROY_STA) {
 316                cancel_work_sync(&sta->ampdu_mlme.work);
 317
 318                mutex_lock(&sta->ampdu_mlme.mtx);
 319                for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
 320                        struct tid_ampdu_tx *tid_tx =
 321                                rcu_dereference_protected_tid_tx(sta, i);
 322
 323                        if (!tid_tx)
 324                                continue;
 325
 326                        if (test_and_clear_bit(HT_AGG_STATE_STOP_CB, &tid_tx->state))
 327                                ieee80211_stop_tx_ba_cb(sta, i, tid_tx);
 328                }
 329                mutex_unlock(&sta->ampdu_mlme.mtx);
 330        }
 331}
 332
 333void ieee80211_ba_session_work(struct work_struct *work)
 334{
 335        struct sta_info *sta =
 336                container_of(work, struct sta_info, ampdu_mlme.work);
 337        struct tid_ampdu_tx *tid_tx;
 338        bool blocked;
 339        int tid;
 340
 341        /* When this flag is set, new sessions should be blocked. */
 342        blocked = test_sta_flag(sta, WLAN_STA_BLOCK_BA);
 343
 344        mutex_lock(&sta->ampdu_mlme.mtx);
 345        for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
 346                if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired))
 347                        ___ieee80211_stop_rx_ba_session(
 348                                sta, tid, WLAN_BACK_RECIPIENT,
 349                                WLAN_REASON_QSTA_TIMEOUT, true);
 350
 351                if (test_and_clear_bit(tid,
 352                                       sta->ampdu_mlme.tid_rx_stop_requested))
 353                        ___ieee80211_stop_rx_ba_session(
 354                                sta, tid, WLAN_BACK_RECIPIENT,
 355                                WLAN_REASON_UNSPECIFIED, true);
 356
 357                if (!blocked &&
 358                    test_and_clear_bit(tid,
 359                                       sta->ampdu_mlme.tid_rx_manage_offl))
 360                        ___ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid,
 361                                                         IEEE80211_MAX_AMPDU_BUF_HT,
 362                                                         false, true);
 363
 364                if (test_and_clear_bit(tid + IEEE80211_NUM_TIDS,
 365                                       sta->ampdu_mlme.tid_rx_manage_offl))
 366                        ___ieee80211_stop_rx_ba_session(
 367                                sta, tid, WLAN_BACK_RECIPIENT,
 368                                0, false);
 369
 370                spin_lock_bh(&sta->lock);
 371
 372                tid_tx = sta->ampdu_mlme.tid_start_tx[tid];
 373                if (!blocked && tid_tx) {
 374                        /*
 375                         * Assign it over to the normal tid_tx array
 376                         * where it "goes live".
 377                         */
 378
 379                        sta->ampdu_mlme.tid_start_tx[tid] = NULL;
 380                        /* could there be a race? */
 381                        if (sta->ampdu_mlme.tid_tx[tid])
 382                                kfree(tid_tx);
 383                        else
 384                                ieee80211_assign_tid_tx(sta, tid, tid_tx);
 385                        spin_unlock_bh(&sta->lock);
 386
 387                        ieee80211_tx_ba_session_handle_start(sta, tid);
 388                        continue;
 389                }
 390                spin_unlock_bh(&sta->lock);
 391
 392                tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
 393                if (!tid_tx)
 394                        continue;
 395
 396                if (!blocked &&
 397                    test_and_clear_bit(HT_AGG_STATE_START_CB, &tid_tx->state))
 398                        ieee80211_start_tx_ba_cb(sta, tid, tid_tx);
 399                if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state))
 400                        ___ieee80211_stop_tx_ba_session(sta, tid,
 401                                                        AGG_STOP_LOCAL_REQUEST);
 402                if (test_and_clear_bit(HT_AGG_STATE_STOP_CB, &tid_tx->state))
 403                        ieee80211_stop_tx_ba_cb(sta, tid, tid_tx);
 404        }
 405        mutex_unlock(&sta->ampdu_mlme.mtx);
 406}
 407
 408void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
 409                          const u8 *da, u16 tid,
 410                          u16 initiator, u16 reason_code)
 411{
 412        struct ieee80211_local *local = sdata->local;
 413        struct sk_buff *skb;
 414        struct ieee80211_mgmt *mgmt;
 415        u16 params;
 416
 417        skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
 418        if (!skb)
 419                return;
 420
 421        skb_reserve(skb, local->hw.extra_tx_headroom);
 422        mgmt = skb_put_zero(skb, 24);
 423        memcpy(mgmt->da, da, ETH_ALEN);
 424        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
 425        if (sdata->vif.type == NL80211_IFTYPE_AP ||
 426            sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
 427            sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
 428                memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
 429        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
 430                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
 431        else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
 432                memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
 433
 434        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 435                                          IEEE80211_STYPE_ACTION);
 436
 437        skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba));
 438
 439        mgmt->u.action.category = WLAN_CATEGORY_BACK;
 440        mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
 441        params = (u16)(initiator << 11);        /* bit 11 initiator */
 442        params |= (u16)(tid << 12);             /* bit 15:12 TID number */
 443
 444        mgmt->u.action.u.delba.params = cpu_to_le16(params);
 445        mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
 446
 447        ieee80211_tx_skb(sdata, skb);
 448}
 449
 450void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
 451                             struct sta_info *sta,
 452                             struct ieee80211_mgmt *mgmt, size_t len)
 453{
 454        u16 tid, params;
 455        u16 initiator;
 456
 457        params = le16_to_cpu(mgmt->u.action.u.delba.params);
 458        tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
 459        initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11;
 460
 461        ht_dbg_ratelimited(sdata, "delba from %pM (%s) tid %d reason code %d\n",
 462                           mgmt->sa, initiator ? "initiator" : "recipient",
 463                           tid,
 464                           le16_to_cpu(mgmt->u.action.u.delba.reason_code));
 465
 466        if (initiator == WLAN_BACK_INITIATOR)
 467                __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0,
 468                                               true);
 469        else
 470                __ieee80211_stop_tx_ba_session(sta, tid, AGG_STOP_PEER_REQUEST);
 471}
 472
 473enum nl80211_smps_mode
 474ieee80211_smps_mode_to_smps_mode(enum ieee80211_smps_mode smps)
 475{
 476        switch (smps) {
 477        case IEEE80211_SMPS_OFF:
 478                return NL80211_SMPS_OFF;
 479        case IEEE80211_SMPS_STATIC:
 480                return NL80211_SMPS_STATIC;
 481        case IEEE80211_SMPS_DYNAMIC:
 482                return NL80211_SMPS_DYNAMIC;
 483        default:
 484                return NL80211_SMPS_OFF;
 485        }
 486}
 487
 488int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
 489                               enum ieee80211_smps_mode smps, const u8 *da,
 490                               const u8 *bssid)
 491{
 492        struct ieee80211_local *local = sdata->local;
 493        struct sk_buff *skb;
 494        struct ieee80211_mgmt *action_frame;
 495
 496        /* 27 = header + category + action + smps mode */
 497        skb = dev_alloc_skb(27 + local->hw.extra_tx_headroom);
 498        if (!skb)
 499                return -ENOMEM;
 500
 501        skb_reserve(skb, local->hw.extra_tx_headroom);
 502        action_frame = skb_put(skb, 27);
 503        memcpy(action_frame->da, da, ETH_ALEN);
 504        memcpy(action_frame->sa, sdata->dev->dev_addr, ETH_ALEN);
 505        memcpy(action_frame->bssid, bssid, ETH_ALEN);
 506        action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 507                                                  IEEE80211_STYPE_ACTION);
 508        action_frame->u.action.category = WLAN_CATEGORY_HT;
 509        action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS;
 510        switch (smps) {
 511        case IEEE80211_SMPS_AUTOMATIC:
 512        case IEEE80211_SMPS_NUM_MODES:
 513                WARN_ON(1);
 514                /* fall through */
 515        case IEEE80211_SMPS_OFF:
 516                action_frame->u.action.u.ht_smps.smps_control =
 517                                WLAN_HT_SMPS_CONTROL_DISABLED;
 518                break;
 519        case IEEE80211_SMPS_STATIC:
 520                action_frame->u.action.u.ht_smps.smps_control =
 521                                WLAN_HT_SMPS_CONTROL_STATIC;
 522                break;
 523        case IEEE80211_SMPS_DYNAMIC:
 524                action_frame->u.action.u.ht_smps.smps_control =
 525                                WLAN_HT_SMPS_CONTROL_DYNAMIC;
 526                break;
 527        }
 528
 529        /* we'll do more on status of this frame */
 530        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
 531        ieee80211_tx_skb(sdata, skb);
 532
 533        return 0;
 534}
 535
 536void ieee80211_request_smps_mgd_work(struct work_struct *work)
 537{
 538        struct ieee80211_sub_if_data *sdata =
 539                container_of(work, struct ieee80211_sub_if_data,
 540                             u.mgd.request_smps_work);
 541
 542        sdata_lock(sdata);
 543        __ieee80211_request_smps_mgd(sdata, sdata->u.mgd.driver_smps_mode);
 544        sdata_unlock(sdata);
 545}
 546
 547void ieee80211_request_smps_ap_work(struct work_struct *work)
 548{
 549        struct ieee80211_sub_if_data *sdata =
 550                container_of(work, struct ieee80211_sub_if_data,
 551                             u.ap.request_smps_work);
 552
 553        sdata_lock(sdata);
 554        if (sdata_dereference(sdata->u.ap.beacon, sdata))
 555                __ieee80211_request_smps_ap(sdata,
 556                                            sdata->u.ap.driver_smps_mode);
 557        sdata_unlock(sdata);
 558}
 559
 560void ieee80211_request_smps(struct ieee80211_vif *vif,
 561                            enum ieee80211_smps_mode smps_mode)
 562{
 563        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 564
 565        if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION &&
 566                         vif->type != NL80211_IFTYPE_AP))
 567                return;
 568
 569        if (vif->type == NL80211_IFTYPE_STATION) {
 570                if (sdata->u.mgd.driver_smps_mode == smps_mode)
 571                        return;
 572                sdata->u.mgd.driver_smps_mode = smps_mode;
 573                ieee80211_queue_work(&sdata->local->hw,
 574                                     &sdata->u.mgd.request_smps_work);
 575        } else {
 576                /* AUTOMATIC is meaningless in AP mode */
 577                if (WARN_ON_ONCE(smps_mode == IEEE80211_SMPS_AUTOMATIC))
 578                        return;
 579                if (sdata->u.ap.driver_smps_mode == smps_mode)
 580                        return;
 581                sdata->u.ap.driver_smps_mode = smps_mode;
 582                ieee80211_queue_work(&sdata->local->hw,
 583                                     &sdata->u.ap.request_smps_work);
 584        }
 585}
 586/* this might change ... don't want non-open drivers using it */
 587EXPORT_SYMBOL_GPL(ieee80211_request_smps);
 588