Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/net/mac80211/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 169 kB image not shown  

Quelle  tx.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright 2002-2005, Instant802 Networks, Inc.
 * Copyright 2005-2006, Devicescape Software, Inc.
 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
 * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
 * Copyright 2013-2014  Intel Mobile Communications GmbH
 * Copyright (C) 2018-2025 Intel Corporation
 *
 * Transmit and frame generation functions.
 */


#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/if_vlan.h>
#include <linux/etherdevice.h>
#include <linux/bitmap.h>
#include <linux/rcupdate.h>
#include <linux/export.h>
#include <net/net_namespace.h>
#include <net/ieee80211_radiotap.h>
#include <net/cfg80211.h>
#include <net/mac80211.h>
#include <net/codel.h>
#include <net/codel_impl.h>
#include <linux/unaligned.h>
#include <net/fq_impl.h>
#include <net/sock.h>
#include <net/gso.h>

#include "ieee80211_i.h"
#include "driver-ops.h"
#include "led.h"
#include "mesh.h"
#include "wep.h"
#include "wpa.h"
#include "wme.h"
#include "rate.h"

/* misc utils */

static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
     struct sk_buff *skb, int group_addr,
     int next_frag_len)
{
 int rate, mrate, erp, dur, i;
 struct ieee80211_rate *txrate;
 struct ieee80211_local *local = tx->local;
 struct ieee80211_supported_band *sband;
 struct ieee80211_hdr *hdr;
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);

 /* assume HW handles this */
 if (tx->rate.flags & (IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS))
  return 0;

 /* uh huh? */
 if (WARN_ON_ONCE(tx->rate.idx < 0))
  return 0;

 sband = local->hw.wiphy->bands[info->band];
 txrate = &sband->bitrates[tx->rate.idx];

 erp = txrate->flags & IEEE80211_RATE_ERP_G;

 /* device is expected to do this */
 if (sband->band == NL80211_BAND_S1GHZ)
  return 0;

 /*
 * data and mgmt (except PS Poll):
 * - during CFP: 32768
 * - during contention period:
 *   if addr1 is group address: 0
 *   if more fragments = 0 and addr1 is individual address: time to
 *      transmit one ACK plus SIFS
 *   if more fragments = 1 and addr1 is individual address: time to
 *      transmit next fragment plus 2 x ACK plus 3 x SIFS
 *
 * IEEE 802.11, 9.6:
 * - control response frame (CTS or ACK) shall be transmitted using the
 *   same rate as the immediately previous frame in the frame exchange
 *   sequence, if this rate belongs to the PHY mandatory rates, or else
 *   at the highest possible rate belonging to the PHY rates in the
 *   BSSBasicRateSet
 */

 hdr = (struct ieee80211_hdr *)skb->data;
 if (ieee80211_is_ctl(hdr->frame_control)) {
  /* TODO: These control frames are not currently sent by
 * mac80211, but should they be implemented, this function
 * needs to be updated to support duration field calculation.
 *
 * RTS: time needed to transmit pending data/mgmt frame plus
 *    one CTS frame plus one ACK frame plus 3 x SIFS
 * CTS: duration of immediately previous RTS minus time
 *    required to transmit CTS and its SIFS
 * ACK: 0 if immediately previous directed data/mgmt had
 *    more=0, with more=1 duration in ACK frame is duration
 *    from previous frame minus time needed to transmit ACK
 *    and its SIFS
 * PS Poll: BIT(15) | BIT(14) | aid
 */

  return 0;
 }

 /* data/mgmt */
 if (0 /* FIX: data/mgmt during CFP */)
  return cpu_to_le16(32768);

 if (group_addr) /* Group address as the destination - no ACK */
  return 0;

 /* Individual destination address:
 * IEEE 802.11, Ch. 9.6 (after IEEE 802.11g changes)
 * CTS and ACK frames shall be transmitted using the highest rate in
 * basic rate set that is less than or equal to the rate of the
 * immediately previous frame and that is using the same modulation
 * (CCK or OFDM). If no basic rate set matches with these requirements,
 * the highest mandatory rate of the PHY that is less than or equal to
 * the rate of the previous frame is used.
 * Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps
 */

 rate = -1;
 /* use lowest available if everything fails */
 mrate = sband->bitrates[0].bitrate;
 for (i = 0; i < sband->n_bitrates; i++) {
  struct ieee80211_rate *r = &sband->bitrates[i];
  u32 flag;

  if (r->bitrate > txrate->bitrate)
   break;

  if (tx->sdata->vif.bss_conf.basic_rates & BIT(i))
   rate = r->bitrate;

  switch (sband->band) {
  case NL80211_BAND_2GHZ:
  case NL80211_BAND_LC:
   if (tx->sdata->deflink.operating_11g_mode)
    flag = IEEE80211_RATE_MANDATORY_G;
   else
    flag = IEEE80211_RATE_MANDATORY_B;
   break;
  case NL80211_BAND_5GHZ:
  case NL80211_BAND_6GHZ:
   flag = IEEE80211_RATE_MANDATORY_A;
   break;
  default:
   flag = 0;
   WARN_ON(1);
   break;
  }

  if (r->flags & flag)
   mrate = r->bitrate;
 }
 if (rate == -1) {
  /* No matching basic rate found; use highest suitable mandatory
 * PHY rate */

  rate = mrate;
 }

 /* Don't calculate ACKs for QoS Frames with NoAck Policy set */
 if (ieee80211_is_data_qos(hdr->frame_control) &&
     *(ieee80211_get_qos_ctl(hdr)) & IEEE80211_QOS_CTL_ACK_POLICY_NOACK)
  dur = 0;
 else
  /* Time needed to transmit ACK
 * (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up
 * to closest integer */

  dur = ieee80211_frame_duration(sband->band, 10, rate, erp,
    tx->sdata->vif.bss_conf.use_short_preamble);

 if (next_frag_len) {
  /* Frame is fragmented: duration increases with time needed to
 * transmit next fragment plus ACK and 2 x SIFS. */

  dur *= 2; /* ACK + SIFS */
  /* next fragment */
  dur += ieee80211_frame_duration(sband->band, next_frag_len,
    txrate->bitrate, erp,
    tx->sdata->vif.bss_conf.use_short_preamble);
 }

 return cpu_to_le16(dur);
}

/* tx handlers */
static ieee80211_tx_result debug_noinline
ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
{
 struct ieee80211_local *local = tx->local;
 struct ieee80211_if_managed *ifmgd;
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);

 /* driver doesn't support power save */
 if (!ieee80211_hw_check(&local->hw, SUPPORTS_PS))
  return TX_CONTINUE;

 /* hardware does dynamic power save */
 if (ieee80211_hw_check(&local->hw, SUPPORTS_DYNAMIC_PS))
  return TX_CONTINUE;

 /* dynamic power save disabled */
 if (local->hw.conf.dynamic_ps_timeout <= 0)
  return TX_CONTINUE;

 /* we are scanning, don't enable power save */
 if (local->scanning)
  return TX_CONTINUE;

 if (!local->ps_sdata)
  return TX_CONTINUE;

 /* No point if we're going to suspend */
 if (local->quiescing)
  return TX_CONTINUE;

 /* dynamic ps is supported only in managed mode */
 if (tx->sdata->vif.type != NL80211_IFTYPE_STATION)
  return TX_CONTINUE;

 if (unlikely(info->flags & IEEE80211_TX_INTFL_OFFCHAN_TX_OK))
  return TX_CONTINUE;

 ifmgd = &tx->sdata->u.mgd;

 /*
 * Don't wakeup from power save if u-apsd is enabled, voip ac has
 * u-apsd enabled and the frame is in voip class. This effectively
 * means that even if all access categories have u-apsd enabled, in
 * practise u-apsd is only used with the voip ac. This is a
 * workaround for the case when received voip class packets do not
 * have correct qos tag for some reason, due the network or the
 * peer application.
 *
 * Note: ifmgd->uapsd_queues access is racy here. If the value is
 * changed via debugfs, user needs to reassociate manually to have
 * everything in sync.
 */

 if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) &&
     (ifmgd->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) &&
     skb_get_queue_mapping(tx->skb) == IEEE80211_AC_VO)
  return TX_CONTINUE;

 if (local->hw.conf.flags & IEEE80211_CONF_PS) {
  ieee80211_stop_queues_by_reason(&local->hw,
      IEEE80211_MAX_QUEUE_MAP,
      IEEE80211_QUEUE_STOP_REASON_PS,
      false);
  ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
  wiphy_work_queue(local->hw.wiphy,
     &local->dynamic_ps_disable_work);
 }

 /* Don't restart the timer if we're not disassociated */
 if (!ifmgd->associated)
  return TX_CONTINUE;

 mod_timer(&local->dynamic_ps_timer, jiffies +
    msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));

 return TX_CONTINUE;
}

static ieee80211_tx_result debug_noinline
ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
{

 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
 bool assoc = false;

 if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED))
  return TX_CONTINUE;

 if (unlikely(test_bit(SCAN_SW_SCANNING, &tx->local->scanning)) &&
     test_bit(SDATA_STATE_OFFCHANNEL, &tx->sdata->state) &&
     !ieee80211_is_probe_req(hdr->frame_control) &&
     !ieee80211_is_any_nullfunc(hdr->frame_control))
  /*
 * When software scanning only nullfunc frames (to notify
 * the sleep state to the AP) and probe requests (for the
 * active scan) are allowed, all other frames should not be
 * sent and we should not get here, but if we do
 * nonetheless, drop them to avoid sending them
 * off-channel. See the link below and
 * ieee80211_start_scan() for more.
 *
 * http://article.gmane.org/gmane.linux.kernel.wireless.general/30089
 */

  return TX_DROP;

 if (tx->sdata->vif.type == NL80211_IFTYPE_OCB)
  return TX_CONTINUE;

 if (tx->flags & IEEE80211_TX_PS_BUFFERED)
  return TX_CONTINUE;

 if (tx->sta)
  assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);

 if (likely(tx->flags & IEEE80211_TX_UNICAST)) {
  if (unlikely(!assoc &&
        ieee80211_is_data(hdr->frame_control))) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
   sdata_info(tx->sdata,
       "dropped data frame to not associated station %pM\n",
       hdr->addr1);
#endif
   I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
   return TX_DROP;
  }
 } else if (unlikely(ieee80211_is_data(hdr->frame_control) &&
       ieee80211_vif_get_num_mcast_if(tx->sdata) == 0)) {
  /*
 * No associated STAs - no need to send multicast
 * frames.
 */

  return TX_DROP;
 }

 return TX_CONTINUE;
}

/* This function is called whenever the AP is about to exceed the maximum limit
 * of buffered frames for power saving STAs. This situation should not really
 * happen often during normal operation, so dropping the oldest buffered packet
 * from each queue should be OK to make some room for new frames. */

static void purge_old_ps_buffers(struct ieee80211_local *local)
{
 int total = 0, purged = 0;
 struct sk_buff *skb;
 struct ieee80211_sub_if_data *sdata;
 struct sta_info *sta;

 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
  struct ps_data *ps;

  if (sdata->vif.type == NL80211_IFTYPE_AP)
   ps = &sdata->u.ap.ps;
  else if (ieee80211_vif_is_mesh(&sdata->vif))
   ps = &sdata->u.mesh.ps;
  else
   continue;

  skb = skb_dequeue(&ps->bc_buf);
  if (skb) {
   purged++;
   ieee80211_free_txskb(&local->hw, skb);
  }
  total += skb_queue_len(&ps->bc_buf);
 }

 /*
 * Drop one frame from each station from the lowest-priority
 * AC that has frames at all.
 */

 list_for_each_entry_rcu(sta, &local->sta_list, list) {
  int ac;

  for (ac = IEEE80211_AC_BK; ac >= IEEE80211_AC_VO; ac--) {
   skb = skb_dequeue(&sta->ps_tx_buf[ac]);
   total += skb_queue_len(&sta->ps_tx_buf[ac]);
   if (skb) {
    purged++;
    ieee80211_free_txskb(&local->hw, skb);
    break;
   }
  }
 }

 local->total_ps_buffered = total;
 ps_dbg_hw(&local->hw, "PS buffers full - purged %d frames\n", purged);
}

static ieee80211_tx_result
ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
{
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 struct ps_data *ps;

 /*
 * broadcast/multicast frame
 *
 * If any of the associated/peer stations is in power save mode,
 * the frame is buffered to be sent after DTIM beacon frame.
 * This is done either by the hardware or us.
 */


 /* powersaving STAs currently only in AP/VLAN/mesh mode */
 if (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
     tx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
  if (!tx->sdata->bss)
   return TX_CONTINUE;

  ps = &tx->sdata->bss->ps;
 } else if (ieee80211_vif_is_mesh(&tx->sdata->vif)) {
  ps = &tx->sdata->u.mesh.ps;
 } else {
  return TX_CONTINUE;
 }


 /* no buffering for ordered frames */
 if (ieee80211_has_order(hdr->frame_control))
  return TX_CONTINUE;

 if (ieee80211_is_probe_req(hdr->frame_control))
  return TX_CONTINUE;

 if (ieee80211_hw_check(&tx->local->hw, QUEUE_CONTROL))
  info->hw_queue = tx->sdata->vif.cab_queue;

 /* no stations in PS mode and no buffered packets */
 if (!atomic_read(&ps->num_sta_ps) && skb_queue_empty(&ps->bc_buf))
  return TX_CONTINUE;

 info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;

 /* device releases frame after DTIM beacon */
 if (!ieee80211_hw_check(&tx->local->hw, HOST_BROADCAST_PS_BUFFERING))
  return TX_CONTINUE;

 /* buffered in mac80211 */
 if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
  purge_old_ps_buffers(tx->local);

 if (skb_queue_len(&ps->bc_buf) >= AP_MAX_BC_BUFFER) {
  ps_dbg(tx->sdata,
         "BC TX buffer full - dropping the oldest frame\n");
  ieee80211_free_txskb(&tx->local->hw, skb_dequeue(&ps->bc_buf));
 } else
  tx->local->total_ps_buffered++;

 skb_queue_tail(&ps->bc_buf, tx->skb);

 return TX_QUEUED;
}

static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta,
        struct sk_buff *skb)
{
 if (!ieee80211_is_mgmt(fc))
  return 0;

 if (sta == NULL || !test_sta_flag(sta, WLAN_STA_MFP))
  return 0;

 if (!ieee80211_is_robust_mgmt_frame(skb))
  return 0;

 return 1;
}

static ieee80211_tx_result
ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
{
 struct sta_info *sta = tx->sta;
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 struct ieee80211_local *local = tx->local;

 if (unlikely(!sta))
  return TX_CONTINUE;

 if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) ||
        test_sta_flag(sta, WLAN_STA_PS_DRIVER) ||
        test_sta_flag(sta, WLAN_STA_PS_DELIVER)) &&
       !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) {
  int ac = skb_get_queue_mapping(tx->skb);

  if (ieee80211_is_mgmt(hdr->frame_control) &&
      !ieee80211_is_bufferable_mmpdu(tx->skb)) {
   info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
   return TX_CONTINUE;
  }

  ps_dbg(sta->sdata, "STA %pM aid %d: PS buffer for AC %d\n",
         sta->sta.addr, sta->sta.aid, ac);
  if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
   purge_old_ps_buffers(tx->local);

  /* sync with ieee80211_sta_ps_deliver_wakeup */
  spin_lock(&sta->ps_lock);
  /*
 * STA woke up the meantime and all the frames on ps_tx_buf have
 * been queued to pending queue. No reordering can happen, go
 * ahead and Tx the packet.
 */

  if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
      !test_sta_flag(sta, WLAN_STA_PS_DRIVER) &&
      !test_sta_flag(sta, WLAN_STA_PS_DELIVER)) {
   spin_unlock(&sta->ps_lock);
   return TX_CONTINUE;
  }

  if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
   struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
   ps_dbg(tx->sdata,
          "STA %pM TX buffer for AC %d full - dropping oldest frame\n",
          sta->sta.addr, ac);
   ieee80211_free_txskb(&local->hw, old);
  } else
   tx->local->total_ps_buffered++;

  info->control.jiffies = jiffies;
  info->control.vif = &tx->sdata->vif;
  info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
  info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
  skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
  spin_unlock(&sta->ps_lock);

  if (!timer_pending(&local->sta_cleanup))
   mod_timer(&local->sta_cleanup,
      round_jiffies(jiffies +
      STA_INFO_CLEANUP_INTERVAL));

  /*
 * We queued up some frames, so the TIM bit might
 * need to be set, recalculate it.
 */

  sta_info_recalc_tim(sta);

  return TX_QUEUED;
 } else if (unlikely(test_sta_flag(sta, WLAN_STA_PS_STA))) {
  ps_dbg(tx->sdata,
         "STA %pM in PS mode, but polling/in SP -> send frame\n",
         sta->sta.addr);
 }

 return TX_CONTINUE;
}

static ieee80211_tx_result debug_noinline
ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx)
{
 if (unlikely(tx->flags & IEEE80211_TX_PS_BUFFERED))
  return TX_CONTINUE;

 if (tx->flags & IEEE80211_TX_UNICAST)
  return ieee80211_tx_h_unicast_ps_buf(tx);
 else
  return ieee80211_tx_h_multicast_ps_buf(tx);
}

static ieee80211_tx_result debug_noinline
ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx)
{
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);

 if (unlikely(tx->sdata->control_port_protocol == tx->skb->protocol)) {
  if (tx->sdata->control_port_no_encrypt)
   info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
  info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO;
  info->flags |= IEEE80211_TX_CTL_USE_MINRATE;
 }

 return TX_CONTINUE;
}

static struct ieee80211_key *
ieee80211_select_link_key(struct ieee80211_tx_data *tx)
{
 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
 struct ieee80211_link_data *link;
 unsigned int link_id;

 link_id = u32_get_bits(info->control.flags, IEEE80211_TX_CTRL_MLO_LINK);
 if (link_id == IEEE80211_LINK_UNSPECIFIED) {
  link = &tx->sdata->deflink;
 } else {
  link = rcu_dereference(tx->sdata->link[link_id]);
  if (!link)
   return NULL;
 }

 if (ieee80211_is_group_privacy_action(tx->skb))
  return rcu_dereference(link->default_multicast_key);
 else if (ieee80211_is_mgmt(hdr->frame_control) &&
   is_multicast_ether_addr(hdr->addr1) &&
   ieee80211_is_robust_mgmt_frame(tx->skb))
  return rcu_dereference(link->default_mgmt_key);
 else if (is_multicast_ether_addr(hdr->addr1))
  return rcu_dereference(link->default_multicast_key);

 return NULL;
}

static ieee80211_tx_result debug_noinline
ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
{
 struct ieee80211_key *key;
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;

 if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) {
  tx->key = NULL;
  return TX_CONTINUE;
 }

 if (tx->sta &&
     (key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx])))
  tx->key = key;
 else if ((key = ieee80211_select_link_key(tx)))
  tx->key = key;
 else if (!is_multicast_ether_addr(hdr->addr1) &&
   (key = rcu_dereference(tx->sdata->default_unicast_key)))
  tx->key = key;
 else
  tx->key = NULL;

 if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
  if (tx->key && tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
   info->control.hw_key = &tx->key->conf;
  return TX_CONTINUE;
 }

 if (tx->key) {
  bool skip_hw = false;

  /* TODO: add threshold stuff again */

  switch (tx->key->conf.cipher) {
  case WLAN_CIPHER_SUITE_WEP40:
  case WLAN_CIPHER_SUITE_WEP104:
  case WLAN_CIPHER_SUITE_TKIP:
   if (!ieee80211_is_data_present(hdr->frame_control))
    tx->key = NULL;
   break;
  case WLAN_CIPHER_SUITE_CCMP:
  case WLAN_CIPHER_SUITE_CCMP_256:
  case WLAN_CIPHER_SUITE_GCMP:
  case WLAN_CIPHER_SUITE_GCMP_256:
   if (!ieee80211_is_data_present(hdr->frame_control) &&
       !ieee80211_use_mfp(hdr->frame_control, tx->sta,
            tx->skb) &&
       !ieee80211_is_group_privacy_action(tx->skb))
    tx->key = NULL;
   else
    skip_hw = (tx->key->conf.flags &
        IEEE80211_KEY_FLAG_SW_MGMT_TX) &&
     ieee80211_is_mgmt(hdr->frame_control);
   break;
  case WLAN_CIPHER_SUITE_AES_CMAC:
  case WLAN_CIPHER_SUITE_BIP_CMAC_256:
  case WLAN_CIPHER_SUITE_BIP_GMAC_128:
  case WLAN_CIPHER_SUITE_BIP_GMAC_256:
   if (!ieee80211_is_mgmt(hdr->frame_control))
    tx->key = NULL;
   break;
  }

  if (unlikely(tx->key && tx->key->flags & KEY_FLAG_TAINTED &&
        !ieee80211_is_deauth(hdr->frame_control)) &&
        tx->skb->protocol != tx->sdata->control_port_protocol)
   return TX_DROP;

  if (!skip_hw && tx->key &&
      tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
   info->control.hw_key = &tx->key->conf;
 } else if (ieee80211_is_data_present(hdr->frame_control) && tx->sta &&
     test_sta_flag(tx->sta, WLAN_STA_USES_ENCRYPTION)) {
  return TX_DROP;
 }

 return TX_CONTINUE;
}

static ieee80211_tx_result debug_noinline
ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
{
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
 struct ieee80211_hdr *hdr = (void *)tx->skb->data;
 struct ieee80211_supported_band *sband;
 u32 len;
 struct ieee80211_tx_rate_control txrc;
 struct ieee80211_sta_rates *ratetbl = NULL;
 bool encap = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
 bool assoc = false;

 memset(&txrc, 0, sizeof(txrc));

 sband = tx->local->hw.wiphy->bands[info->band];

 len = min_t(u32, tx->skb->len + FCS_LEN,
    tx->local->hw.wiphy->frag_threshold);

 /* set up the tx rate control struct we give the RC algo */
 txrc.hw = &tx->local->hw;
 txrc.sband = sband;
 txrc.bss_conf = &tx->sdata->vif.bss_conf;
 txrc.skb = tx->skb;
 txrc.reported_rate.idx = -1;

 if (unlikely(info->control.flags & IEEE80211_TX_CTRL_DONT_USE_RATE_MASK)) {
  txrc.rate_idx_mask = ~0;
 } else {
  txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[info->band];

  if (tx->sdata->rc_has_mcs_mask[info->band])
   txrc.rate_idx_mcs_mask =
    tx->sdata->rc_rateidx_mcs_mask[info->band];
 }

 txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
      tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
      tx->sdata->vif.type == NL80211_IFTYPE_ADHOC ||
      tx->sdata->vif.type == NL80211_IFTYPE_OCB);

 /* set up RTS protection if desired */
 if (len > tx->local->hw.wiphy->rts_threshold) {
  txrc.rts = true;
 }

 info->control.use_rts = txrc.rts;
 info->control.use_cts_prot = tx->sdata->vif.bss_conf.use_cts_prot;

 /*
 * Use short preamble if the BSS can handle it, but not for
 * management frames unless we know the receiver can handle
 * that -- the management frame might be to a station that
 * just wants a probe response.
 */

 if (tx->sdata->vif.bss_conf.use_short_preamble &&
     (ieee80211_is_tx_data(tx->skb) ||
      (tx->sta && test_sta_flag(tx->sta, WLAN_STA_SHORT_PREAMBLE))))
  txrc.short_preamble = true;

 info->control.short_preamble = txrc.short_preamble;

 /* don't ask rate control when rate already injected via radiotap */
 if (info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)
  return TX_CONTINUE;

 if (tx->sta)
  assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);

 /*
 * Lets not bother rate control if we're associated and cannot
 * talk to the sta. This should not happen.
 */

 if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) && assoc &&
   !rate_usable_index_exists(sband, &tx->sta->sta),
   "%s: Dropped data frame as no usable bitrate found while "
   "scanning and associated. Target station: "
   "%pM on %d GHz band\n",
   tx->sdata->name,
   encap ? ((struct ethhdr *)hdr)->h_dest : hdr->addr1,
   info->band ? 5 : 2))
  return TX_DROP;

 /*
 * If we're associated with the sta at this point we know we can at
 * least send the frame at the lowest bit rate.
 */

 rate_control_get_rate(tx->sdata, tx->sta, &txrc);

 if (tx->sta && !info->control.skip_table)
  ratetbl = rcu_dereference(tx->sta->sta.rates);

 if (unlikely(info->control.rates[0].idx < 0)) {
  if (ratetbl) {
   struct ieee80211_tx_rate rate = {
    .idx = ratetbl->rate[0].idx,
    .flags = ratetbl->rate[0].flags,
    .count = ratetbl->rate[0].count
   };

   if (ratetbl->rate[0].idx < 0)
    return TX_DROP;

   tx->rate = rate;
  } else {
   return TX_DROP;
  }
 } else {
  tx->rate = info->control.rates[0];
 }

 if (txrc.reported_rate.idx < 0) {
  txrc.reported_rate = tx->rate;
  if (tx->sta && ieee80211_is_tx_data(tx->skb))
   tx->sta->deflink.tx_stats.last_rate = txrc.reported_rate;
 } else if (tx->sta)
  tx->sta->deflink.tx_stats.last_rate = txrc.reported_rate;

 if (ratetbl)
  return TX_CONTINUE;

 if (unlikely(!info->control.rates[0].count))
  info->control.rates[0].count = 1;

 if (WARN_ON_ONCE((info->control.rates[0].count > 1) &&
    (info->flags & IEEE80211_TX_CTL_NO_ACK)))
  info->control.rates[0].count = 1;

 return TX_CONTINUE;
}

static __le16 ieee80211_tx_next_seq(struct sta_info *sta, int tid)
{
 u16 *seq = &sta->tid_seq[tid];
 __le16 ret = cpu_to_le16(*seq);

 /* Increase the sequence number. */
 *seq = (*seq + 0x10) & IEEE80211_SCTL_SEQ;

 return ret;
}

static ieee80211_tx_result debug_noinline
ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
{
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 int tid;

 /*
 * Packet injection may want to control the sequence
 * number, if we have no matching interface then we
 * neither assign one ourselves nor ask the driver to.
 */

 if (unlikely(info->control.vif->type == NL80211_IFTYPE_MONITOR))
  return TX_CONTINUE;

 if (unlikely(ieee80211_is_ctl(hdr->frame_control)))
  return TX_CONTINUE;

 if (ieee80211_hdrlen(hdr->frame_control) < 24)
  return TX_CONTINUE;

 if (ieee80211_is_qos_nullfunc(hdr->frame_control))
  return TX_CONTINUE;

 if (info->control.flags & IEEE80211_TX_CTRL_NO_SEQNO)
  return TX_CONTINUE;

 /* SNS11 from 802.11be 10.3.2.14 */
 if (unlikely(is_multicast_ether_addr(hdr->addr1) &&
       ieee80211_vif_is_mld(info->control.vif) &&
       info->control.vif->type == NL80211_IFTYPE_AP)) {
  if (info->control.flags & IEEE80211_TX_CTRL_MCAST_MLO_FIRST_TX)
   tx->sdata->mld_mcast_seq += 0x10;
  hdr->seq_ctrl = cpu_to_le16(tx->sdata->mld_mcast_seq);
  return TX_CONTINUE;
 }

 /*
 * Anything but QoS data that has a sequence number field
 * (is long enough) gets a sequence number from the global
 * counter.  QoS data frames with a multicast destination
 * also use the global counter (802.11-2012 9.3.2.10).
 */

 if (!ieee80211_is_data_qos(hdr->frame_control) ||
     is_multicast_ether_addr(hdr->addr1)) {
  /* driver should assign sequence number */
  info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
  /* for pure STA mode without beacons, we can do it */
  hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number);
  tx->sdata->sequence_number += 0x10;
  if (tx->sta)
   tx->sta->deflink.tx_stats.msdu[IEEE80211_NUM_TIDS]++;
  return TX_CONTINUE;
 }

 /*
 * This should be true for injected/management frames only, for
 * management frames we have set the IEEE80211_TX_CTL_ASSIGN_SEQ
 * above since they are not QoS-data frames.
 */

 if (!tx->sta)
  return TX_CONTINUE;

 /* include per-STA, per-TID sequence counter */
 tid = ieee80211_get_tid(hdr);
 tx->sta->deflink.tx_stats.msdu[tid]++;

 hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid);

 return TX_CONTINUE;
}

static int ieee80211_fragment(struct ieee80211_tx_data *tx,
         struct sk_buff *skb, int hdrlen,
         int frag_threshold)
{
 struct ieee80211_local *local = tx->local;
 struct ieee80211_tx_info *info;
 struct sk_buff *tmp;
 int per_fragm = frag_threshold - hdrlen - FCS_LEN;
 int pos = hdrlen + per_fragm;
 int rem = skb->len - hdrlen - per_fragm;

 if (WARN_ON(rem < 0))
  return -EINVAL;

 /* first fragment was already added to queue by caller */

 while (rem) {
  int fraglen = per_fragm;

  if (fraglen > rem)
   fraglen = rem;
  rem -= fraglen;
  tmp = dev_alloc_skb(local->tx_headroom +
        frag_threshold +
        IEEE80211_ENCRYPT_HEADROOM +
        IEEE80211_ENCRYPT_TAILROOM);
  if (!tmp)
   return -ENOMEM;

  __skb_queue_tail(&tx->skbs, tmp);

  skb_reserve(tmp,
       local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM);

  /* copy control information */
  memcpy(tmp->cb, skb->cb, sizeof(tmp->cb));

  info = IEEE80211_SKB_CB(tmp);
  info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT |
     IEEE80211_TX_CTL_FIRST_FRAGMENT);

  if (rem)
   info->flags |= IEEE80211_TX_CTL_MORE_FRAMES;

  skb_copy_queue_mapping(tmp, skb);
  tmp->priority = skb->priority;
  tmp->dev = skb->dev;

  /* copy header and data */
  skb_put_data(tmp, skb->data, hdrlen);
  skb_put_data(tmp, skb->data + pos, fraglen);

  pos += fraglen;
 }

 /* adjust first fragment's length */
 skb_trim(skb, hdrlen + per_fragm);
 return 0;
}

static ieee80211_tx_result debug_noinline
ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
{
 struct sk_buff *skb = tx->skb;
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 struct ieee80211_hdr *hdr = (void *)skb->data;
 int frag_threshold = tx->local->hw.wiphy->frag_threshold;
 int hdrlen;
 int fragnum;

 /* no matter what happens, tx->skb moves to tx->skbs */
 __skb_queue_tail(&tx->skbs, skb);
 tx->skb = NULL;

 if (info->flags & IEEE80211_TX_CTL_DONTFRAG)
  return TX_CONTINUE;

 if (ieee80211_hw_check(&tx->local->hw, SUPPORTS_TX_FRAG))
  return TX_CONTINUE;

 /*
 * Warn when submitting a fragmented A-MPDU frame and drop it.
 * This scenario is handled in ieee80211_tx_prepare but extra
 * caution taken here as fragmented ampdu may cause Tx stop.
 */

 if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU))
  return TX_DROP;

 hdrlen = ieee80211_hdrlen(hdr->frame_control);

 /* internal error, why isn't DONTFRAG set? */
 if (WARN_ON(skb->len + FCS_LEN <= frag_threshold))
  return TX_DROP;

 /*
 * Now fragment the frame. This will allocate all the fragments and
 * chain them (using skb as the first fragment) to skb->next.
 * During transmission, we will remove the successfully transmitted
 * fragments from this list. When the low-level driver rejects one
 * of the fragments then we will simply pretend to accept the skb
 * but store it away as pending.
 */

 if (ieee80211_fragment(tx, skb, hdrlen, frag_threshold))
  return TX_DROP;

 /* update duration/seq/flags of fragments */
 fragnum = 0;

 skb_queue_walk(&tx->skbs, skb) {
  const __le16 morefrags = cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);

  hdr = (void *)skb->data;
  info = IEEE80211_SKB_CB(skb);

  if (!skb_queue_is_last(&tx->skbs, skb)) {
   hdr->frame_control |= morefrags;
   /*
 * No multi-rate retries for fragmented frames, that
 * would completely throw off the NAV at other STAs.
 */

   info->control.rates[1].idx = -1;
   info->control.rates[2].idx = -1;
   info->control.rates[3].idx = -1;
   BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 4);
   info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
  } else {
   hdr->frame_control &= ~morefrags;
  }
  hdr->seq_ctrl |= cpu_to_le16(fragnum & IEEE80211_SCTL_FRAG);
  fragnum++;
 }

 return TX_CONTINUE;
}

static ieee80211_tx_result debug_noinline
ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
{
 struct sk_buff *skb;
 int ac = -1;

 if (!tx->sta)
  return TX_CONTINUE;

 skb_queue_walk(&tx->skbs, skb) {
  ac = skb_get_queue_mapping(skb);
  tx->sta->deflink.tx_stats.bytes[ac] += skb->len;
 }
 if (ac >= 0)
  tx->sta->deflink.tx_stats.packets[ac]++;

 return TX_CONTINUE;
}

static ieee80211_tx_result debug_noinline
ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
{
 if (!tx->key)
  return TX_CONTINUE;

 switch (tx->key->conf.cipher) {
 case WLAN_CIPHER_SUITE_WEP40:
 case WLAN_CIPHER_SUITE_WEP104:
  return ieee80211_crypto_wep_encrypt(tx);
 case WLAN_CIPHER_SUITE_TKIP:
  return ieee80211_crypto_tkip_encrypt(tx);
 case WLAN_CIPHER_SUITE_CCMP:
  return ieee80211_crypto_ccmp_encrypt(
   tx, IEEE80211_CCMP_MIC_LEN);
 case WLAN_CIPHER_SUITE_CCMP_256:
  return ieee80211_crypto_ccmp_encrypt(
   tx, IEEE80211_CCMP_256_MIC_LEN);
 case WLAN_CIPHER_SUITE_AES_CMAC:
  return ieee80211_crypto_aes_cmac_encrypt(tx);
 case WLAN_CIPHER_SUITE_BIP_CMAC_256:
  return ieee80211_crypto_aes_cmac_256_encrypt(tx);
 case WLAN_CIPHER_SUITE_BIP_GMAC_128:
 case WLAN_CIPHER_SUITE_BIP_GMAC_256:
  return ieee80211_crypto_aes_gmac_encrypt(tx);
 case WLAN_CIPHER_SUITE_GCMP:
 case WLAN_CIPHER_SUITE_GCMP_256:
  return ieee80211_crypto_gcmp_encrypt(tx);
 }

 return TX_DROP;
}

static ieee80211_tx_result debug_noinline
ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx)
{
 struct sk_buff *skb;
 struct ieee80211_hdr *hdr;
 int next_len;
 bool group_addr;

 skb_queue_walk(&tx->skbs, skb) {
  hdr = (void *) skb->data;
  if (unlikely(ieee80211_is_pspoll(hdr->frame_control)))
   break/* must not overwrite AID */
  if (!skb_queue_is_last(&tx->skbs, skb)) {
   struct sk_buff *next = skb_queue_next(&tx->skbs, skb);
   next_len = next->len;
  } else
   next_len = 0;
  group_addr = is_multicast_ether_addr(hdr->addr1);

  hdr->duration_id =
   ieee80211_duration(tx, skb, group_addr, next_len);
 }

 return TX_CONTINUE;
}

/* actual transmit path */

static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
      struct sk_buff *skb,
      struct ieee80211_tx_info *info,
      struct tid_ampdu_tx *tid_tx,
      int tid)
{
 bool queued = false;
 bool reset_agg_timer = false;
 struct sk_buff *purge_skb = NULL;

 if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
  reset_agg_timer = true;
 } else if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
  /*
 * nothing -- this aggregation session is being started
 * but that might still fail with the driver
 */

 } else if (!tx->sta->sta.txq[tid]) {
  spin_lock(&tx->sta->lock);
  /*
 * Need to re-check now, because we may get here
 *
 *  1) in the window during which the setup is actually
 *     already done, but not marked yet because not all
 *     packets are spliced over to the driver pending
 *     queue yet -- if this happened we acquire the lock
 *     either before or after the splice happens, but
 *     need to recheck which of these cases happened.
 *
 *  2) during session teardown, if the OPERATIONAL bit
 *     was cleared due to the teardown but the pointer
 *     hasn't been assigned NULL yet (or we loaded it
 *     before it was assigned) -- in this case it may
 *     now be NULL which means we should just let the
 *     packet pass through because splicing the frames
 *     back is already done.
 */

  tid_tx = rcu_dereference_protected_tid_tx(tx->sta, tid);

  if (!tid_tx) {
   /* do nothing, let packet pass through */
  } else if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
   reset_agg_timer = true;
  } else {
   queued = true;
   if (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER) {
    clear_sta_flag(tx->sta, WLAN_STA_SP);
    ps_dbg(tx->sta->sdata,
           "STA %pM aid %d: SP frame queued, close the SP w/o telling the peer\n",
           tx->sta->sta.addr, tx->sta->sta.aid);
   }
   info->control.vif = &tx->sdata->vif;
   info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
   info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
   __skb_queue_tail(&tid_tx->pending, skb);
   if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER)
    purge_skb = __skb_dequeue(&tid_tx->pending);
  }
  spin_unlock(&tx->sta->lock);

  if (purge_skb)
   ieee80211_free_txskb(&tx->local->hw, purge_skb);
 }

 /* reset session timer */
 if (reset_agg_timer)
  tid_tx->last_tx = jiffies;

 return queued;
}

void ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata,
     struct sta_info *sta, struct sk_buff *skb)
{
 struct rate_control_ref *ref = sdata->local->rate_ctrl;
 u16 tid;

 if (!ref || !(ref->ops->capa & RATE_CTRL_CAPA_AMPDU_TRIGGER))
  return;

 if (!sta ||
     (!sta->sta.valid_links && !sta->sta.deflink.ht_cap.ht_supported &&
      !sta->sta.deflink.s1g_cap.s1g) ||
     !sta->sta.wme || skb_get_queue_mapping(skb) == IEEE80211_AC_VO ||
     skb->protocol == sdata->control_port_protocol)
  return;

 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
 if (likely(sta->ampdu_mlme.tid_tx[tid]))
  return;

 ieee80211_start_tx_ba_session(&sta->sta, tid, 0);
}

/*
 * initialises @tx
 * pass %NULL for the station if unknown, a valid pointer if known
 * or an ERR_PTR() if the station is known not to exist
 */

static ieee80211_tx_result
ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
       struct ieee80211_tx_data *tx,
       struct sta_info *sta, struct sk_buff *skb)
{
 struct ieee80211_local *local = sdata->local;
 struct ieee80211_hdr *hdr;
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 bool aggr_check = false;
 int tid;

 memset(tx, 0, sizeof(*tx));
 tx->skb = skb;
 tx->local = local;
 tx->sdata = sdata;
 __skb_queue_head_init(&tx->skbs);

 /*
 * If this flag is set to true anywhere, and we get here,
 * we are doing the needed processing, so remove the flag
 * now.
 */

 info->control.flags &= ~IEEE80211_TX_INTCFL_NEED_TXPROCESSING;

 hdr = (struct ieee80211_hdr *) skb->data;

 if (likely(sta)) {
  if (!IS_ERR(sta))
   tx->sta = sta;
 } else {
  if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
   tx->sta = rcu_dereference(sdata->u.vlan.sta);
   if (!tx->sta && sdata->wdev.use_4addr)
    return TX_DROP;
  } else if (tx->sdata->control_port_protocol == tx->skb->protocol) {
   tx->sta = sta_info_get_bss(sdata, hdr->addr1);
  }
  if (!tx->sta && !is_multicast_ether_addr(hdr->addr1)) {
   tx->sta = sta_info_get(sdata, hdr->addr1);
   aggr_check = true;
  }
 }

 if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
     !ieee80211_is_qos_nullfunc(hdr->frame_control) &&
     ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION) &&
     !ieee80211_hw_check(&local->hw, TX_AMPDU_SETUP_IN_HW)) {
  struct tid_ampdu_tx *tid_tx;

  tid = ieee80211_get_tid(hdr);
  tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]);
  if (!tid_tx && aggr_check) {
   ieee80211_aggr_check(sdata, tx->sta, skb);
   tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]);
  }

  if (tid_tx) {
   bool queued;

   queued = ieee80211_tx_prep_agg(tx, skb, info,
             tid_tx, tid);

   if (unlikely(queued))
    return TX_QUEUED;
  }
 }

 if (is_multicast_ether_addr(hdr->addr1)) {
  tx->flags &= ~IEEE80211_TX_UNICAST;
  info->flags |= IEEE80211_TX_CTL_NO_ACK;
 } else
  tx->flags |= IEEE80211_TX_UNICAST;

 if (!(info->flags & IEEE80211_TX_CTL_DONTFRAG)) {
  if (!(tx->flags & IEEE80211_TX_UNICAST) ||
      skb->len + FCS_LEN <= local->hw.wiphy->frag_threshold ||
      info->flags & IEEE80211_TX_CTL_AMPDU)
   info->flags |= IEEE80211_TX_CTL_DONTFRAG;
 }

 if (!tx->sta)
  info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
 else if (test_and_clear_sta_flag(tx->sta, WLAN_STA_CLEAR_PS_FILT)) {
  info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
  ieee80211_check_fast_xmit(tx->sta);
 }

 info->flags |= IEEE80211_TX_CTL_FIRST_FRAGMENT;

 return TX_CONTINUE;
}

static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
       struct ieee80211_vif *vif,
       struct sta_info *sta,
       struct sk_buff *skb)
{
 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 struct ieee80211_txq *txq = NULL;

 if ((info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) ||
     (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
  return NULL;

 if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
     unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
  if ((!ieee80211_is_mgmt(hdr->frame_control) ||
       ieee80211_is_bufferable_mmpdu(skb) ||
       vif->type == NL80211_IFTYPE_STATION) &&
      sta && sta->uploaded) {
   /*
 * This will be NULL if the driver didn't set the
 * opt-in hardware flag.
 */

   txq = sta->sta.txq[IEEE80211_NUM_TIDS];
  }
 } else if (sta) {
  u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;

  if (!sta->uploaded)
   return NULL;

  txq = sta->sta.txq[tid];
 } else {
  txq = vif->txq;
 }

 if (!txq)
  return NULL;

 return to_txq_info(txq);
}

static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb)
{
 struct sk_buff *next;
 codel_time_t now = codel_get_time();

 skb_list_walk_safe(skb, skb, next)
  IEEE80211_SKB_CB(skb)->control.enqueue_time = now;
}

static u32 codel_skb_len_func(const struct sk_buff *skb)
{
 return skb->len;
}

static codel_time_t codel_skb_time_func(const struct sk_buff *skb)
{
 const struct ieee80211_tx_info *info;

 info = (const struct ieee80211_tx_info *)skb->cb;
 return info->control.enqueue_time;
}

static struct sk_buff *codel_dequeue_func(struct codel_vars *cvars,
       void *ctx)
{
 struct ieee80211_local *local;
 struct txq_info *txqi;
 struct fq *fq;
 struct fq_flow *flow;

 txqi = ctx;
 local = vif_to_sdata(txqi->txq.vif)->local;
 fq = &local->fq;

 if (cvars == &txqi->def_cvars)
  flow = &txqi->tin.default_flow;
 else
  flow = &fq->flows[cvars - local->cvars];

 return fq_flow_dequeue(fq, flow);
}

static void codel_drop_func(struct sk_buff *skb,
       void *ctx)
{
 struct ieee80211_local *local;
 struct ieee80211_hw *hw;
 struct txq_info *txqi;

 txqi = ctx;
 local = vif_to_sdata(txqi->txq.vif)->local;
 hw = &local->hw;

 ieee80211_free_txskb(hw, skb);
}

static struct sk_buff *fq_tin_dequeue_func(struct fq *fq,
        struct fq_tin *tin,
        struct fq_flow *flow)
{
 struct ieee80211_local *local;
 struct txq_info *txqi;
 struct codel_vars *cvars;
 struct codel_params *cparams;
 struct codel_stats *cstats;

 local = container_of(fq, struct ieee80211_local, fq);
 txqi = container_of(tin, struct txq_info, tin);
 cparams = &local->cparams;
 cstats = &txqi->cstats;

 if (flow == &tin->default_flow)
  cvars = &txqi->def_cvars;
 else
  cvars = &local->cvars[flow - fq->flows];

 return codel_dequeue(txqi,
        &flow->backlog,
        cparams,
        cvars,
        cstats,
        codel_skb_len_func,
        codel_skb_time_func,
        codel_drop_func,
        codel_dequeue_func);
}

static void fq_skb_free_func(struct fq *fq,
        struct fq_tin *tin,
        struct fq_flow *flow,
        struct sk_buff *skb)
{
 struct ieee80211_local *local;

 local = container_of(fq, struct ieee80211_local, fq);
 ieee80211_free_txskb(&local->hw, skb);
}

static void ieee80211_txq_enqueue(struct ieee80211_local *local,
      struct txq_info *txqi,
      struct sk_buff *skb)
{
 struct fq *fq = &local->fq;
 struct fq_tin *tin = &txqi->tin;
 u32 flow_idx;

 ieee80211_set_skb_enqueue_time(skb);

 spin_lock_bh(&fq->lock);
 /*
 * For management frames, don't really apply codel etc.,
 * we don't want to apply any shaping or anything we just
 * want to simplify the driver API by having them on the
 * txqi.
 */

 if (unlikely(txqi->txq.tid == IEEE80211_NUM_TIDS)) {
  IEEE80211_SKB_CB(skb)->control.flags |=
   IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
  __skb_queue_tail(&txqi->frags, skb);
 } else {
  flow_idx = fq_flow_idx(fq, skb);
  fq_tin_enqueue(fq, tin, flow_idx, skb,
          fq_skb_free_func);
 }
 spin_unlock_bh(&fq->lock);
}

static bool fq_vlan_filter_func(struct fq *fq, struct fq_tin *tin,
    struct fq_flow *flow, struct sk_buff *skb,
    void *data)
{
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);

 return info->control.vif == data;
}

void ieee80211_txq_remove_vlan(struct ieee80211_local *local,
          struct ieee80211_sub_if_data *sdata)
{
 struct fq *fq = &local->fq;
 struct txq_info *txqi;
 struct fq_tin *tin;
 struct ieee80211_sub_if_data *ap;

 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP_VLAN))
  return;

 ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);

 if (!ap->vif.txq)
  return;

 txqi = to_txq_info(ap->vif.txq);
 tin = &txqi->tin;

 spin_lock_bh(&fq->lock);
 fq_tin_filter(fq, tin, fq_vlan_filter_func, &sdata->vif,
        fq_skb_free_func);
 spin_unlock_bh(&fq->lock);
}

void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
   struct sta_info *sta,
   struct txq_info *txqi, int tid)
{
 fq_tin_init(&txqi->tin);
 codel_vars_init(&txqi->def_cvars);
 codel_stats_init(&txqi->cstats);
 __skb_queue_head_init(&txqi->frags);
 INIT_LIST_HEAD(&txqi->schedule_order);

 txqi->txq.vif = &sdata->vif;

 if (!sta) {
  sdata->vif.txq = &txqi->txq;
  txqi->txq.tid = 0;
  txqi->txq.ac = IEEE80211_AC_BE;

  return;
 }

 if (tid == IEEE80211_NUM_TIDS) {
  if (sdata->vif.type == NL80211_IFTYPE_STATION) {
   /* Drivers need to opt in to the management MPDU TXQ */
   if (!ieee80211_hw_check(&sdata->local->hw,
      STA_MMPDU_TXQ))
    return;
  } else if (!ieee80211_hw_check(&sdata->local->hw,
            BUFF_MMPDU_TXQ)) {
   /* Drivers need to opt in to the bufferable MMPDU TXQ */
   return;
  }
  txqi->txq.ac = IEEE80211_AC_VO;
 } else {
  txqi->txq.ac = ieee80211_ac_from_tid(tid);
 }

 txqi->txq.sta = &sta->sta;
 txqi->txq.tid = tid;
 sta->sta.txq[tid] = &txqi->txq;
}

void ieee80211_txq_purge(struct ieee80211_local *local,
    struct txq_info *txqi)
{
 struct fq *fq = &local->fq;
 struct fq_tin *tin = &txqi->tin;

 spin_lock_bh(&fq->lock);
 fq_tin_reset(fq, tin, fq_skb_free_func);
 ieee80211_purge_tx_queue(&local->hw, &txqi->frags);
 spin_unlock_bh(&fq->lock);

 spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]);
 list_del_init(&txqi->schedule_order);
 spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]);
}

void ieee80211_txq_set_params(struct ieee80211_local *local, int radio_idx)
{
 if (local->hw.wiphy->txq_limit)
  local->fq.limit = local->hw.wiphy->txq_limit;
 else
  local->hw.wiphy->txq_limit = local->fq.limit;

 if (local->hw.wiphy->txq_memory_limit)
  local->fq.memory_limit = local->hw.wiphy->txq_memory_limit;
 else
  local->hw.wiphy->txq_memory_limit = local->fq.memory_limit;

 if (local->hw.wiphy->txq_quantum)
  local->fq.quantum = local->hw.wiphy->txq_quantum;
 else
  local->hw.wiphy->txq_quantum = local->fq.quantum;
}

int ieee80211_txq_setup_flows(struct ieee80211_local *local)
{
 struct fq *fq = &local->fq;
 int ret;
 int i;
 bool supp_vht = false;
 enum nl80211_band band;

 ret = fq_init(fq, 4096);
 if (ret)
  return ret;

 /*
 * If the hardware doesn't support VHT, it is safe to limit the maximum
 * queue size. 4 Mbytes is 64 max-size aggregates in 802.11n.
 */

 for (band = 0; band < NUM_NL80211_BANDS; band++) {
  struct ieee80211_supported_band *sband;

  sband = local->hw.wiphy->bands[band];
  if (!sband)
   continue;

  supp_vht = supp_vht || sband->vht_cap.vht_supported;
 }

 if (!supp_vht)
  fq->memory_limit = 4 << 20; /* 4 Mbytes */

 codel_params_init(&local->cparams);
 local->cparams.interval = MS2TIME(100);
 local->cparams.target = MS2TIME(20);
 local->cparams.ecn = true;

 local->cvars = kvcalloc(fq->flows_cnt, sizeof(local->cvars[0]),
    GFP_KERNEL);
 if (!local->cvars) {
  spin_lock_bh(&fq->lock);
  fq_reset(fq, fq_skb_free_func);
  spin_unlock_bh(&fq->lock);
  return -ENOMEM;
 }

 for (i = 0; i < fq->flows_cnt; i++)
  codel_vars_init(&local->cvars[i]);

 ieee80211_txq_set_params(local, -1);

 return 0;
}

void ieee80211_txq_teardown_flows(struct ieee80211_local *local)
{
 struct fq *fq = &local->fq;

 kvfree(local->cvars);
 local->cvars = NULL;

 spin_lock_bh(&fq->lock);
 fq_reset(fq, fq_skb_free_func);
 spin_unlock_bh(&fq->lock);
}

static bool ieee80211_queue_skb(struct ieee80211_local *local,
    struct ieee80211_sub_if_data *sdata,
    struct sta_info *sta,
    struct sk_buff *skb)
{
 struct ieee80211_vif *vif;
 struct txq_info *txqi;

 if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
  return false;

 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
  sdata = container_of(sdata->bss,
         struct ieee80211_sub_if_data, u.ap);

 vif = &sdata->vif;
 txqi = ieee80211_get_txq(local, vif, sta, skb);

 if (!txqi)
  return false;

 ieee80211_txq_enqueue(local, txqi, skb);

 schedule_and_wake_txq(local, txqi);

 return true;
}

static bool ieee80211_tx_frags(struct ieee80211_local *local,
          struct ieee80211_vif *vif,
          struct sta_info *sta,
          struct sk_buff_head *skbs,
          bool txpending)
{
 struct ieee80211_tx_control control = {};
 struct sk_buff *skb, *tmp;
 unsigned long flags;

 skb_queue_walk_safe(skbs, skb, tmp) {
  struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
  int q = info->hw_queue;

#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
  if (WARN_ON_ONCE(q >= local->hw.queues)) {
   __skb_unlink(skb, skbs);
   ieee80211_free_txskb(&local->hw, skb);
   continue;
  }
#endif

  spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
  if (local->queue_stop_reasons[q] ||
      (!txpending && !skb_queue_empty(&local->pending[q]))) {
   if (unlikely(info->flags &
         IEEE80211_TX_INTFL_OFFCHAN_TX_OK)) {
    if (local->queue_stop_reasons[q] &
        ~BIT(IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL)) {
     /*
 * Drop off-channel frames if queues
 * are stopped for any reason other
 * than off-channel operation. Never
 * queue them.
 */

     spin_unlock_irqrestore(
      &local->queue_stop_reason_lock,
      flags);
     ieee80211_purge_tx_queue(&local->hw,
         skbs);
     return true;
    }
   } else {

    /*
 * Since queue is stopped, queue up frames for
 * later transmission from the tx-pending
 * tasklet when the queue is woken again.
 */

    if (txpending)
     skb_queue_splice_init(skbs,
             &local->pending[q]);
    else
     skb_queue_splice_tail_init(skbs,
           &local->pending[q]);

    spin_unlock_irqrestore(&local->queue_stop_reason_lock,
             flags);
    return false;
   }
  }
  spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);

  info->control.vif = vif;
  control.sta = sta ? &sta->sta : NULL;

  __skb_unlink(skb, skbs);
  drv_tx(local, &control, skb);
 }

 return true;
}

/*
 * Returns false if the frame couldn't be transmitted but was queued instead.
 */

static bool __ieee80211_tx(struct ieee80211_local *local,
      struct sk_buff_head *skbs, struct sta_info *sta,
      bool txpending)
{
 struct ieee80211_tx_info *info;
 struct ieee80211_sub_if_data *sdata;
 struct ieee80211_vif *vif;
 struct sk_buff *skb;
 bool result;

 if (WARN_ON(skb_queue_empty(skbs)))
  return true;

 skb = skb_peek(skbs);
 info = IEEE80211_SKB_CB(skb);
 sdata = vif_to_sdata(info->control.vif);
 if (sta && !sta->uploaded)
  sta = NULL;

 switch (sdata->vif.type) {
 case NL80211_IFTYPE_MONITOR:
  if ((sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) ||
      ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
   vif = &sdata->vif;
   break;
  }
  sdata = rcu_dereference(local->monitor_sdata);
  if (sdata && ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF)) {
   vif = &sdata->vif;
   info->hw_queue =
    vif->hw_queue[skb_get_queue_mapping(skb)];
  } else if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL)) {
   ieee80211_purge_tx_queue(&local->hw, skbs);
   return true;
  } else
   vif = NULL;
  break;
 case NL80211_IFTYPE_AP_VLAN:
  sdata = container_of(sdata->bss,
         struct ieee80211_sub_if_data, u.ap);
  fallthrough;
 default:
  vif = &sdata->vif;
  break;
 }

 result = ieee80211_tx_frags(local, vif, sta, skbs, txpending);

 WARN_ON_ONCE(!skb_queue_empty(skbs));

 return result;
}

/*
 * Invoke TX handlers, return 0 on success and non-zero if the
 * frame was dropped or queued.
 *
 * The handlers are split into an early and late part. The latter is everything
 * that can be sensitive to reordering, and will be deferred to after packets
 * are dequeued from the intermediate queues (when they are enabled).
 */

static int invoke_tx_handlers_early(struct ieee80211_tx_data *tx)
{
 ieee80211_tx_result res = TX_DROP;

#define CALL_TXH(txh) \
 do {    \
  res = txh(tx);  \
  if (res != TX_CONTINUE) \
   goto txh_done; \
 } while (0)

 CALL_TXH(ieee80211_tx_h_dynamic_ps);
 CALL_TXH(ieee80211_tx_h_check_assoc);
 CALL_TXH(ieee80211_tx_h_ps_buf);
 CALL_TXH(ieee80211_tx_h_check_control_port_protocol);
 CALL_TXH(ieee80211_tx_h_select_key);

 txh_done:
 if (unlikely(res == TX_DROP)) {
  I802_DEBUG_INC(tx->local->tx_handlers_drop);
  if (tx->skb)
   ieee80211_free_txskb(&tx->local->hw, tx->skb);
  else
   ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs);
  return -1;
 } else if (unlikely(res == TX_QUEUED)) {
  I802_DEBUG_INC(tx->local->tx_handlers_queued);
  return -1;
 }

 return 0;
}

/*
 * Late handlers can be called while the sta lock is held. Handlers that can
 * cause packets to be generated will cause deadlock!
 */

static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx)
{
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
 ieee80211_tx_result res = TX_CONTINUE;

 if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
  CALL_TXH(ieee80211_tx_h_rate_ctrl);

 if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) {
  __skb_queue_tail(&tx->skbs, tx->skb);
  tx->skb = NULL;
  goto txh_done;
 }

 CALL_TXH(ieee80211_tx_h_michael_mic_add);
 CALL_TXH(ieee80211_tx_h_sequence);
 CALL_TXH(ieee80211_tx_h_fragment);
 /* handlers after fragment must be aware of tx info fragmentation! */
 CALL_TXH(ieee80211_tx_h_stats);
 CALL_TXH(ieee80211_tx_h_encrypt);
 if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
  CALL_TXH(ieee80211_tx_h_calculate_duration);
#undef CALL_TXH

 txh_done:
 if (unlikely(res == TX_DROP)) {
  I802_DEBUG_INC(tx->local->tx_handlers_drop);
  if (tx->skb)
   ieee80211_free_txskb(&tx->local->hw, tx->skb);
  else
   ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs);
  return -1;
 } else if (unlikely(res == TX_QUEUED)) {
  I802_DEBUG_INC(tx->local->tx_handlers_queued);
  return -1;
 }

 return 0;
}

static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
{
 int r = invoke_tx_handlers_early(tx);

 if (r)
  return r;
 return invoke_tx_handlers_late(tx);
}

bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
         struct ieee80211_vif *vif, struct sk_buff *skb,
         int band, struct ieee80211_sta **sta)
{
 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 struct ieee80211_tx_data tx;
 struct sk_buff *skb2;

 if (ieee80211_tx_prepare(sdata, &tx, NULL, skb) == TX_DROP)
  return false;

 info->band = band;
 info->control.vif = vif;
 info->hw_queue = vif->hw_queue[skb_get_queue_mapping(skb)];

 if (invoke_tx_handlers(&tx))
  return false;

 if (sta) {
  if (tx.sta)
   *sta = &tx.sta->sta;
  else
   *sta = NULL;
 }

 /* this function isn't suitable for fragmented data frames */
 skb2 = __skb_dequeue(&tx.skbs);
 if (WARN_ON(skb2 != skb || !skb_queue_empty(&tx.skbs))) {
  ieee80211_free_txskb(hw, skb2);
  ieee80211_purge_tx_queue(hw, &tx.skbs);
  return false;
 }

 return true;
}
EXPORT_SYMBOL(ieee80211_tx_prepare_skb);

/*
 * Returns false if the frame couldn't be transmitted but was queued instead.
 */

static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
    struct sta_info *sta, struct sk_buff *skb,
    bool txpending)
{
 struct ieee80211_local *local = sdata->local;
 struct ieee80211_tx_data tx;
 ieee80211_tx_result res_prepare;
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 bool result = true;

 if (unlikely(skb->len < 10)) {
  dev_kfree_skb(skb);
  return true;
 }

 /* initialises tx */
 res_prepare = ieee80211_tx_prepare(sdata, &tx, sta, skb);

 if (unlikely(res_prepare == TX_DROP)) {
  ieee80211_free_txskb(&local->hw, skb);
  return true;
 } else if (unlikely(res_prepare == TX_QUEUED)) {
  return true;
 }

 /* set up hw_queue value early */
 if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) ||
     !ieee80211_hw_check(&local->hw, QUEUE_CONTROL))
  info->hw_queue =
   sdata->vif.hw_queue[skb_get_queue_mapping(skb)];

 if (invoke_tx_handlers_early(&tx))
  return true;

 if (ieee80211_queue_skb(local, sdata, tx.sta, tx.skb))
  return true;

 if (!invoke_tx_handlers_late(&tx))
  result = __ieee80211_tx(local, &tx.skbs, tx.sta, txpending);

 return result;
}

/* device xmit handlers */

enum ieee80211_encrypt {
 ENCRYPT_NO,
 ENCRYPT_MGMT,
 ENCRYPT_DATA,
};

static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
    struct sk_buff *skb,
    int head_need,
    enum ieee80211_encrypt encrypt)
{
 struct ieee80211_local *local = sdata->local;
 bool enc_tailroom;
 int tail_need = 0;

 enc_tailroom = encrypt == ENCRYPT_MGMT ||
         (encrypt == ENCRYPT_DATA &&
   sdata->crypto_tx_tailroom_needed_cnt);

 if (enc_tailroom) {
  tail_need = IEEE80211_ENCRYPT_TAILROOM;
  tail_need -= skb_tailroom(skb);
  tail_need = max_t(int, tail_need, 0);
 }

 if (skb_cloned(skb) &&
     (!ieee80211_hw_check(&local->hw, SUPPORTS_CLONED_SKBS) ||
      !skb_clone_writable(skb, ETH_HLEN) || enc_tailroom))
  I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
 else if (head_need || tail_need)
  I802_DEBUG_INC(local->tx_expand_skb_head);
 else
  return 0;

 if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) {
  wiphy_debug(local->hw.wiphy,
       "failed to reallocate TX buffer\n");
  return -ENOMEM;
 }

 return 0;
}

void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
      struct sta_info *sta, struct sk_buff *skb)
{
 struct ieee80211_local *local = sdata->local;
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 int headroom;
 enum ieee80211_encrypt encrypt;

 if (info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)
  encrypt = ENCRYPT_NO;
 else if (ieee80211_is_mgmt(hdr->frame_control))
  encrypt = ENCRYPT_MGMT;
 else
  encrypt = ENCRYPT_DATA;

 headroom = local->tx_headroom;
 if (encrypt != ENCRYPT_NO)
  headroom += IEEE80211_ENCRYPT_HEADROOM;
 headroom -= skb_headroom(skb);
 headroom = max_t(int, 0, headroom);

 if (ieee80211_skb_resize(sdata, skb, headroom, encrypt)) {
  ieee80211_free_txskb(&local->hw, skb);
  return;
 }

 /* reload after potential resize */
 hdr = (struct ieee80211_hdr *) skb->data;
 info->control.vif = &sdata->vif;

 if (ieee80211_vif_is_mesh(&sdata->vif)) {
  if (ieee80211_is_data(hdr->frame_control) &&
      is_unicast_ether_addr(hdr->addr1)) {
   if (mesh_nexthop_resolve(sdata, skb))
    return/* skb queued: don't free */
  } else {
   ieee80211_mps_set_frame_flags(sdata, NULL, hdr);
  }
 }

 ieee80211_set_qos_hdr(sdata, skb);
 ieee80211_tx(sdata, sta, skb, false);
}

static bool ieee80211_validate_radiotap_len(struct sk_buff *skb)
{
 struct ieee80211_radiotap_header *rthdr =
  (struct ieee80211_radiotap_header *)skb->data;

 /* check for not even having the fixed radiotap header part */
 if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
  return false/* too short to be possibly valid */

 /* is it a header version we can trust to find length from? */
 if (unlikely(rthdr->it_version))
  return false/* only version 0 is supported */

 /* does the skb contain enough to deliver on the alleged length? */
 if (unlikely(skb->len < ieee80211_get_radiotap_len(skb->data)))
  return false/* skb too short for claimed rt header extent */

 return true;
}

bool ieee80211_parse_tx_radiotap(struct sk_buff *skb,
     struct net_device *dev)
{
 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 struct ieee80211_radiotap_iterator iterator;
 struct ieee80211_radiotap_header *rthdr =
  (struct ieee80211_radiotap_header *) skb->data;
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
         NULL);
 u16 txflags;
 u16 rate = 0;
 bool rate_found = false;
 u8 rate_retries = 0;
 u16 rate_flags = 0;
 u8 mcs_known, mcs_flags, mcs_bw;
 u16 vht_known;
 u8 vht_mcs = 0, vht_nss = 0;
 int i;

 if (!ieee80211_validate_radiotap_len(skb))
  return false;

 info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
         IEEE80211_TX_CTL_DONTFRAG;

 /*
 * for every radiotap entry that is present
 * (ieee80211_radiotap_iterator_next returns -ENOENT when no more
 * entries present, or -EINVAL on error)
 */


 while (!ret) {
  ret = ieee80211_radiotap_iterator_next(&iterator);

  if (ret)
   continue;

  /* see if this argument is something we can use */
  switch (iterator.this_arg_index) {
  /*
 * You must take care when dereferencing iterator.this_arg
 * for multibyte types... the pointer is not aligned.  Use
 * get_unaligned((type *)iterator.this_arg) to dereference
 * iterator.this_arg for type "type" safely on all arches.
*/

  case IEEE80211_RADIOTAP_FLAGS:
   if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
    /*
 * this indicates that the skb we have been
 * handed has the 32-bit FCS CRC at the end...
 * we should react to that by snipping it off
 * because it will be recomputed and added
 * on transmission
 */

    if (skb->len < (iterator._max_length + FCS_LEN))
     return false;

    skb_trim(skb, skb->len - FCS_LEN);
   }
   if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
    info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT;
   if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
    info->flags &= ~IEEE80211_TX_CTL_DONTFRAG;
   break;

  case IEEE80211_RADIOTAP_TX_FLAGS:
   txflags = get_unaligned_le16(iterator.this_arg);
   if (txflags & IEEE80211_RADIOTAP_F_TX_NOACK)
    info->flags |= IEEE80211_TX_CTL_NO_ACK;
   if (txflags & IEEE80211_RADIOTAP_F_TX_NOSEQNO)
    info->control.flags |= IEEE80211_TX_CTRL_NO_SEQNO;
   if (txflags & IEEE80211_RADIOTAP_F_TX_ORDER)
    info->control.flags |=
     IEEE80211_TX_CTRL_DONT_REORDER;
   break;

  case IEEE80211_RADIOTAP_RATE:
   rate = *iterator.this_arg;
   rate_flags = 0;
   rate_found = true;
   break;

  case IEEE80211_RADIOTAP_ANTENNA:
   /* this can appear multiple times, keep a bitmap */
   info->control.antennas |= BIT(*iterator.this_arg);
   break;

  case IEEE80211_RADIOTAP_DATA_RETRIES:
   rate_retries = *iterator.this_arg;
   break;

  case IEEE80211_RADIOTAP_MCS:
   mcs_known = iterator.this_arg[0];
   mcs_flags = iterator.this_arg[1];
   if (!(mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_MCS))
    break;

   rate_found = true;
   rate = iterator.this_arg[2];
   rate_flags = IEEE80211_TX_RC_MCS;

   if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_GI &&
       mcs_flags & IEEE80211_RADIOTAP_MCS_SGI)
    rate_flags |= IEEE80211_TX_RC_SHORT_GI;

   mcs_bw = mcs_flags & IEEE80211_RADIOTAP_MCS_BW_MASK;
   if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_BW &&
       mcs_bw == IEEE80211_RADIOTAP_MCS_BW_40)
    rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;

   if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_FEC &&
       mcs_flags & IEEE80211_RADIOTAP_MCS_FEC_LDPC)
    info->flags |= IEEE80211_TX_CTL_LDPC;

   if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_STBC) {
    u8 stbc = u8_get_bits(mcs_flags,
            IEEE80211_RADIOTAP_MCS_STBC_MASK);

    info->flags |=
     u32_encode_bits(stbc,
       IEEE80211_TX_CTL_STBC);
   }
   break;

  case IEEE80211_RADIOTAP_VHT:
   vht_known = get_unaligned_le16(iterator.this_arg);
   rate_found = true;

   rate_flags = IEEE80211_TX_RC_VHT_MCS;
   if ((vht_known & IEEE80211_RADIOTAP_VHT_KNOWN_GI) &&
       (iterator.this_arg[2] &
        IEEE80211_RADIOTAP_VHT_FLAG_SGI))
    rate_flags |= IEEE80211_TX_RC_SHORT_GI;
   if (vht_known &
       IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH) {
    if (iterator.this_arg[3] == 1)
     rate_flags |=
      IEEE80211_TX_RC_40_MHZ_WIDTH;
    else if (iterator.this_arg[3] == 4)
     rate_flags |=
      IEEE80211_TX_RC_80_MHZ_WIDTH;
    else if (iterator.this_arg[3] == 11)
     rate_flags |=
      IEEE80211_TX_RC_160_MHZ_WIDTH;
   }

   vht_mcs = iterator.this_arg[4] >> 4;
   if (vht_mcs > 11)
    vht_mcs = 0;
   vht_nss = iterator.this_arg[4] & 0xF;
   if (!vht_nss || vht_nss > 8)
    vht_nss = 1;
   break;

  /*
 * Please update the file
 * Documentation/networking/mac80211-injection.rst
 * when parsing new fields here.
 */


  default:
   break;
  }
 }

 if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
  return false;

 if (rate_found) {
  struct ieee80211_supported_band *sband =
   local->hw.wiphy->bands[info->band];

  info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT;

  for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
   info->control.rates[i].idx = -1;
   info->control.rates[i].flags = 0;
   info->control.rates[i].count = 0;
  }

  if (rate_flags & IEEE80211_TX_RC_MCS) {
   /* reset antennas if not enough */
   if (IEEE80211_HT_MCS_CHAINS(rate) >
     hweight8(info->control.antennas))
    info->control.antennas = 0;

   info->control.rates[0].idx = rate;
  } else if (rate_flags & IEEE80211_TX_RC_VHT_MCS) {
   /* reset antennas if not enough */
   if (vht_nss > hweight8(info->control.antennas))
    info->control.antennas = 0;

   ieee80211_rate_set_vht(info->control.rates, vht_mcs,
            vht_nss);
  } else if (sband) {
   for (i = 0; i < sband->n_bitrates; i++) {
    if (rate * 5 != sband->bitrates[i].bitrate)
     continue;

    info->control.rates[0].idx = i;
    break;
   }
  }

  if (info->control.rates[0].idx < 0)
   info->control.flags &= ~IEEE80211_TX_CTRL_RATE_INJECT;

  info->control.rates[0].flags = rate_flags;
  info->control.rates[0].count = min_t(u8, rate_retries + 1,
           local->hw.max_rate_tries);
 }

 return true;
}

netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
      struct net_device *dev)
{
 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 struct ieee80211_chanctx_conf *chanctx_conf;
 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 struct ieee80211_hdr *hdr;
 struct ieee80211_sub_if_data *tmp_sdata, *sdata;
 struct cfg80211_chan_def *chandef;
 u16 len_rthdr;
 int hdrlen;

 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 if (unlikely(!ieee80211_sdata_running(sdata)))
  goto fail;

 memset(info, 0, sizeof(*info));
 info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
        IEEE80211_TX_CTL_INJECTED;

 /* Sanity-check the length of the radiotap header */
 if (!ieee80211_validate_radiotap_len(skb))
  goto fail;

 /* we now know there is a radiotap header with a length we can use */
 len_rthdr = ieee80211_get_radiotap_len(skb->data);

 /*
 * fix up the pointers accounting for the radiotap
 * header still being in there.  We are being given
 * a precooked IEEE80211 header so no need for
 * normal processing
 */

 skb_set_mac_header(skb, len_rthdr);
 /*
 * these are just fixed to the end of the rt area since we
 * don't have any better information and at this point, nobody cares
 */

 skb_set_network_header(skb, len_rthdr);
 skb_set_transport_header(skb, len_rthdr);

 if (skb->len < len_rthdr + 2)
  goto fail;

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=97 H=95 G=95

¤ Dauer der Verarbeitung: 0.20 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.