LCOV - code coverage report
Current view: top level - net/mac80211 - status.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 438 0.0 %
Date: 2022-04-01 13:59:58 Functions: 0 17 0.0 %
Branches: 0 329 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * Copyright 2002-2005, Instant802 Networks, Inc.
       4                 :            :  * Copyright 2005-2006, Devicescape Software, Inc.
       5                 :            :  * Copyright 2006-2007  Jiri Benc <jbenc@suse.cz>
       6                 :            :  * Copyright 2008-2010  Johannes Berg <johannes@sipsolutions.net>
       7                 :            :  * Copyright 2013-2014  Intel Mobile Communications GmbH
       8                 :            :  */
       9                 :            : 
      10                 :            : #include <linux/export.h>
      11                 :            : #include <linux/etherdevice.h>
      12                 :            : #include <net/mac80211.h>
      13                 :            : #include <asm/unaligned.h>
      14                 :            : #include "ieee80211_i.h"
      15                 :            : #include "rate.h"
      16                 :            : #include "mesh.h"
      17                 :            : #include "led.h"
      18                 :            : #include "wme.h"
      19                 :            : 
      20                 :            : 
      21                 :          0 : void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
      22                 :            :                                  struct sk_buff *skb)
      23                 :            : {
      24         [ #  # ]:          0 :         struct ieee80211_local *local = hw_to_local(hw);
      25         [ #  # ]:          0 :         struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
      26                 :          0 :         int tmp;
      27                 :            : 
      28                 :          0 :         skb->pkt_type = IEEE80211_TX_STATUS_MSG;
      29         [ #  # ]:          0 :         skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
      30                 :            :                        &local->skb_queue : &local->skb_queue_unreliable, skb);
      31                 :          0 :         tmp = skb_queue_len(&local->skb_queue) +
      32                 :          0 :                 skb_queue_len(&local->skb_queue_unreliable);
      33         [ #  # ]:          0 :         while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
      34                 :          0 :                (skb = skb_dequeue(&local->skb_queue_unreliable))) {
      35                 :          0 :                 ieee80211_free_txskb(hw, skb);
      36                 :          0 :                 tmp--;
      37         [ #  # ]:          0 :                 I802_DEBUG_INC(local->tx_status_drop);
      38                 :            :         }
      39                 :          0 :         tasklet_schedule(&local->tasklet);
      40                 :          0 : }
      41                 :            : EXPORT_SYMBOL(ieee80211_tx_status_irqsafe);
      42                 :            : 
      43                 :          0 : static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
      44                 :            :                                             struct sta_info *sta,
      45                 :            :                                             struct sk_buff *skb)
      46                 :            : {
      47         [ #  # ]:          0 :         struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
      48                 :          0 :         struct ieee80211_hdr *hdr = (void *)skb->data;
      49                 :          0 :         int ac;
      50                 :            : 
      51         [ #  # ]:          0 :         if (info->flags & (IEEE80211_TX_CTL_NO_PS_BUFFER |
      52                 :            :                            IEEE80211_TX_CTL_AMPDU)) {
      53                 :          0 :                 ieee80211_free_txskb(&local->hw, skb);
      54                 :          0 :                 return;
      55                 :            :         }
      56                 :            : 
      57                 :            :         /*
      58                 :            :          * This skb 'survived' a round-trip through the driver, and
      59                 :            :          * hopefully the driver didn't mangle it too badly. However,
      60                 :            :          * we can definitely not rely on the control information
      61                 :            :          * being correct. Clear it so we don't get junk there, and
      62                 :            :          * indicate that it needs new processing, but must not be
      63                 :            :          * modified/encrypted again.
      64                 :            :          */
      65                 :          0 :         memset(&info->control, 0, sizeof(info->control));
      66                 :            : 
      67                 :          0 :         info->control.jiffies = jiffies;
      68                 :          0 :         info->control.vif = &sta->sdata->vif;
      69                 :          0 :         info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING |
      70                 :            :                        IEEE80211_TX_INTFL_RETRANSMISSION;
      71                 :          0 :         info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
      72                 :            : 
      73                 :          0 :         sta->status_stats.filtered++;
      74                 :            : 
      75                 :            :         /*
      76                 :            :          * Clear more-data bit on filtered frames, it might be set
      77                 :            :          * but later frames might time out so it might have to be
      78                 :            :          * clear again ... It's all rather unlikely (this frame
      79                 :            :          * should time out first, right?) but let's not confuse
      80                 :            :          * peers unnecessarily.
      81                 :            :          */
      82         [ #  # ]:          0 :         if (hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_MOREDATA))
      83                 :          0 :                 hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA);
      84                 :            : 
      85         [ #  # ]:          0 :         if (ieee80211_is_data_qos(hdr->frame_control)) {
      86         [ #  # ]:          0 :                 u8 *p = ieee80211_get_qos_ctl(hdr);
      87                 :          0 :                 int tid = *p & IEEE80211_QOS_CTL_TID_MASK;
      88                 :            : 
      89                 :            :                 /*
      90                 :            :                  * Clear EOSP if set, this could happen e.g.
      91                 :            :                  * if an absence period (us being a P2P GO)
      92                 :            :                  * shortens the SP.
      93                 :            :                  */
      94         [ #  # ]:          0 :                 if (*p & IEEE80211_QOS_CTL_EOSP)
      95                 :          0 :                         *p &= ~IEEE80211_QOS_CTL_EOSP;
      96                 :          0 :                 ac = ieee80211_ac_from_tid(tid);
      97                 :            :         } else {
      98                 :            :                 ac = IEEE80211_AC_BE;
      99                 :            :         }
     100                 :            : 
     101                 :            :         /*
     102                 :            :          * Clear the TX filter mask for this STA when sending the next
     103                 :            :          * packet. If the STA went to power save mode, this will happen
     104                 :            :          * when it wakes up for the next time.
     105                 :            :          */
     106                 :          0 :         set_sta_flag(sta, WLAN_STA_CLEAR_PS_FILT);
     107                 :          0 :         ieee80211_clear_fast_xmit(sta);
     108                 :            : 
     109                 :            :         /*
     110                 :            :          * This code races in the following way:
     111                 :            :          *
     112                 :            :          *  (1) STA sends frame indicating it will go to sleep and does so
     113                 :            :          *  (2) hardware/firmware adds STA to filter list, passes frame up
     114                 :            :          *  (3) hardware/firmware processes TX fifo and suppresses a frame
     115                 :            :          *  (4) we get TX status before having processed the frame and
     116                 :            :          *      knowing that the STA has gone to sleep.
     117                 :            :          *
     118                 :            :          * This is actually quite unlikely even when both those events are
     119                 :            :          * processed from interrupts coming in quickly after one another or
     120                 :            :          * even at the same time because we queue both TX status events and
     121                 :            :          * RX frames to be processed by a tasklet and process them in the
     122                 :            :          * same order that they were received or TX status last. Hence, there
     123                 :            :          * is no race as long as the frame RX is processed before the next TX
     124                 :            :          * status, which drivers can ensure, see below.
     125                 :            :          *
     126                 :            :          * Note that this can only happen if the hardware or firmware can
     127                 :            :          * actually add STAs to the filter list, if this is done by the
     128                 :            :          * driver in response to set_tim() (which will only reduce the race
     129                 :            :          * this whole filtering tries to solve, not completely solve it)
     130                 :            :          * this situation cannot happen.
     131                 :            :          *
     132                 :            :          * To completely solve this race drivers need to make sure that they
     133                 :            :          *  (a) don't mix the irq-safe/not irq-safe TX status/RX processing
     134                 :            :          *      functions and
     135                 :            :          *  (b) always process RX events before TX status events if ordering
     136                 :            :          *      can be unknown, for example with different interrupt status
     137                 :            :          *      bits.
     138                 :            :          *  (c) if PS mode transitions are manual (i.e. the flag
     139                 :            :          *      %IEEE80211_HW_AP_LINK_PS is set), always process PS state
     140                 :            :          *      changes before calling TX status events if ordering can be
     141                 :            :          *      unknown.
     142                 :            :          */
     143   [ #  #  #  # ]:          0 :         if (test_sta_flag(sta, WLAN_STA_PS_STA) &&
     144         [ #  # ]:          0 :             skb_queue_len(&sta->tx_filtered[ac]) < STA_MAX_TX_BUFFER) {
     145                 :          0 :                 skb_queue_tail(&sta->tx_filtered[ac], skb);
     146                 :          0 :                 sta_info_recalc_tim(sta);
     147                 :            : 
     148         [ #  # ]:          0 :                 if (!timer_pending(&local->sta_cleanup))
     149                 :          0 :                         mod_timer(&local->sta_cleanup,
     150                 :            :                                   round_jiffies(jiffies +
     151                 :            :                                                 STA_INFO_CLEANUP_INTERVAL));
     152                 :          0 :                 return;
     153                 :            :         }
     154                 :            : 
     155         [ #  # ]:          0 :         if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
     156         [ #  # ]:          0 :             !(info->flags & IEEE80211_TX_INTFL_RETRIED)) {
     157                 :            :                 /* Software retry the packet once */
     158                 :          0 :                 info->flags |= IEEE80211_TX_INTFL_RETRIED;
     159                 :          0 :                 ieee80211_add_pending_skb(local, skb);
     160                 :          0 :                 return;
     161                 :            :         }
     162                 :            : 
     163                 :          0 :         ps_dbg_ratelimited(sta->sdata,
     164                 :            :                            "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n",
     165                 :            :                            skb_queue_len(&sta->tx_filtered[ac]),
     166                 :            :                            !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies);
     167                 :          0 :         ieee80211_free_txskb(&local->hw, skb);
     168                 :            : }
     169                 :            : 
     170                 :          0 : static void ieee80211_check_pending_bar(struct sta_info *sta, u8 *addr, u8 tid)
     171                 :            : {
     172                 :          0 :         struct tid_ampdu_tx *tid_tx;
     173                 :            : 
     174         [ #  # ]:          0 :         tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
     175   [ #  #  #  # ]:          0 :         if (!tid_tx || !tid_tx->bar_pending)
     176                 :            :                 return;
     177                 :            : 
     178                 :          0 :         tid_tx->bar_pending = false;
     179                 :          0 :         ieee80211_send_bar(&sta->sdata->vif, addr, tid, tid_tx->failed_bar_ssn);
     180                 :            : }
     181                 :            : 
     182                 :          0 : static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
     183                 :            : {
     184                 :          0 :         struct ieee80211_mgmt *mgmt = (void *) skb->data;
     185                 :          0 :         struct ieee80211_local *local = sta->local;
     186                 :          0 :         struct ieee80211_sub_if_data *sdata = sta->sdata;
     187                 :          0 :         struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
     188                 :            : 
     189         [ #  # ]:          0 :         if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
     190                 :          0 :                 sta->status_stats.last_ack = jiffies;
     191         [ #  # ]:          0 :                 if (txinfo->status.is_valid_ack_signal) {
     192                 :          0 :                         sta->status_stats.last_ack_signal =
     193                 :          0 :                                          (s8)txinfo->status.ack_signal;
     194                 :          0 :                         sta->status_stats.ack_signal_filled = true;
     195                 :          0 :                         ewma_avg_signal_add(&sta->status_stats.avg_ack_signal,
     196         [ #  # ]:          0 :                                             -txinfo->status.ack_signal);
     197                 :            :                 }
     198                 :            :         }
     199                 :            : 
     200         [ #  # ]:          0 :         if (ieee80211_is_data_qos(mgmt->frame_control)) {
     201                 :          0 :                 struct ieee80211_hdr *hdr = (void *) skb->data;
     202         [ #  # ]:          0 :                 u8 *qc = ieee80211_get_qos_ctl(hdr);
     203                 :          0 :                 u16 tid = qc[0] & 0xf;
     204                 :            : 
     205                 :          0 :                 ieee80211_check_pending_bar(sta, hdr->addr1, tid);
     206                 :            :         }
     207                 :            : 
     208   [ #  #  #  # ]:          0 :         if (ieee80211_is_action(mgmt->frame_control) &&
     209                 :            :             !ieee80211_has_protected(mgmt->frame_control) &&
     210         [ #  # ]:          0 :             mgmt->u.action.category == WLAN_CATEGORY_HT &&
     211         [ #  # ]:          0 :             mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS &&
     212                 :            :             ieee80211_sdata_running(sdata)) {
     213                 :          0 :                 enum ieee80211_smps_mode smps_mode;
     214                 :            : 
     215      [ #  #  # ]:          0 :                 switch (mgmt->u.action.u.ht_smps.smps_control) {
     216                 :            :                 case WLAN_HT_SMPS_CONTROL_DYNAMIC:
     217                 :            :                         smps_mode = IEEE80211_SMPS_DYNAMIC;
     218                 :            :                         break;
     219                 :          0 :                 case WLAN_HT_SMPS_CONTROL_STATIC:
     220                 :          0 :                         smps_mode = IEEE80211_SMPS_STATIC;
     221                 :          0 :                         break;
     222                 :          0 :                 case WLAN_HT_SMPS_CONTROL_DISABLED:
     223                 :            :                 default: /* shouldn't happen since we don't send that */
     224                 :          0 :                         smps_mode = IEEE80211_SMPS_OFF;
     225                 :          0 :                         break;
     226                 :            :                 }
     227                 :            : 
     228         [ #  # ]:          0 :                 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
     229                 :            :                         /*
     230                 :            :                          * This update looks racy, but isn't -- if we come
     231                 :            :                          * here we've definitely got a station that we're
     232                 :            :                          * talking to, and on a managed interface that can
     233                 :            :                          * only be the AP. And the only other place updating
     234                 :            :                          * this variable in managed mode is before association.
     235                 :            :                          */
     236                 :          0 :                         sdata->smps_mode = smps_mode;
     237                 :          0 :                         ieee80211_queue_work(&local->hw, &sdata->recalc_smps);
     238         [ #  # ]:          0 :                 } else if (sdata->vif.type == NL80211_IFTYPE_AP ||
     239                 :            :                            sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
     240                 :          0 :                         sta->known_smps_mode = smps_mode;
     241                 :            :                 }
     242                 :            :         }
     243                 :          0 : }
     244                 :            : 
     245                 :          0 : static void ieee80211_set_bar_pending(struct sta_info *sta, u8 tid, u16 ssn)
     246                 :            : {
     247                 :          0 :         struct tid_ampdu_tx *tid_tx;
     248                 :            : 
     249                 :          0 :         tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
     250         [ #  # ]:          0 :         if (!tid_tx)
     251                 :            :                 return;
     252                 :            : 
     253                 :          0 :         tid_tx->failed_bar_ssn = ssn;
     254                 :          0 :         tid_tx->bar_pending = true;
     255                 :            : }
     256                 :            : 
     257                 :          0 : static int ieee80211_tx_radiotap_len(struct ieee80211_tx_info *info,
     258                 :            :                                      struct ieee80211_tx_status *status)
     259                 :            : {
     260                 :          0 :         int len = sizeof(struct ieee80211_radiotap_header);
     261                 :            : 
     262                 :            :         /* IEEE80211_RADIOTAP_RATE rate */
     263   [ #  #  #  #  :          0 :         if (status && status->rate && !(status->rate->flags &
                   #  # ]
     264                 :            :                                         (RATE_INFO_FLAGS_MCS |
     265                 :            :                                          RATE_INFO_FLAGS_DMG |
     266                 :            :                                          RATE_INFO_FLAGS_EDMG |
     267                 :            :                                          RATE_INFO_FLAGS_VHT_MCS |
     268                 :            :                                          RATE_INFO_FLAGS_HE_MCS)))
     269                 :            :                 len += 2;
     270         [ #  # ]:          0 :         else if (info->status.rates[0].idx >= 0 &&
     271         [ #  # ]:          0 :                  !(info->status.rates[0].flags &
     272                 :            :                    (IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS)))
     273                 :          0 :                 len += 2;
     274                 :            : 
     275                 :            :         /* IEEE80211_RADIOTAP_TX_FLAGS */
     276                 :          0 :         len += 2;
     277                 :            : 
     278                 :            :         /* IEEE80211_RADIOTAP_DATA_RETRIES */
     279                 :          0 :         len += 1;
     280                 :            : 
     281                 :            :         /* IEEE80211_RADIOTAP_MCS
     282                 :            :          * IEEE80211_RADIOTAP_VHT */
     283   [ #  #  #  # ]:          0 :         if (status && status->rate) {
     284         [ #  # ]:          0 :                 if (status->rate->flags & RATE_INFO_FLAGS_MCS)
     285                 :          0 :                         len += 3;
     286         [ #  # ]:          0 :                 else if (status->rate->flags & RATE_INFO_FLAGS_VHT_MCS)
     287                 :          0 :                         len = ALIGN(len, 2) + 12;
     288         [ #  # ]:          0 :                 else if (status->rate->flags & RATE_INFO_FLAGS_HE_MCS)
     289                 :          0 :                         len = ALIGN(len, 2) + 12;
     290         [ #  # ]:          0 :         } else if (info->status.rates[0].idx >= 0) {
     291         [ #  # ]:          0 :                 if (info->status.rates[0].flags & IEEE80211_TX_RC_MCS)
     292                 :          0 :                         len += 3;
     293         [ #  # ]:          0 :                 else if (info->status.rates[0].flags & IEEE80211_TX_RC_VHT_MCS)
     294                 :          0 :                         len = ALIGN(len, 2) + 12;
     295                 :            :         }
     296                 :            : 
     297                 :          0 :         return len;
     298                 :            : }
     299                 :            : 
     300                 :            : static void
     301                 :            : ieee80211_add_tx_radiotap_header(struct ieee80211_local *local,
     302                 :            :                                  struct ieee80211_supported_band *sband,
     303                 :            :                                  struct sk_buff *skb, int retry_count,
     304                 :            :                                  int rtap_len, int shift,
     305                 :            :                                  struct ieee80211_tx_status *status)
     306                 :            : {
     307                 :            :         struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
     308                 :            :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
     309                 :            :         struct ieee80211_radiotap_header *rthdr;
     310                 :            :         unsigned char *pos;
     311                 :            :         u16 legacy_rate = 0;
     312                 :            :         u16 txflags;
     313                 :            : 
     314                 :            :         rthdr = skb_push(skb, rtap_len);
     315                 :            : 
     316                 :            :         memset(rthdr, 0, rtap_len);
     317                 :            :         rthdr->it_len = cpu_to_le16(rtap_len);
     318                 :            :         rthdr->it_present =
     319                 :            :                 cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
     320                 :            :                             (1 << IEEE80211_RADIOTAP_DATA_RETRIES));
     321                 :            :         pos = (unsigned char *)(rthdr + 1);
     322                 :            : 
     323                 :            :         /*
     324                 :            :          * XXX: Once radiotap gets the bitmap reset thing the vendor
     325                 :            :          *      extensions proposal contains, we can actually report
     326                 :            :          *      the whole set of tries we did.
     327                 :            :          */
     328                 :            : 
     329                 :            :         /* IEEE80211_RADIOTAP_RATE */
     330                 :            : 
     331                 :            :         if (status && status->rate) {
     332                 :            :                 if (!(status->rate->flags & (RATE_INFO_FLAGS_MCS |
     333                 :            :                                              RATE_INFO_FLAGS_DMG |
     334                 :            :                                              RATE_INFO_FLAGS_EDMG |
     335                 :            :                                              RATE_INFO_FLAGS_VHT_MCS |
     336                 :            :                                              RATE_INFO_FLAGS_HE_MCS)))
     337                 :            :                         legacy_rate = status->rate->legacy;
     338                 :            :         } else if (info->status.rates[0].idx >= 0 &&
     339                 :            :                  !(info->status.rates[0].flags & (IEEE80211_TX_RC_MCS |
     340                 :            :                                                   IEEE80211_TX_RC_VHT_MCS)))
     341                 :            :                 legacy_rate =
     342                 :            :                         sband->bitrates[info->status.rates[0].idx].bitrate;
     343                 :            : 
     344                 :            :         if (legacy_rate) {
     345                 :            :                 rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE);
     346                 :            :                 *pos = DIV_ROUND_UP(legacy_rate, 5 * (1 << shift));
     347                 :            :                 /* padding for tx flags */
     348                 :            :                 pos += 2;
     349                 :            :         }
     350                 :            : 
     351                 :            :         /* IEEE80211_RADIOTAP_TX_FLAGS */
     352                 :            :         txflags = 0;
     353                 :            :         if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
     354                 :            :             !is_multicast_ether_addr(hdr->addr1))
     355                 :            :                 txflags |= IEEE80211_RADIOTAP_F_TX_FAIL;
     356                 :            : 
     357                 :            :         if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
     358                 :            :                 txflags |= IEEE80211_RADIOTAP_F_TX_CTS;
     359                 :            :         if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
     360                 :            :                 txflags |= IEEE80211_RADIOTAP_F_TX_RTS;
     361                 :            : 
     362                 :            :         put_unaligned_le16(txflags, pos);
     363                 :            :         pos += 2;
     364                 :            : 
     365                 :            :         /* IEEE80211_RADIOTAP_DATA_RETRIES */
     366                 :            :         /* for now report the total retry_count */
     367                 :            :         *pos = retry_count;
     368                 :            :         pos++;
     369                 :            : 
     370                 :            :         if (status && status->rate &&
     371                 :            :             (status->rate->flags & RATE_INFO_FLAGS_MCS)) {
     372                 :            :                 rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS);
     373                 :            :                 pos[0] = IEEE80211_RADIOTAP_MCS_HAVE_MCS |
     374                 :            :                          IEEE80211_RADIOTAP_MCS_HAVE_GI |
     375                 :            :                          IEEE80211_RADIOTAP_MCS_HAVE_BW;
     376                 :            :                 if (status->rate->flags & RATE_INFO_FLAGS_SHORT_GI)
     377                 :            :                         pos[1] |= IEEE80211_RADIOTAP_MCS_SGI;
     378                 :            :                 if (status->rate->bw == RATE_INFO_BW_40)
     379                 :            :                         pos[1] |= IEEE80211_RADIOTAP_MCS_BW_40;
     380                 :            :                 pos[2] = status->rate->mcs;
     381                 :            :                 pos += 3;
     382                 :            :         } else if (status && status->rate &&
     383                 :            :                    (status->rate->flags & RATE_INFO_FLAGS_VHT_MCS)) {
     384                 :            :                 u16 known = local->hw.radiotap_vht_details &
     385                 :            :                         (IEEE80211_RADIOTAP_VHT_KNOWN_GI |
     386                 :            :                          IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH);
     387                 :            : 
     388                 :            :                 rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT);
     389                 :            : 
     390                 :            :                 /* required alignment from rthdr */
     391                 :            :                 pos = (u8 *)rthdr + ALIGN(pos - (u8 *)rthdr, 2);
     392                 :            : 
     393                 :            :                 /* u16 known - IEEE80211_RADIOTAP_VHT_KNOWN_* */
     394                 :            :                 put_unaligned_le16(known, pos);
     395                 :            :                 pos += 2;
     396                 :            : 
     397                 :            :                 /* u8 flags - IEEE80211_RADIOTAP_VHT_FLAG_* */
     398                 :            :                 if (status->rate->flags & RATE_INFO_FLAGS_SHORT_GI)
     399                 :            :                         *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI;
     400                 :            :                 pos++;
     401                 :            : 
     402                 :            :                 /* u8 bandwidth */
     403                 :            :                 switch (status->rate->bw) {
     404                 :            :                 case RATE_INFO_BW_160:
     405                 :            :                         *pos = 11;
     406                 :            :                         break;
     407                 :            :                 case RATE_INFO_BW_80:
     408                 :            :                         *pos = 4;
     409                 :            :                         break;
     410                 :            :                 case RATE_INFO_BW_40:
     411                 :            :                         *pos = 1;
     412                 :            :                         break;
     413                 :            :                 default:
     414                 :            :                         *pos = 0;
     415                 :            :                         break;
     416                 :            :                 }
     417                 :            :                 pos++;
     418                 :            : 
     419                 :            :                 /* u8 mcs_nss[4] */
     420                 :            :                 *pos = (status->rate->mcs << 4) | status->rate->nss;
     421                 :            :                 pos += 4;
     422                 :            : 
     423                 :            :                 /* u8 coding */
     424                 :            :                 pos++;
     425                 :            :                 /* u8 group_id */
     426                 :            :                 pos++;
     427                 :            :                 /* u16 partial_aid */
     428                 :            :                 pos += 2;
     429                 :            :         } else if (status && status->rate &&
     430                 :            :                    (status->rate->flags & RATE_INFO_FLAGS_HE_MCS)) {
     431                 :            :                 struct ieee80211_radiotap_he *he;
     432                 :            : 
     433                 :            :                 rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_HE);
     434                 :            : 
     435                 :            :                 /* required alignment from rthdr */
     436                 :            :                 pos = (u8 *)rthdr + ALIGN(pos - (u8 *)rthdr, 2);
     437                 :            :                 he = (struct ieee80211_radiotap_he *)pos;
     438                 :            : 
     439                 :            :                 he->data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_FORMAT_SU |
     440                 :            :                                         IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN |
     441                 :            :                                         IEEE80211_RADIOTAP_HE_DATA1_DATA_DCM_KNOWN |
     442                 :            :                                         IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN);
     443                 :            : 
     444                 :            :                 he->data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN);
     445                 :            : 
     446                 :            : #define HE_PREP(f, val) le16_encode_bits(val, IEEE80211_RADIOTAP_HE_##f)
     447                 :            : 
     448                 :            :                 he->data6 |= HE_PREP(DATA6_NSTS, status->rate->nss);
     449                 :            : 
     450                 :            : #define CHECK_GI(s) \
     451                 :            :         BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_GI_##s != \
     452                 :            :         (int)NL80211_RATE_INFO_HE_GI_##s)
     453                 :            : 
     454                 :            :                 CHECK_GI(0_8);
     455                 :            :                 CHECK_GI(1_6);
     456                 :            :                 CHECK_GI(3_2);
     457                 :            : 
     458                 :            :                 he->data3 |= HE_PREP(DATA3_DATA_MCS, status->rate->mcs);
     459                 :            :                 he->data3 |= HE_PREP(DATA3_DATA_DCM, status->rate->he_dcm);
     460                 :            : 
     461                 :            :                 he->data5 |= HE_PREP(DATA5_GI, status->rate->he_gi);
     462                 :            : 
     463                 :            :                 switch (status->rate->bw) {
     464                 :            :                 case RATE_INFO_BW_20:
     465                 :            :                         he->data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
     466                 :            :                                              IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_20MHZ);
     467                 :            :                         break;
     468                 :            :                 case RATE_INFO_BW_40:
     469                 :            :                         he->data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
     470                 :            :                                              IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_40MHZ);
     471                 :            :                         break;
     472                 :            :                 case RATE_INFO_BW_80:
     473                 :            :                         he->data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
     474                 :            :                                              IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_80MHZ);
     475                 :            :                         break;
     476                 :            :                 case RATE_INFO_BW_160:
     477                 :            :                         he->data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
     478                 :            :                                              IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_160MHZ);
     479                 :            :                         break;
     480                 :            :                 case RATE_INFO_BW_HE_RU:
     481                 :            : #define CHECK_RU_ALLOC(s) \
     482                 :            :         BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_##s##T != \
     483                 :            :         NL80211_RATE_INFO_HE_RU_ALLOC_##s + 4)
     484                 :            : 
     485                 :            :                         CHECK_RU_ALLOC(26);
     486                 :            :                         CHECK_RU_ALLOC(52);
     487                 :            :                         CHECK_RU_ALLOC(106);
     488                 :            :                         CHECK_RU_ALLOC(242);
     489                 :            :                         CHECK_RU_ALLOC(484);
     490                 :            :                         CHECK_RU_ALLOC(996);
     491                 :            :                         CHECK_RU_ALLOC(2x996);
     492                 :            : 
     493                 :            :                         he->data5 |= HE_PREP(DATA5_DATA_BW_RU_ALLOC,
     494                 :            :                                              status->rate->he_ru_alloc + 4);
     495                 :            :                         break;
     496                 :            :                 default:
     497                 :            :                         WARN_ONCE(1, "Invalid SU BW %d\n", status->rate->bw);
     498                 :            :                 }
     499                 :            : 
     500                 :            :                 pos += sizeof(struct ieee80211_radiotap_he);
     501                 :            :         }
     502                 :            : 
     503                 :            :         if ((status && status->rate) || info->status.rates[0].idx < 0)
     504                 :            :                 return;
     505                 :            : 
     506                 :            :         /* IEEE80211_RADIOTAP_MCS
     507                 :            :          * IEEE80211_RADIOTAP_VHT */
     508                 :            :         if (info->status.rates[0].flags & IEEE80211_TX_RC_MCS) {
     509                 :            :                 rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS);
     510                 :            :                 pos[0] = IEEE80211_RADIOTAP_MCS_HAVE_MCS |
     511                 :            :                          IEEE80211_RADIOTAP_MCS_HAVE_GI |
     512                 :            :                          IEEE80211_RADIOTAP_MCS_HAVE_BW;
     513                 :            :                 if (info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)
     514                 :            :                         pos[1] |= IEEE80211_RADIOTAP_MCS_SGI;
     515                 :            :                 if (info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
     516                 :            :                         pos[1] |= IEEE80211_RADIOTAP_MCS_BW_40;
     517                 :            :                 if (info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)
     518                 :            :                         pos[1] |= IEEE80211_RADIOTAP_MCS_FMT_GF;
     519                 :            :                 pos[2] = info->status.rates[0].idx;
     520                 :            :                 pos += 3;
     521                 :            :         } else if (info->status.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) {
     522                 :            :                 u16 known = local->hw.radiotap_vht_details &
     523                 :            :                         (IEEE80211_RADIOTAP_VHT_KNOWN_GI |
     524                 :            :                          IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH);
     525                 :            : 
     526                 :            :                 rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT);
     527                 :            : 
     528                 :            :                 /* required alignment from rthdr */
     529                 :            :                 pos = (u8 *)rthdr + ALIGN(pos - (u8 *)rthdr, 2);
     530                 :            : 
     531                 :            :                 /* u16 known - IEEE80211_RADIOTAP_VHT_KNOWN_* */
     532                 :            :                 put_unaligned_le16(known, pos);
     533                 :            :                 pos += 2;
     534                 :            : 
     535                 :            :                 /* u8 flags - IEEE80211_RADIOTAP_VHT_FLAG_* */
     536                 :            :                 if (info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)
     537                 :            :                         *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI;
     538                 :            :                 pos++;
     539                 :            : 
     540                 :            :                 /* u8 bandwidth */
     541                 :            :                 if (info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
     542                 :            :                         *pos = 1;
     543                 :            :                 else if (info->status.rates[0].flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
     544                 :            :                         *pos = 4;
     545                 :            :                 else if (info->status.rates[0].flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
     546                 :            :                         *pos = 11;
     547                 :            :                 else /* IEEE80211_TX_RC_{20_MHZ_WIDTH,FIXME:DUP_DATA} */
     548                 :            :                         *pos = 0;
     549                 :            :                 pos++;
     550                 :            : 
     551                 :            :                 /* u8 mcs_nss[4] */
     552                 :            :                 *pos = (ieee80211_rate_get_vht_mcs(&info->status.rates[0]) << 4) |
     553                 :            :                         ieee80211_rate_get_vht_nss(&info->status.rates[0]);
     554                 :            :                 pos += 4;
     555                 :            : 
     556                 :            :                 /* u8 coding */
     557                 :            :                 pos++;
     558                 :            :                 /* u8 group_id */
     559                 :            :                 pos++;
     560                 :            :                 /* u16 partial_aid */
     561                 :            :                 pos += 2;
     562                 :            :         }
     563                 :            : }
     564                 :            : 
     565                 :            : /*
     566                 :            :  * Handles the tx for TDLS teardown frames.
     567                 :            :  * If the frame wasn't ACKed by the peer - it will be re-sent through the AP
     568                 :            :  */
     569                 :          0 : static void ieee80211_tdls_td_tx_handle(struct ieee80211_local *local,
     570                 :            :                                         struct ieee80211_sub_if_data *sdata,
     571                 :            :                                         struct sk_buff *skb, u32 flags)
     572                 :            : {
     573                 :          0 :         struct sk_buff *teardown_skb;
     574                 :          0 :         struct sk_buff *orig_teardown_skb;
     575                 :          0 :         bool is_teardown = false;
     576                 :            : 
     577                 :            :         /* Get the teardown data we need and free the lock */
     578                 :          0 :         spin_lock(&sdata->u.mgd.teardown_lock);
     579                 :          0 :         teardown_skb = sdata->u.mgd.teardown_skb;
     580                 :          0 :         orig_teardown_skb = sdata->u.mgd.orig_teardown_skb;
     581         [ #  # ]:          0 :         if ((skb == orig_teardown_skb) && teardown_skb) {
     582                 :          0 :                 sdata->u.mgd.teardown_skb = NULL;
     583                 :          0 :                 sdata->u.mgd.orig_teardown_skb = NULL;
     584                 :          0 :                 is_teardown = true;
     585                 :            :         }
     586                 :          0 :         spin_unlock(&sdata->u.mgd.teardown_lock);
     587                 :            : 
     588         [ #  # ]:          0 :         if (is_teardown) {
     589                 :            :                 /* This mechanism relies on being able to get ACKs */
     590         [ #  # ]:          0 :                 WARN_ON(!ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS));
     591                 :            : 
     592                 :            :                 /* Check if peer has ACKed */
     593         [ #  # ]:          0 :                 if (flags & IEEE80211_TX_STAT_ACK) {
     594                 :          0 :                         dev_kfree_skb_any(teardown_skb);
     595                 :            :                 } else {
     596                 :          0 :                         tdls_dbg(sdata,
     597                 :            :                                  "TDLS Resending teardown through AP\n");
     598                 :            : 
     599                 :          0 :                         ieee80211_subif_start_xmit(teardown_skb, skb->dev);
     600                 :            :                 }
     601                 :            :         }
     602                 :          0 : }
     603                 :            : 
     604                 :            : static struct ieee80211_sub_if_data *
     605                 :          0 : ieee80211_sdata_from_skb(struct ieee80211_local *local, struct sk_buff *skb)
     606                 :            : {
     607                 :          0 :         struct ieee80211_sub_if_data *sdata;
     608                 :            : 
     609                 :          0 :         if (skb->dev) {
     610   [ #  #  #  # ]:          0 :                 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
     611   [ #  #  #  # ]:          0 :                         if (!sdata->dev)
     612                 :          0 :                                 continue;
     613                 :            : 
     614   [ #  #  #  # ]:          0 :                         if (skb->dev == sdata->dev)
     615                 :            :                                 return sdata;
     616                 :            :                 }
     617                 :            : 
     618                 :            :                 return NULL;
     619                 :            :         }
     620                 :            : 
     621                 :          0 :         return rcu_dereference(local->p2p_sdata);
     622                 :            : }
     623                 :            : 
     624                 :          0 : static void ieee80211_report_ack_skb(struct ieee80211_local *local,
     625                 :            :                                      struct ieee80211_tx_info *info,
     626                 :            :                                      bool acked, bool dropped)
     627                 :            : {
     628                 :          0 :         struct sk_buff *skb;
     629                 :          0 :         unsigned long flags;
     630                 :            : 
     631                 :          0 :         spin_lock_irqsave(&local->ack_status_lock, flags);
     632                 :          0 :         skb = idr_remove(&local->ack_status_frames, info->ack_frame_id);
     633                 :          0 :         spin_unlock_irqrestore(&local->ack_status_lock, flags);
     634                 :            : 
     635         [ #  # ]:          0 :         if (!skb)
     636                 :            :                 return;
     637                 :            : 
     638         [ #  # ]:          0 :         if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
     639                 :          0 :                 u64 cookie = IEEE80211_SKB_CB(skb)->ack.cookie;
     640                 :          0 :                 struct ieee80211_sub_if_data *sdata;
     641                 :          0 :                 struct ieee80211_hdr *hdr = (void *)skb->data;
     642                 :            : 
     643                 :          0 :                 rcu_read_lock();
     644         [ #  # ]:          0 :                 sdata = ieee80211_sdata_from_skb(local, skb);
     645         [ #  # ]:          0 :                 if (sdata) {
     646   [ #  #  #  # ]:          0 :                         if (ieee80211_is_nullfunc(hdr->frame_control) ||
     647                 :            :                             ieee80211_is_qos_nullfunc(hdr->frame_control))
     648                 :          0 :                                 cfg80211_probe_status(sdata->dev, hdr->addr1,
     649                 :            :                                                       cookie, acked,
     650                 :            :                                                       info->status.ack_signal,
     651                 :          0 :                                                       info->status.is_valid_ack_signal,
     652                 :            :                                                       GFP_ATOMIC);
     653                 :            :                         else
     654                 :          0 :                                 cfg80211_mgmt_tx_status(&sdata->wdev, cookie,
     655                 :          0 :                                                         skb->data, skb->len,
     656                 :            :                                                         acked, GFP_ATOMIC);
     657                 :            :                 }
     658                 :          0 :                 rcu_read_unlock();
     659                 :            : 
     660                 :          0 :                 dev_kfree_skb_any(skb);
     661         [ #  # ]:          0 :         } else if (dropped) {
     662                 :          0 :                 dev_kfree_skb_any(skb);
     663                 :            :         } else {
     664                 :            :                 /* consumes skb */
     665                 :          0 :                 skb_complete_wifi_ack(skb, acked);
     666                 :            :         }
     667                 :            : }
     668                 :            : 
     669                 :          0 : static void ieee80211_report_used_skb(struct ieee80211_local *local,
     670                 :            :                                       struct sk_buff *skb, bool dropped)
     671                 :            : {
     672         [ #  # ]:          0 :         struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
     673         [ #  # ]:          0 :         u16 tx_time_est = ieee80211_info_get_tx_time_est(info);
     674                 :          0 :         struct ieee80211_hdr *hdr = (void *)skb->data;
     675                 :          0 :         bool acked = info->flags & IEEE80211_TX_STAT_ACK;
     676                 :            : 
     677         [ #  # ]:          0 :         if (dropped)
     678                 :          0 :                 acked = false;
     679                 :            : 
     680         [ #  # ]:          0 :         if (tx_time_est) {
     681                 :          0 :                 struct sta_info *sta;
     682                 :            : 
     683                 :          0 :                 rcu_read_lock();
     684                 :            : 
     685                 :          0 :                 sta = sta_info_get_by_addrs(local, hdr->addr1, hdr->addr2);
     686                 :          0 :                 ieee80211_sta_update_pending_airtime(local, sta,
     687                 :          0 :                                                      skb_get_queue_mapping(skb),
     688                 :            :                                                      tx_time_est,
     689                 :            :                                                      true);
     690                 :          0 :                 rcu_read_unlock();
     691                 :            :         }
     692                 :            : 
     693         [ #  # ]:          0 :         if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) {
     694                 :          0 :                 struct ieee80211_sub_if_data *sdata;
     695                 :            : 
     696                 :          0 :                 rcu_read_lock();
     697                 :            : 
     698         [ #  # ]:          0 :                 sdata = ieee80211_sdata_from_skb(local, skb);
     699                 :            : 
     700         [ #  # ]:          0 :                 if (!sdata) {
     701                 :          0 :                         skb->dev = NULL;
     702                 :            :                 } else {
     703                 :          0 :                         unsigned int hdr_size =
     704                 :          0 :                                 ieee80211_hdrlen(hdr->frame_control);
     705                 :            : 
     706                 :            :                         /* Check to see if packet is a TDLS teardown packet */
     707         [ #  # ]:          0 :                         if (ieee80211_is_data(hdr->frame_control) &&
     708         [ #  # ]:          0 :                             (ieee80211_get_tdls_action(skb, hdr_size) ==
     709                 :            :                              WLAN_TDLS_TEARDOWN))
     710                 :          0 :                                 ieee80211_tdls_td_tx_handle(local, sdata, skb,
     711                 :            :                                                             info->flags);
     712                 :            :                         else
     713                 :          0 :                                 ieee80211_mgd_conn_tx_status(sdata,
     714                 :            :                                                              hdr->frame_control,
     715                 :            :                                                              acked);
     716                 :            :                 }
     717                 :            : 
     718                 :          0 :                 rcu_read_unlock();
     719         [ #  # ]:          0 :         } else if (info->ack_frame_id) {
     720                 :          0 :                 ieee80211_report_ack_skb(local, info, acked, dropped);
     721                 :            :         }
     722                 :            : 
     723   [ #  #  #  # ]:          0 :         if (!dropped && skb->destructor) {
     724                 :          0 :                 skb->wifi_acked_valid = 1;
     725                 :          0 :                 skb->wifi_acked = acked;
     726                 :            :         }
     727                 :            : 
     728                 :          0 :         ieee80211_led_tx(local);
     729                 :            : 
     730         [ #  # ]:          0 :         if (skb_has_frag_list(skb)) {
     731                 :          0 :                 kfree_skb_list(skb_shinfo(skb)->frag_list);
     732                 :          0 :                 skb_shinfo(skb)->frag_list = NULL;
     733                 :            :         }
     734                 :          0 : }
     735                 :            : 
     736                 :            : /*
     737                 :            :  * Use a static threshold for now, best value to be determined
     738                 :            :  * by testing ...
     739                 :            :  * Should it depend on:
     740                 :            :  *  - on # of retransmissions
     741                 :            :  *  - current throughput (higher value for higher tpt)?
     742                 :            :  */
     743                 :            : #define STA_LOST_PKT_THRESHOLD  50
     744                 :            : #define STA_LOST_TDLS_PKT_THRESHOLD     10
     745                 :            : #define STA_LOST_TDLS_PKT_TIME          (10*HZ) /* 10secs since last ACK */
     746                 :            : 
     747                 :          0 : static void ieee80211_lost_packet(struct sta_info *sta,
     748                 :            :                                   struct ieee80211_tx_info *info)
     749                 :            : {
     750                 :            :         /* If driver relies on its own algorithm for station kickout, skip
     751                 :            :          * mac80211 packet loss mechanism.
     752                 :            :          */
     753         [ #  # ]:          0 :         if (ieee80211_hw_check(&sta->local->hw, REPORTS_LOW_ACK))
     754                 :            :                 return;
     755                 :            : 
     756                 :            :         /* This packet was aggregated but doesn't carry status info */
     757         [ #  # ]:          0 :         if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
     758                 :            :             !(info->flags & IEEE80211_TX_STAT_AMPDU))
     759                 :            :                 return;
     760                 :            : 
     761                 :          0 :         sta->status_stats.lost_packets++;
     762   [ #  #  #  # ]:          0 :         if (!sta->sta.tdls &&
     763                 :            :             sta->status_stats.lost_packets < STA_LOST_PKT_THRESHOLD)
     764                 :            :                 return;
     765                 :            : 
     766                 :            :         /*
     767                 :            :          * If we're in TDLS mode, make sure that all STA_LOST_TDLS_PKT_THRESHOLD
     768                 :            :          * of the last packets were lost, and that no ACK was received in the
     769                 :            :          * last STA_LOST_TDLS_PKT_TIME ms, before triggering the CQM packet-loss
     770                 :            :          * mechanism.
     771                 :            :          */
     772   [ #  #  #  # ]:          0 :         if (sta->sta.tdls &&
     773                 :            :             (sta->status_stats.lost_packets < STA_LOST_TDLS_PKT_THRESHOLD ||
     774         [ #  # ]:          0 :              time_before(jiffies,
     775                 :            :                          sta->status_stats.last_tdls_pkt_time +
     776                 :            :                          STA_LOST_TDLS_PKT_TIME)))
     777                 :            :                 return;
     778                 :            : 
     779                 :          0 :         cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
     780                 :            :                                     sta->status_stats.lost_packets, GFP_ATOMIC);
     781                 :          0 :         sta->status_stats.lost_packets = 0;
     782                 :            : }
     783                 :            : 
     784                 :          0 : static int ieee80211_tx_get_rates(struct ieee80211_hw *hw,
     785                 :            :                                   struct ieee80211_tx_info *info,
     786                 :            :                                   int *retry_count)
     787                 :            : {
     788                 :            :         int rates_idx = -1;
     789                 :            :         int count = -1;
     790                 :            :         int i;
     791                 :            : 
     792   [ #  #  #  # ]:          0 :         for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
     793   [ #  #  #  # ]:          0 :                 if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
     794                 :            :                     !(info->flags & IEEE80211_TX_STAT_AMPDU)) {
     795                 :            :                         /* just the first aggr frame carry status info */
     796                 :          0 :                         info->status.rates[i].idx = -1;
     797                 :          0 :                         info->status.rates[i].count = 0;
     798                 :          0 :                         break;
     799   [ #  #  #  # ]:          0 :                 } else if (info->status.rates[i].idx < 0) {
     800                 :            :                         break;
     801   [ #  #  #  # ]:          0 :                 } else if (i >= hw->max_report_rates) {
     802                 :            :                         /* the HW cannot have attempted that rate */
     803                 :          0 :                         info->status.rates[i].idx = -1;
     804                 :          0 :                         info->status.rates[i].count = 0;
     805                 :          0 :                         break;
     806                 :            :                 }
     807                 :            : 
     808                 :          0 :                 count += info->status.rates[i].count;
     809                 :            :         }
     810                 :          0 :         rates_idx = i - 1;
     811                 :            : 
     812                 :          0 :         if (count < 0)
     813                 :            :                 count = 0;
     814                 :            : 
     815                 :          0 :         *retry_count = count;
     816                 :          0 :         return rates_idx;
     817                 :            : }
     818                 :            : 
     819                 :          0 : void ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb,
     820                 :            :                           struct ieee80211_supported_band *sband,
     821                 :            :                           int retry_count, int shift, bool send_to_cooked,
     822                 :            :                           struct ieee80211_tx_status *status)
     823                 :            : {
     824                 :          0 :         struct sk_buff *skb2;
     825         [ #  # ]:          0 :         struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
     826                 :          0 :         struct ieee80211_sub_if_data *sdata;
     827                 :          0 :         struct net_device *prev_dev = NULL;
     828                 :          0 :         int rtap_len;
     829                 :            : 
     830                 :            :         /* send frame to monitor interfaces now */
     831                 :          0 :         rtap_len = ieee80211_tx_radiotap_len(info, status);
     832   [ #  #  #  # ]:          0 :         if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
     833                 :          0 :                 pr_err("ieee80211_tx_status: headroom too small\n");
     834                 :          0 :                 dev_kfree_skb(skb);
     835                 :          0 :                 return;
     836                 :            :         }
     837                 :          0 :         ieee80211_add_tx_radiotap_header(local, sband, skb, retry_count,
     838                 :            :                                          rtap_len, shift, status);
     839                 :            : 
     840                 :            :         /* XXX: is this sufficient for BPF? */
     841                 :          0 :         skb_reset_mac_header(skb);
     842                 :          0 :         skb->ip_summed = CHECKSUM_UNNECESSARY;
     843                 :          0 :         skb->pkt_type = PACKET_OTHERHOST;
     844                 :          0 :         skb->protocol = htons(ETH_P_802_2);
     845                 :          0 :         memset(skb->cb, 0, sizeof(skb->cb));
     846                 :            : 
     847                 :          0 :         rcu_read_lock();
     848         [ #  # ]:          0 :         list_for_each_entry_rcu(sdata, &local->interfaces, list) {
     849         [ #  # ]:          0 :                 if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
     850         [ #  # ]:          0 :                         if (!ieee80211_sdata_running(sdata))
     851                 :          0 :                                 continue;
     852                 :            : 
     853   [ #  #  #  # ]:          0 :                         if ((sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) &&
     854                 :            :                             !send_to_cooked)
     855                 :          0 :                                 continue;
     856                 :            : 
     857         [ #  # ]:          0 :                         if (prev_dev) {
     858                 :          0 :                                 skb2 = skb_clone(skb, GFP_ATOMIC);
     859         [ #  # ]:          0 :                                 if (skb2) {
     860                 :          0 :                                         skb2->dev = prev_dev;
     861                 :          0 :                                         netif_rx(skb2);
     862                 :            :                                 }
     863                 :            :                         }
     864                 :            : 
     865                 :          0 :                         prev_dev = sdata->dev;
     866                 :            :                 }
     867                 :            :         }
     868         [ #  # ]:          0 :         if (prev_dev) {
     869                 :          0 :                 skb->dev = prev_dev;
     870                 :          0 :                 netif_rx(skb);
     871                 :          0 :                 skb = NULL;
     872                 :            :         }
     873                 :          0 :         rcu_read_unlock();
     874                 :          0 :         dev_kfree_skb(skb);
     875                 :            : }
     876                 :            : 
     877                 :          0 : static void __ieee80211_tx_status(struct ieee80211_hw *hw,
     878                 :            :                                   struct ieee80211_tx_status *status)
     879                 :            : {
     880                 :          0 :         struct sk_buff *skb = status->skb;
     881                 :          0 :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
     882                 :          0 :         struct ieee80211_local *local = hw_to_local(hw);
     883                 :          0 :         struct ieee80211_tx_info *info = status->info;
     884                 :          0 :         struct sta_info *sta;
     885                 :          0 :         __le16 fc;
     886                 :          0 :         struct ieee80211_supported_band *sband;
     887                 :          0 :         int retry_count;
     888                 :          0 :         int rates_idx;
     889                 :          0 :         bool send_to_cooked;
     890                 :          0 :         bool acked;
     891                 :          0 :         struct ieee80211_bar *bar;
     892                 :          0 :         int shift = 0;
     893                 :          0 :         int tid = IEEE80211_NUM_TIDS;
     894                 :          0 :         u16 tx_time_est;
     895                 :            : 
     896                 :          0 :         rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
     897                 :            : 
     898                 :          0 :         sband = local->hw.wiphy->bands[info->band];
     899                 :          0 :         fc = hdr->frame_control;
     900                 :            : 
     901         [ #  # ]:          0 :         if (status->sta) {
     902                 :          0 :                 sta = container_of(status->sta, struct sta_info, sta);
     903                 :          0 :                 shift = ieee80211_vif_get_shift(&sta->sdata->vif);
     904                 :            : 
     905         [ #  # ]:          0 :                 if (info->flags & IEEE80211_TX_STATUS_EOSP)
     906                 :          0 :                         clear_sta_flag(sta, WLAN_STA_SP);
     907                 :            : 
     908                 :          0 :                 acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
     909                 :            : 
     910                 :            :                 /* mesh Peer Service Period support */
     911         [ #  # ]:          0 :                 if (ieee80211_vif_is_mesh(&sta->sdata->vif) &&
     912                 :            :                     ieee80211_is_data_qos(fc))
     913                 :            :                         ieee80211_mpsp_trigger_process(
     914                 :            :                                 ieee80211_get_qos_ctl(hdr), sta, true, acked);
     915                 :            : 
     916   [ #  #  #  # ]:          0 :                 if (!acked && test_sta_flag(sta, WLAN_STA_PS_STA)) {
     917                 :            :                         /*
     918                 :            :                          * The STA is in power save mode, so assume
     919                 :            :                          * that this TX packet failed because of that.
     920                 :            :                          */
     921                 :          0 :                         ieee80211_handle_filtered_frame(local, sta, skb);
     922                 :          0 :                         return;
     923                 :            :                 }
     924                 :            : 
     925   [ #  #  #  # ]:          0 :                 if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL) &&
     926   [ #  #  #  # ]:          0 :                     (ieee80211_is_data(hdr->frame_control)) &&
     927                 :            :                     (rates_idx != -1))
     928                 :          0 :                         sta->tx_stats.last_rate =
     929                 :            :                                 info->status.rates[rates_idx];
     930                 :            : 
     931   [ #  #  #  # ]:          0 :                 if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
     932                 :          0 :                     (ieee80211_is_data_qos(fc))) {
     933                 :          0 :                         u16 ssn;
     934                 :          0 :                         u8 *qc;
     935                 :            : 
     936         [ #  # ]:          0 :                         qc = ieee80211_get_qos_ctl(hdr);
     937                 :          0 :                         tid = qc[0] & 0xf;
     938                 :          0 :                         ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10)
     939                 :          0 :                                                 & IEEE80211_SCTL_SEQ);
     940                 :          0 :                         ieee80211_send_bar(&sta->sdata->vif, hdr->addr1,
     941                 :            :                                            tid, ssn);
     942         [ #  # ]:          0 :                 } else if (ieee80211_is_data_qos(fc)) {
     943         [ #  # ]:          0 :                         u8 *qc = ieee80211_get_qos_ctl(hdr);
     944                 :            : 
     945                 :          0 :                         tid = qc[0] & 0xf;
     946                 :            :                 }
     947                 :            : 
     948   [ #  #  #  # ]:          0 :                 if (!acked && ieee80211_is_back_req(fc)) {
     949                 :          0 :                         u16 control;
     950                 :            : 
     951                 :            :                         /*
     952                 :            :                          * BAR failed, store the last SSN and retry sending
     953                 :            :                          * the BAR when the next unicast transmission on the
     954                 :            :                          * same TID succeeds.
     955                 :            :                          */
     956                 :          0 :                         bar = (struct ieee80211_bar *) skb->data;
     957                 :          0 :                         control = le16_to_cpu(bar->control);
     958         [ #  # ]:          0 :                         if (!(control & IEEE80211_BAR_CTRL_MULTI_TID)) {
     959                 :          0 :                                 u16 ssn = le16_to_cpu(bar->start_seq_num);
     960                 :            : 
     961                 :          0 :                                 tid = (control &
     962                 :          0 :                                        IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
     963                 :            :                                       IEEE80211_BAR_CTRL_TID_INFO_SHIFT;
     964                 :            : 
     965         [ #  # ]:          0 :                                 ieee80211_set_bar_pending(sta, tid, ssn);
     966                 :            :                         }
     967                 :            :                 }
     968                 :            : 
     969         [ #  # ]:          0 :                 if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
     970                 :          0 :                         ieee80211_handle_filtered_frame(local, sta, skb);
     971                 :          0 :                         return;
     972                 :            :                 } else {
     973         [ #  # ]:          0 :                         if (!acked)
     974                 :          0 :                                 sta->status_stats.retry_failed++;
     975                 :          0 :                         sta->status_stats.retry_count += retry_count;
     976                 :            : 
     977         [ #  # ]:          0 :                         if (ieee80211_is_data_present(fc)) {
     978         [ #  # ]:          0 :                                 if (!acked)
     979                 :          0 :                                         sta->status_stats.msdu_failed[tid]++;
     980                 :            : 
     981                 :          0 :                                 sta->status_stats.msdu_retries[tid] +=
     982                 :            :                                         retry_count;
     983                 :            :                         }
     984                 :            :                 }
     985                 :            : 
     986                 :          0 :                 rate_control_tx_status(local, sband, status);
     987         [ #  # ]:          0 :                 if (ieee80211_vif_is_mesh(&sta->sdata->vif))
     988                 :            :                         ieee80211s_update_metric(local, sta, status);
     989                 :            : 
     990   [ #  #  #  # ]:          0 :                 if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked)
     991                 :          0 :                         ieee80211_frame_acked(sta, skb);
     992                 :            : 
     993   [ #  #  #  # ]:          0 :                 if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) &&
     994                 :            :                     ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
     995                 :          0 :                         ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data,
     996                 :          0 :                                                 acked, info->status.tx_time);
     997                 :            : 
     998   [ #  #  #  # ]:          0 :                 if (info->status.tx_time &&
     999         [ #  # ]:          0 :                     wiphy_ext_feature_isset(local->hw.wiphy,
    1000                 :            :                                             NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
    1001                 :          0 :                         ieee80211_sta_register_airtime(&sta->sta, tid,
    1002                 :            :                                                        info->status.tx_time, 0);
    1003                 :            : 
    1004         [ #  # ]:          0 :                 if ((tx_time_est = ieee80211_info_get_tx_time_est(info)) > 0) {
    1005                 :            :                         /* Do this here to avoid the expensive lookup of the sta
    1006                 :            :                          * in ieee80211_report_used_skb().
    1007                 :            :                          */
    1008                 :          0 :                         ieee80211_sta_update_pending_airtime(local, sta,
    1009                 :          0 :                                                              skb_get_queue_mapping(skb),
    1010                 :            :                                                              tx_time_est,
    1011                 :            :                                                              true);
    1012                 :          0 :                         ieee80211_info_set_tx_time_est(info, 0);
    1013                 :            :                 }
    1014                 :            : 
    1015         [ #  # ]:          0 :                 if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
    1016         [ #  # ]:          0 :                         if (info->flags & IEEE80211_TX_STAT_ACK) {
    1017         [ #  # ]:          0 :                                 if (sta->status_stats.lost_packets)
    1018                 :          0 :                                         sta->status_stats.lost_packets = 0;
    1019                 :            : 
    1020                 :            :                                 /* Track when last TDLS packet was ACKed */
    1021         [ #  # ]:          0 :                                 if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
    1022                 :          0 :                                         sta->status_stats.last_tdls_pkt_time =
    1023                 :            :                                                 jiffies;
    1024                 :            :                         } else {
    1025                 :          0 :                                 ieee80211_lost_packet(sta, info);
    1026                 :            :                         }
    1027                 :            :                 }
    1028                 :            :         }
    1029                 :            : 
    1030                 :            :         /* SNMP counters
    1031                 :            :          * Fragments are passed to low-level drivers as separate skbs, so these
    1032                 :            :          * are actually fragments, not frames. Update frame counters only for
    1033                 :            :          * the first fragment of the frame. */
    1034                 :          0 :         if ((info->flags & IEEE80211_TX_STAT_ACK) ||
    1035                 :            :             (info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED)) {
    1036         [ #  # ]:          0 :                 if (ieee80211_is_first_frag(hdr->seq_ctrl)) {
    1037                 :            :                         I802_DEBUG_INC(local->dot11TransmittedFrameCount);
    1038                 :            :                         if (is_multicast_ether_addr(ieee80211_get_DA(hdr)))
    1039                 :            :                                 I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount);
    1040                 :            :                         if (retry_count > 0)
    1041                 :            :                                 I802_DEBUG_INC(local->dot11RetryCount);
    1042                 :            :                         if (retry_count > 1)
    1043                 :          0 :                                 I802_DEBUG_INC(local->dot11MultipleRetryCount);
    1044                 :            :                 }
    1045                 :            : 
    1046                 :            :                 /* This counter shall be incremented for an acknowledged MPDU
    1047                 :            :                  * with an individual address in the address 1 field or an MPDU
    1048                 :            :                  * with a multicast address in the address 1 field of type Data
    1049                 :            :                  * or Management. */
    1050         [ #  # ]:          0 :                 if (!is_multicast_ether_addr(hdr->addr1) ||
    1051                 :            :                     ieee80211_is_data(fc) ||
    1052                 :            :                     ieee80211_is_mgmt(fc))
    1053                 :            :                         I802_DEBUG_INC(local->dot11TransmittedFragmentCount);
    1054                 :            :         } else {
    1055                 :            :                 if (ieee80211_is_first_frag(hdr->seq_ctrl))
    1056                 :          0 :                         I802_DEBUG_INC(local->dot11FailedCount);
    1057                 :            :         }
    1058                 :            : 
    1059   [ #  #  #  #  :          0 :         if ((ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)) &&
                   #  # ]
    1060         [ #  # ]:          0 :             ieee80211_has_pm(fc) &&
    1061                 :          0 :             ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS) &&
    1062         [ #  # ]:          0 :             !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
    1063   [ #  #  #  # ]:          0 :             local->ps_sdata && !(local->scanning)) {
    1064         [ #  # ]:          0 :                 if (info->flags & IEEE80211_TX_STAT_ACK) {
    1065                 :          0 :                         local->ps_sdata->u.mgd.flags |=
    1066                 :            :                                         IEEE80211_STA_NULLFUNC_ACKED;
    1067                 :            :                 } else
    1068                 :          0 :                         mod_timer(&local->dynamic_ps_timer, jiffies +
    1069                 :            :                                         msecs_to_jiffies(10));
    1070                 :            :         }
    1071                 :            : 
    1072                 :          0 :         ieee80211_report_used_skb(local, skb, false);
    1073                 :            : 
    1074                 :            :         /* this was a transmitted frame, but now we want to reuse it */
    1075                 :          0 :         skb_orphan(skb);
    1076                 :            : 
    1077                 :            :         /* Need to make a copy before skb->cb gets cleared */
    1078   [ #  #  #  # ]:          0 :         send_to_cooked = !!(info->flags & IEEE80211_TX_CTL_INJECTED) ||
    1079                 :            :                          !(ieee80211_is_data(fc));
    1080                 :            : 
    1081                 :            :         /*
    1082                 :            :          * This is a bit racy but we can avoid a lot of work
    1083                 :            :          * with this test...
    1084                 :            :          */
    1085   [ #  #  #  #  :          0 :         if (!local->monitors && (!send_to_cooked || !local->cooked_mntrs)) {
                   #  # ]
    1086                 :          0 :                 dev_kfree_skb(skb);
    1087                 :          0 :                 return;
    1088                 :            :         }
    1089                 :            : 
    1090                 :            :         /* send to monitor interfaces */
    1091                 :          0 :         ieee80211_tx_monitor(local, skb, sband, retry_count, shift,
    1092                 :            :                              send_to_cooked, status);
    1093                 :            : }
    1094                 :            : 
    1095                 :          0 : void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
    1096                 :            : {
    1097                 :          0 :         struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
    1098                 :          0 :         struct ieee80211_local *local = hw_to_local(hw);
    1099                 :          0 :         struct ieee80211_tx_status status = {
    1100                 :            :                 .skb = skb,
    1101                 :            :                 .info = IEEE80211_SKB_CB(skb),
    1102                 :            :         };
    1103                 :          0 :         struct sta_info *sta;
    1104                 :            : 
    1105                 :          0 :         rcu_read_lock();
    1106                 :            : 
    1107                 :          0 :         sta = sta_info_get_by_addrs(local, hdr->addr1, hdr->addr2);
    1108         [ #  # ]:          0 :         if (sta)
    1109                 :          0 :                 status.sta = &sta->sta;
    1110                 :            : 
    1111                 :          0 :         __ieee80211_tx_status(hw, &status);
    1112                 :          0 :         rcu_read_unlock();
    1113                 :          0 : }
    1114                 :            : EXPORT_SYMBOL(ieee80211_tx_status);
    1115                 :            : 
    1116                 :          0 : void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
    1117                 :            :                              struct ieee80211_tx_status *status)
    1118                 :            : {
    1119         [ #  # ]:          0 :         struct ieee80211_local *local = hw_to_local(hw);
    1120                 :          0 :         struct ieee80211_tx_info *info = status->info;
    1121                 :          0 :         struct ieee80211_sta *pubsta = status->sta;
    1122                 :          0 :         struct ieee80211_supported_band *sband;
    1123                 :          0 :         int retry_count;
    1124                 :          0 :         bool acked, noack_success;
    1125                 :            : 
    1126         [ #  # ]:          0 :         if (status->skb)
    1127                 :          0 :                 return __ieee80211_tx_status(hw, status);
    1128                 :            : 
    1129         [ #  # ]:          0 :         if (!status->sta)
    1130                 :            :                 return;
    1131                 :            : 
    1132                 :            :         ieee80211_tx_get_rates(hw, info, &retry_count);
    1133                 :            : 
    1134                 :          0 :         sband = hw->wiphy->bands[info->band];
    1135                 :            : 
    1136                 :          0 :         acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
    1137                 :          0 :         noack_success = !!(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED);
    1138                 :            : 
    1139                 :          0 :         if (pubsta) {
    1140                 :          0 :                 struct sta_info *sta;
    1141                 :            : 
    1142                 :          0 :                 sta = container_of(pubsta, struct sta_info, sta);
    1143                 :            : 
    1144         [ #  # ]:          0 :                 if (!acked)
    1145                 :          0 :                         sta->status_stats.retry_failed++;
    1146                 :          0 :                 sta->status_stats.retry_count += retry_count;
    1147                 :            : 
    1148         [ #  # ]:          0 :                 if (acked) {
    1149                 :          0 :                         sta->status_stats.last_ack = jiffies;
    1150                 :            : 
    1151         [ #  # ]:          0 :                         if (sta->status_stats.lost_packets)
    1152                 :          0 :                                 sta->status_stats.lost_packets = 0;
    1153                 :            : 
    1154                 :            :                         /* Track when last TDLS packet was ACKed */
    1155         [ #  # ]:          0 :                         if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
    1156                 :          0 :                                 sta->status_stats.last_tdls_pkt_time = jiffies;
    1157         [ #  # ]:          0 :                 } else if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
    1158                 :            :                         return;
    1159                 :            :                 } else {
    1160                 :          0 :                         ieee80211_lost_packet(sta, info);
    1161                 :            :                 }
    1162                 :            : 
    1163                 :          0 :                 rate_control_tx_status(local, sband, status);
    1164                 :          0 :                 if (ieee80211_vif_is_mesh(&sta->sdata->vif))
    1165                 :            :                         ieee80211s_update_metric(local, sta, status);
    1166                 :            :         }
    1167                 :            : 
    1168                 :          0 :         if (acked || noack_success) {
    1169                 :            :                 I802_DEBUG_INC(local->dot11TransmittedFrameCount);
    1170                 :            :                 if (!pubsta)
    1171                 :            :                         I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount);
    1172                 :            :                 if (retry_count > 0)
    1173                 :            :                         I802_DEBUG_INC(local->dot11RetryCount);
    1174                 :            :                 if (retry_count > 1)
    1175                 :            :                         I802_DEBUG_INC(local->dot11MultipleRetryCount);
    1176                 :            :         } else {
    1177                 :            :                 I802_DEBUG_INC(local->dot11FailedCount);
    1178                 :            :         }
    1179                 :            : }
    1180                 :            : EXPORT_SYMBOL(ieee80211_tx_status_ext);
    1181                 :            : 
    1182                 :          0 : void ieee80211_tx_rate_update(struct ieee80211_hw *hw,
    1183                 :            :                               struct ieee80211_sta *pubsta,
    1184                 :            :                               struct ieee80211_tx_info *info)
    1185                 :            : {
    1186                 :          0 :         struct ieee80211_local *local = hw_to_local(hw);
    1187                 :          0 :         struct ieee80211_supported_band *sband = hw->wiphy->bands[info->band];
    1188                 :          0 :         struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
    1189                 :          0 :         struct ieee80211_tx_status status = {
    1190                 :            :                 .info = info,
    1191                 :            :                 .sta = pubsta,
    1192                 :            :         };
    1193                 :            : 
    1194                 :          0 :         rate_control_tx_status(local, sband, &status);
    1195                 :            : 
    1196         [ #  # ]:          0 :         if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL))
    1197                 :          0 :                 sta->tx_stats.last_rate = info->status.rates[0];
    1198                 :          0 : }
    1199                 :            : EXPORT_SYMBOL(ieee80211_tx_rate_update);
    1200                 :            : 
    1201                 :          0 : void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets)
    1202                 :            : {
    1203                 :          0 :         struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
    1204                 :          0 :         cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
    1205                 :            :                                     num_packets, GFP_ATOMIC);
    1206                 :          0 : }
    1207                 :            : EXPORT_SYMBOL(ieee80211_report_low_ack);
    1208                 :            : 
    1209                 :          0 : void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
    1210                 :            : {
    1211                 :          0 :         struct ieee80211_local *local = hw_to_local(hw);
    1212                 :            : 
    1213                 :          0 :         ieee80211_report_used_skb(local, skb, true);
    1214                 :          0 :         dev_kfree_skb_any(skb);
    1215                 :          0 : }
    1216                 :            : EXPORT_SYMBOL(ieee80211_free_txskb);
    1217                 :            : 
    1218                 :          0 : void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
    1219                 :            :                               struct sk_buff_head *skbs)
    1220                 :            : {
    1221                 :          0 :         struct sk_buff *skb;
    1222                 :            : 
    1223   [ #  #  #  # ]:          0 :         while ((skb = __skb_dequeue(skbs)))
    1224                 :          0 :                 ieee80211_free_txskb(hw, skb);
    1225                 :          0 : }

Generated by: LCOV version 1.14