LCOV - code coverage report
Current view: top level - net/mac80211 - ht.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 284 0.0 %
Date: 2022-03-28 16:04:14 Functions: 0 11 0.0 %
Branches: 0 157 0.0 %

           Branch data     Line data    Source code
       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                 :            : 
      20                 :          0 : static 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                 :          0 :         __le16 le_flag = cpu_to_le16(flag);
      26                 :          0 :         if (ht_capa_mask->cap_info & le_flag) {
      27   [ #  #  #  #  :          0 :                 if (!(ht_capa->cap_info & le_flag))
          #  #  #  #  #  
                      # ]
      28                 :          0 :                         ht_cap->cap &= ~flag;
      29                 :            :         }
      30                 :            : }
      31                 :            : 
      32                 :          0 : static 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                 :          0 :         __le16 le_flag = cpu_to_le16(flag);
      38                 :            : 
      39                 :          0 :         if ((ht_capa_mask->cap_info & le_flag) &&
      40   [ #  #  #  # ]:          0 :             (ht_capa->cap_info & le_flag))
      41                 :          0 :                 ht_cap->cap |= flag;
      42                 :            : }
      43                 :            : 
      44                 :          0 : void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
      45                 :            :                                      struct ieee80211_sta_ht_cap *ht_cap)
      46                 :            : {
      47                 :          0 :         struct ieee80211_ht_cap *ht_capa, *ht_capa_mask;
      48                 :          0 :         u8 *scaps, *smask;
      49                 :          0 :         int i;
      50                 :            : 
      51         [ #  # ]:          0 :         if (!ht_cap->ht_supported)
      52                 :            :                 return;
      53                 :            : 
      54      [ #  #  # ]:          0 :         switch (sdata->vif.type) {
      55                 :          0 :         case NL80211_IFTYPE_STATION:
      56                 :          0 :                 ht_capa = &sdata->u.mgd.ht_capa;
      57                 :          0 :                 ht_capa_mask = &sdata->u.mgd.ht_capa_mask;
      58                 :          0 :                 break;
      59                 :          0 :         case NL80211_IFTYPE_ADHOC:
      60                 :          0 :                 ht_capa = &sdata->u.ibss.ht_capa;
      61                 :          0 :                 ht_capa_mask = &sdata->u.ibss.ht_capa_mask;
      62                 :          0 :                 break;
      63                 :            :         default:
      64                 :          0 :                 WARN_ON_ONCE(1);
      65                 :          0 :                 return;
      66                 :            :         }
      67                 :            : 
      68                 :          0 :         scaps = (u8 *)(&ht_capa->mcs.rx_mask);
      69                 :          0 :         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         [ #  # ]:          0 :         for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
      79                 :          0 :                 u8 m = smask[i];
      80                 :          0 :                 ht_cap->mcs.rx_mask[i] &= ~m; /* turn off all masked bits */
      81                 :            :                 /* Add back rates that are supported */
      82                 :          0 :                 ht_cap->mcs.rx_mask[i] |= (m & scaps[i]);
      83                 :            :         }
      84                 :            : 
      85                 :            :         /* Force removal of HT-40 capabilities? */
      86         [ #  # ]:          0 :         __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap,
      87                 :            :                               IEEE80211_HT_CAP_SUP_WIDTH_20_40);
      88         [ #  # ]:          0 :         __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         [ #  # ]:          0 :         __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         [ #  # ]:          0 :         __check_htcap_disable(ht_capa, ht_capa_mask, ht_cap,
      97                 :            :                               IEEE80211_HT_CAP_MAX_AMSDU);
      98                 :            : 
      99                 :            :         /* Allow user to disable LDPC */
     100         [ #  # ]:          0 :         __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         [ #  # ]:          0 :         __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         [ #  # ]:          0 :         __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         [ #  # ]:          0 :         if (ht_capa_mask->cap_info & cpu_to_le16(IEEE80211_HT_CAP_RX_STBC))
     113                 :          0 :                 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         [ #  # ]:          0 :         if (ht_capa_mask->ampdu_params_info &
     118                 :            :             IEEE80211_HT_AMPDU_PARM_FACTOR) {
     119                 :          0 :                 u8 n = ht_capa->ampdu_params_info &
     120                 :            :                        IEEE80211_HT_AMPDU_PARM_FACTOR;
     121         [ #  # ]:          0 :                 if (n < ht_cap->ampdu_factor)
     122                 :          0 :                         ht_cap->ampdu_factor = n;
     123                 :            :         }
     124                 :            : 
     125                 :            :         /* Allow the user to increase AMPDU density. */
     126         [ #  # ]:          0 :         if (ht_capa_mask->ampdu_params_info &
     127                 :            :             IEEE80211_HT_AMPDU_PARM_DENSITY) {
     128                 :          0 :                 u8 n = (ht_capa->ampdu_params_info &
     129                 :            :                         IEEE80211_HT_AMPDU_PARM_DENSITY)
     130                 :          0 :                         >> IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT;
     131         [ #  # ]:          0 :                 if (n > ht_cap->ampdu_density)
     132                 :          0 :                         ht_cap->ampdu_density = n;
     133                 :            :         }
     134                 :            : }
     135                 :            : 
     136                 :            : 
     137                 :          0 : bool 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                 :          0 :         struct ieee80211_sta_ht_cap ht_cap, own_cap;
     143                 :          0 :         u8 ampdu_info, tx_mcs_set_cap;
     144                 :          0 :         int i, max_tx_streams;
     145                 :          0 :         bool changed;
     146                 :          0 :         enum ieee80211_sta_rx_bandwidth bw;
     147                 :          0 :         enum ieee80211_smps_mode smps_mode;
     148                 :            : 
     149                 :          0 :         memset(&ht_cap, 0, sizeof(ht_cap));
     150                 :            : 
     151   [ #  #  #  # ]:          0 :         if (!ht_cap_ie || !sband->ht_cap.ht_supported)
     152                 :          0 :                 goto apply;
     153                 :            : 
     154                 :          0 :         ht_cap.ht_supported = true;
     155                 :            : 
     156                 :          0 :         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         [ #  # ]:          0 :         if (sdata->vif.type == NL80211_IFTYPE_STATION ||
     165                 :            :             sdata->vif.type == NL80211_IFTYPE_ADHOC)
     166                 :          0 :                 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                 :          0 :         ht_cap.cap = le16_to_cpu(ht_cap_ie->cap_info) &
     175                 :          0 :                 (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         [ #  # ]:          0 :         if (!(own_cap.cap & IEEE80211_HT_CAP_TX_STBC))
     187                 :          0 :                 ht_cap.cap &= ~IEEE80211_HT_CAP_RX_STBC;
     188         [ #  # ]:          0 :         if (!(own_cap.cap & IEEE80211_HT_CAP_RX_STBC))
     189                 :          0 :                 ht_cap.cap &= ~IEEE80211_HT_CAP_TX_STBC;
     190                 :            : 
     191                 :          0 :         ampdu_info = ht_cap_ie->ampdu_params_info;
     192                 :          0 :         ht_cap.ampdu_factor =
     193                 :          0 :                 ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
     194                 :          0 :         ht_cap.ampdu_density =
     195                 :          0 :                 (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
     196                 :            : 
     197                 :            :         /* own MCS TX capabilities */
     198                 :          0 :         tx_mcs_set_cap = own_cap.mcs.tx_params;
     199                 :            : 
     200                 :            :         /* Copy peer MCS TX capabilities, the driver might need them. */
     201                 :          0 :         ht_cap.mcs.tx_params = ht_cap_ie->mcs.tx_params;
     202                 :            : 
     203                 :            :         /* can we TX with MCS rates? */
     204         [ #  # ]:          0 :         if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED))
     205                 :          0 :                 goto apply;
     206                 :            : 
     207                 :            :         /* Counting from 0, therefore +1 */
     208         [ #  # ]:          0 :         if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF)
     209                 :          0 :                 max_tx_streams =
     210                 :            :                         ((tx_mcs_set_cap & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
     211                 :          0 :                                 >> 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         [ #  # ]:          0 :         for (i = 0; i < max_tx_streams; i++)
     223                 :          0 :                 ht_cap.mcs.rx_mask[i] =
     224                 :          0 :                         own_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
     225                 :            : 
     226         [ #  # ]:          0 :         if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
     227                 :          0 :                 for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
     228         [ #  # ]:          0 :                      i < IEEE80211_HT_MCS_MASK_LEN; i++)
     229                 :          0 :                         ht_cap.mcs.rx_mask[i] =
     230                 :          0 :                                 own_cap.mcs.rx_mask[i] &
     231                 :          0 :                                         ht_cap_ie->mcs.rx_mask[i];
     232                 :            : 
     233                 :            :         /* handle MCS rate 32 too */
     234         [ #  # ]:          0 :         if (own_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
     235                 :          0 :                 ht_cap.mcs.rx_mask[32/8] |= 1;
     236                 :            : 
     237                 :            :         /* set Rx highest rate */
     238                 :          0 :         ht_cap.mcs.rx_highest = ht_cap_ie->mcs.rx_highest;
     239                 :            : 
     240         [ #  # ]:          0 :         if (ht_cap.cap & IEEE80211_HT_CAP_MAX_AMSDU)
     241                 :          0 :                 sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_7935;
     242                 :            :         else
     243                 :          0 :                 sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_3839;
     244                 :            : 
     245                 :          0 :  apply:
     246                 :          0 :         changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
     247                 :            : 
     248                 :          0 :         memcpy(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
     249                 :            : 
     250      [ #  #  # ]:          0 :         switch (sdata->vif.bss_conf.chandef.width) {
     251                 :            :         default:
     252                 :          0 :                 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                 :          0 :         case NL80211_CHAN_WIDTH_40:
     259                 :            :         case NL80211_CHAN_WIDTH_80:
     260                 :            :         case NL80211_CHAN_WIDTH_80P80:
     261                 :            :         case NL80211_CHAN_WIDTH_160:
     262                 :          0 :                 bw = ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
     263                 :          0 :                                 IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
     264                 :          0 :                 break;
     265                 :            :         }
     266                 :            : 
     267                 :          0 :         sta->sta.bandwidth = bw;
     268                 :            : 
     269                 :          0 :         sta->cur_max_bandwidth =
     270                 :          0 :                 ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
     271                 :          0 :                                 IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
     272                 :            : 
     273                 :          0 :         switch ((ht_cap.cap & IEEE80211_HT_CAP_SM_PS)
     274      [ #  #  # ]:          0 :                         >> 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                 :          0 :         case WLAN_HT_CAP_SM_PS_DYNAMIC:
     280                 :          0 :                 smps_mode = IEEE80211_SMPS_DYNAMIC;
     281                 :          0 :                 break;
     282                 :          0 :         case WLAN_HT_CAP_SM_PS_DISABLED:
     283                 :          0 :                 smps_mode = IEEE80211_SMPS_OFF;
     284                 :          0 :                 break;
     285                 :            :         }
     286                 :            : 
     287         [ #  # ]:          0 :         if (smps_mode != sta->sta.smps_mode)
     288                 :          0 :                 changed = true;
     289                 :          0 :         sta->sta.smps_mode = smps_mode;
     290                 :            : 
     291                 :          0 :         return changed;
     292                 :            : }
     293                 :            : 
     294                 :          0 : void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
     295                 :            :                                          enum ieee80211_agg_stop_reason reason)
     296                 :            : {
     297                 :          0 :         int i;
     298                 :            : 
     299                 :          0 :         mutex_lock(&sta->ampdu_mlme.mtx);
     300         [ #  # ]:          0 :         for (i = 0; i <  IEEE80211_NUM_TIDS; i++)
     301                 :          0 :                 ___ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
     302                 :            :                                                 WLAN_REASON_QSTA_LEAVE_QBSS,
     303                 :          0 :                                                 reason != AGG_STOP_DESTROY_STA &&
     304                 :            :                                                 reason != AGG_STOP_PEER_REQUEST);
     305                 :            : 
     306         [ #  # ]:          0 :         for (i = 0; i <  IEEE80211_NUM_TIDS; i++)
     307                 :          0 :                 ___ieee80211_stop_tx_ba_session(sta, i, reason);
     308                 :          0 :         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         [ #  # ]:          0 :         if(reason == AGG_STOP_DESTROY_STA) {
     316                 :          0 :                 cancel_work_sync(&sta->ampdu_mlme.work);
     317                 :            : 
     318                 :          0 :                 mutex_lock(&sta->ampdu_mlme.mtx);
     319         [ #  # ]:          0 :                 for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
     320         [ #  # ]:          0 :                         struct tid_ampdu_tx *tid_tx =
     321                 :            :                                 rcu_dereference_protected_tid_tx(sta, i);
     322                 :            : 
     323         [ #  # ]:          0 :                         if (!tid_tx)
     324                 :          0 :                                 continue;
     325                 :            : 
     326         [ #  # ]:          0 :                         if (test_and_clear_bit(HT_AGG_STATE_STOP_CB, &tid_tx->state))
     327                 :          0 :                                 ieee80211_stop_tx_ba_cb(sta, i, tid_tx);
     328                 :            :                 }
     329                 :          0 :                 mutex_unlock(&sta->ampdu_mlme.mtx);
     330                 :            :         }
     331                 :          0 : }
     332                 :            : 
     333                 :          0 : void ieee80211_ba_session_work(struct work_struct *work)
     334                 :            : {
     335                 :          0 :         struct sta_info *sta =
     336                 :          0 :                 container_of(work, struct sta_info, ampdu_mlme.work);
     337                 :          0 :         struct tid_ampdu_tx *tid_tx;
     338                 :          0 :         bool blocked;
     339                 :          0 :         int tid;
     340                 :            : 
     341                 :            :         /* When this flag is set, new sessions should be blocked. */
     342                 :          0 :         blocked = test_sta_flag(sta, WLAN_STA_BLOCK_BA);
     343                 :            : 
     344                 :          0 :         mutex_lock(&sta->ampdu_mlme.mtx);
     345         [ #  # ]:          0 :         for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
     346         [ #  # ]:          0 :                 if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired))
     347                 :          0 :                         ___ieee80211_stop_rx_ba_session(
     348                 :            :                                 sta, tid, WLAN_BACK_RECIPIENT,
     349                 :            :                                 WLAN_REASON_QSTA_TIMEOUT, true);
     350                 :            : 
     351         [ #  # ]:          0 :                 if (test_and_clear_bit(tid,
     352                 :          0 :                                        sta->ampdu_mlme.tid_rx_stop_requested))
     353                 :          0 :                         ___ieee80211_stop_rx_ba_session(
     354                 :            :                                 sta, tid, WLAN_BACK_RECIPIENT,
     355                 :            :                                 WLAN_REASON_UNSPECIFIED, true);
     356                 :            : 
     357   [ #  #  #  # ]:          0 :                 if (!blocked &&
     358                 :          0 :                     test_and_clear_bit(tid,
     359                 :          0 :                                        sta->ampdu_mlme.tid_rx_manage_offl))
     360                 :          0 :                         ___ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid,
     361                 :            :                                                          IEEE80211_MAX_AMPDU_BUF_HT,
     362                 :            :                                                          false, true, NULL);
     363                 :            : 
     364         [ #  # ]:          0 :                 if (test_and_clear_bit(tid + IEEE80211_NUM_TIDS,
     365                 :          0 :                                        sta->ampdu_mlme.tid_rx_manage_offl))
     366                 :          0 :                         ___ieee80211_stop_rx_ba_session(
     367                 :            :                                 sta, tid, WLAN_BACK_RECIPIENT,
     368                 :            :                                 0, false);
     369                 :            : 
     370                 :          0 :                 spin_lock_bh(&sta->lock);
     371                 :            : 
     372                 :          0 :                 tid_tx = sta->ampdu_mlme.tid_start_tx[tid];
     373         [ #  # ]:          0 :                 if (!blocked && tid_tx) {
     374                 :            :                         /*
     375                 :            :                          * Assign it over to the normal tid_tx array
     376                 :            :                          * where it "goes live".
     377                 :            :                          */
     378                 :            : 
     379                 :          0 :                         sta->ampdu_mlme.tid_start_tx[tid] = NULL;
     380                 :            :                         /* could there be a race? */
     381         [ #  # ]:          0 :                         if (sta->ampdu_mlme.tid_tx[tid])
     382                 :          0 :                                 kfree(tid_tx);
     383                 :            :                         else
     384                 :          0 :                                 ieee80211_assign_tid_tx(sta, tid, tid_tx);
     385                 :          0 :                         spin_unlock_bh(&sta->lock);
     386                 :            : 
     387                 :          0 :                         ieee80211_tx_ba_session_handle_start(sta, tid);
     388                 :          0 :                         continue;
     389                 :            :                 }
     390                 :          0 :                 spin_unlock_bh(&sta->lock);
     391                 :            : 
     392         [ #  # ]:          0 :                 tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
     393         [ #  # ]:          0 :                 if (!tid_tx)
     394                 :          0 :                         continue;
     395                 :            : 
     396   [ #  #  #  # ]:          0 :                 if (!blocked &&
     397                 :          0 :                     test_and_clear_bit(HT_AGG_STATE_START_CB, &tid_tx->state))
     398                 :          0 :                         ieee80211_start_tx_ba_cb(sta, tid, tid_tx);
     399         [ #  # ]:          0 :                 if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state))
     400                 :          0 :                         ___ieee80211_stop_tx_ba_session(sta, tid,
     401                 :            :                                                         AGG_STOP_LOCAL_REQUEST);
     402         [ #  # ]:          0 :                 if (test_and_clear_bit(HT_AGG_STATE_STOP_CB, &tid_tx->state))
     403                 :          0 :                         ieee80211_stop_tx_ba_cb(sta, tid, tid_tx);
     404                 :            :         }
     405                 :          0 :         mutex_unlock(&sta->ampdu_mlme.mtx);
     406                 :          0 : }
     407                 :            : 
     408                 :          0 : void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
     409                 :            :                           const u8 *da, u16 tid,
     410                 :            :                           u16 initiator, u16 reason_code)
     411                 :            : {
     412                 :          0 :         struct ieee80211_local *local = sdata->local;
     413                 :          0 :         struct sk_buff *skb;
     414                 :          0 :         struct ieee80211_mgmt *mgmt;
     415                 :          0 :         u16 params;
     416                 :            : 
     417                 :          0 :         skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
     418         [ #  # ]:          0 :         if (!skb)
     419                 :            :                 return;
     420                 :            : 
     421                 :          0 :         skb_reserve(skb, local->hw.extra_tx_headroom);
     422                 :          0 :         mgmt = skb_put_zero(skb, 24);
     423                 :          0 :         memcpy(mgmt->da, da, ETH_ALEN);
     424                 :          0 :         memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
     425                 :          0 :         if (sdata->vif.type == NL80211_IFTYPE_AP ||
     426         [ #  # ]:          0 :             sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
     427                 :            :             sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
     428                 :          0 :                 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
     429         [ #  # ]:          0 :         else if (sdata->vif.type == NL80211_IFTYPE_STATION)
     430                 :          0 :                 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
     431         [ #  # ]:          0 :         else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
     432                 :          0 :                 memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
     433                 :            : 
     434                 :          0 :         mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
     435                 :            :                                           IEEE80211_STYPE_ACTION);
     436                 :            : 
     437                 :          0 :         skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba));
     438                 :            : 
     439                 :          0 :         mgmt->u.action.category = WLAN_CATEGORY_BACK;
     440                 :          0 :         mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
     441                 :          0 :         params = (u16)(initiator << 11);  /* bit 11 initiator */
     442                 :          0 :         params |= (u16)(tid << 12);               /* bit 15:12 TID number */
     443                 :            : 
     444                 :          0 :         mgmt->u.action.u.delba.params = cpu_to_le16(params);
     445                 :          0 :         mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
     446                 :            : 
     447                 :          0 :         ieee80211_tx_skb(sdata, skb);
     448                 :            : }
     449                 :            : 
     450                 :          0 : void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
     451                 :            :                              struct sta_info *sta,
     452                 :            :                              struct ieee80211_mgmt *mgmt, size_t len)
     453                 :            : {
     454                 :          0 :         u16 tid, params;
     455                 :          0 :         u16 initiator;
     456                 :            : 
     457                 :          0 :         params = le16_to_cpu(mgmt->u.action.u.delba.params);
     458                 :          0 :         tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
     459                 :          0 :         initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11;
     460                 :            : 
     461                 :          0 :         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         [ #  # ]:          0 :         if (initiator == WLAN_BACK_INITIATOR)
     467                 :          0 :                 __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0,
     468                 :            :                                                true);
     469                 :            :         else
     470                 :          0 :                 __ieee80211_stop_tx_ba_session(sta, tid, AGG_STOP_PEER_REQUEST);
     471                 :          0 : }
     472                 :            : 
     473                 :            : enum nl80211_smps_mode
     474                 :          0 : ieee80211_smps_mode_to_smps_mode(enum ieee80211_smps_mode smps)
     475                 :            : {
     476      [ #  #  # ]:          0 :         switch (smps) {
     477                 :            :         case IEEE80211_SMPS_OFF:
     478                 :            :                 return NL80211_SMPS_OFF;
     479                 :          0 :         case IEEE80211_SMPS_STATIC:
     480                 :          0 :                 return NL80211_SMPS_STATIC;
     481                 :          0 :         case IEEE80211_SMPS_DYNAMIC:
     482                 :          0 :                 return NL80211_SMPS_DYNAMIC;
     483                 :            :         default:
     484                 :            :                 return NL80211_SMPS_OFF;
     485                 :            :         }
     486                 :            : }
     487                 :            : 
     488                 :          0 : int 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                 :          0 :         struct ieee80211_local *local = sdata->local;
     493                 :          0 :         struct sk_buff *skb;
     494                 :          0 :         struct ieee80211_mgmt *action_frame;
     495                 :            : 
     496                 :            :         /* 27 = header + category + action + smps mode */
     497                 :          0 :         skb = dev_alloc_skb(27 + local->hw.extra_tx_headroom);
     498         [ #  # ]:          0 :         if (!skb)
     499                 :            :                 return -ENOMEM;
     500                 :            : 
     501                 :          0 :         skb_reserve(skb, local->hw.extra_tx_headroom);
     502                 :          0 :         action_frame = skb_put(skb, 27);
     503                 :          0 :         memcpy(action_frame->da, da, ETH_ALEN);
     504                 :          0 :         memcpy(action_frame->sa, sdata->dev->dev_addr, ETH_ALEN);
     505                 :          0 :         memcpy(action_frame->bssid, bssid, ETH_ALEN);
     506                 :          0 :         action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
     507                 :            :                                                   IEEE80211_STYPE_ACTION);
     508                 :          0 :         action_frame->u.action.category = WLAN_CATEGORY_HT;
     509                 :          0 :         action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS;
     510   [ #  #  #  #  :          0 :         switch (smps) {
                      # ]
     511                 :            :         case IEEE80211_SMPS_AUTOMATIC:
     512                 :            :         case IEEE80211_SMPS_NUM_MODES:
     513                 :          0 :                 WARN_ON(1);
     514                 :            :                 /* fall through */
     515                 :          0 :         case IEEE80211_SMPS_OFF:
     516                 :          0 :                 action_frame->u.action.u.ht_smps.smps_control =
     517                 :            :                                 WLAN_HT_SMPS_CONTROL_DISABLED;
     518                 :          0 :                 break;
     519                 :          0 :         case IEEE80211_SMPS_STATIC:
     520                 :          0 :                 action_frame->u.action.u.ht_smps.smps_control =
     521                 :            :                                 WLAN_HT_SMPS_CONTROL_STATIC;
     522                 :          0 :                 break;
     523                 :          0 :         case IEEE80211_SMPS_DYNAMIC:
     524                 :          0 :                 action_frame->u.action.u.ht_smps.smps_control =
     525                 :            :                                 WLAN_HT_SMPS_CONTROL_DYNAMIC;
     526                 :          0 :                 break;
     527                 :            :         }
     528                 :            : 
     529                 :            :         /* we'll do more on status of this frame */
     530                 :          0 :         IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
     531                 :          0 :         ieee80211_tx_skb(sdata, skb);
     532                 :            : 
     533                 :          0 :         return 0;
     534                 :            : }
     535                 :            : 
     536                 :          0 : void ieee80211_request_smps_mgd_work(struct work_struct *work)
     537                 :            : {
     538                 :          0 :         struct ieee80211_sub_if_data *sdata =
     539                 :          0 :                 container_of(work, struct ieee80211_sub_if_data,
     540                 :            :                              u.mgd.request_smps_work);
     541                 :            : 
     542                 :          0 :         sdata_lock(sdata);
     543                 :          0 :         __ieee80211_request_smps_mgd(sdata, sdata->u.mgd.driver_smps_mode);
     544                 :          0 :         sdata_unlock(sdata);
     545                 :          0 : }
     546                 :            : 
     547                 :          0 : void ieee80211_request_smps_ap_work(struct work_struct *work)
     548                 :            : {
     549                 :          0 :         struct ieee80211_sub_if_data *sdata =
     550                 :          0 :                 container_of(work, struct ieee80211_sub_if_data,
     551                 :            :                              u.ap.request_smps_work);
     552                 :            : 
     553                 :          0 :         sdata_lock(sdata);
     554         [ #  # ]:          0 :         if (sdata_dereference(sdata->u.ap.beacon, sdata))
     555                 :          0 :                 __ieee80211_request_smps_ap(sdata,
     556                 :            :                                             sdata->u.ap.driver_smps_mode);
     557                 :          0 :         sdata_unlock(sdata);
     558                 :          0 : }
     559                 :            : 
     560                 :          0 : void ieee80211_request_smps(struct ieee80211_vif *vif,
     561                 :            :                             enum ieee80211_smps_mode smps_mode)
     562                 :            : {
     563         [ #  # ]:          0 :         struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
     564                 :            : 
     565   [ #  #  #  # ]:          0 :         if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION &&
     566                 :            :                          vif->type != NL80211_IFTYPE_AP))
     567                 :            :                 return;
     568                 :            : 
     569         [ #  # ]:          0 :         if (vif->type == NL80211_IFTYPE_STATION) {
     570         [ #  # ]:          0 :                 if (sdata->u.mgd.driver_smps_mode == smps_mode)
     571                 :            :                         return;
     572                 :          0 :                 sdata->u.mgd.driver_smps_mode = smps_mode;
     573                 :          0 :                 ieee80211_queue_work(&sdata->local->hw,
     574                 :            :                                      &sdata->u.mgd.request_smps_work);
     575                 :            :         } else {
     576                 :            :                 /* AUTOMATIC is meaningless in AP mode */
     577   [ #  #  #  # ]:          0 :                 if (WARN_ON_ONCE(smps_mode == IEEE80211_SMPS_AUTOMATIC))
     578                 :            :                         return;
     579         [ #  # ]:          0 :                 if (sdata->u.ap.driver_smps_mode == smps_mode)
     580                 :            :                         return;
     581                 :          0 :                 sdata->u.ap.driver_smps_mode = smps_mode;
     582                 :          0 :                 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 */
     587                 :            : EXPORT_SYMBOL_GPL(ieee80211_request_smps);

Generated by: LCOV version 1.14