Brief explanation of cfg80211/mac80211 data structure
=====================================================

Data structures:
- @wiphy (&struct wiphy): cfg80211 radio interface
- @hw (&struct ieee80211_hw): mac80211 radio interface
- @wdev (&struct wireless_dev): internal virtual interface
- @vif (&struct ieee80211_vif): mac80211 virtual interface
- @sta (&struct ieee80211_sta): mac80211 peer station
- @txq (&struct ieee80211_txq): mac80211 per-station per-tid software tx queue
- @skb (struct sk_buff *skb): ieee80211 frame

Relationships (from, to):
- @wiphy -> @hw:    wiphy_to_ieee80211_hw(@wiphy)
- @wdev  -> @wiphy: @wdev->wiphy
- @wdev  -> @vif:   wdev_to_ieee80211_vif(@wdev)
- @hw    -> @wiphy: @hw->wiphy
- @vif   -> @hw:    ieee80211_vif_to_hw(@vif) (in util.h)
- @vif   -> @wiphy: ieee80211_vif_to_wiphy(@vif) (in util.h)
- @vif   -> @wdev:  ieee80211_vif_to_wdev(@vif)
- @txq   -> @vif:   @txq->vif
- @txq   -> @sta:   @sta->sta
- @skb   -> @vif:   IEEE80211_SKB_CB(@skb)->control.vif

PPDU information:
- @ti = IEEE80211_SKB_CB(@skb) (&struct ieee80211_tx_info)
- @ti->flags: IEEE80211_TX_xxx
- @ti->control.flags: IEEE80211_TX_CTRL_xxx
- @ti->control.rate[i].flags: IEEE80211_TX_RC_xxx
: provided by rate controller and mac80211 tx path

Transmitting STA's capabilities:
- @wiphy->bands[ti->band].ht_cap: HT capabilities
- @wiphy->bands[ti->band].vht_cap : VHT capabilities
- @wiphy->bands[ti->band].he_cap: HE capabilities

Receiving STA's capability:
- @sta->ht_cap         kernel 5-19 -@sta->deflink.ht_cap
- @sta->vht_cap        kernel 5-19 -@sta->deflink.vht_cap
- @sta->he_cap         kernel 5-19 -@sta->deflink.he_cap

Receiving STA's operating parameter:
- @sta->deflink.bandwidth
- @sta->deflink.rx_nss
- @sta->smps_mode
- @sta->max_amsdu_len: max MPDU len (don't be deceived by its name)

Peer information necessary for TXOP scheduling:
- ppdu format (DSSS, DSSS/CCK, OFDM, HT, VHT, HE)
- max. mpdu length: ppdu format & sta->max_amsdu_len
- max. ampdu length (for A-MPDU)
- max. subframe (for A-MPDU)
- BA windows size
- minimum mpdu spacing (for A-MPDU)
- mcs/rate
- channel bandwidth
- dynamic bandwidth
- preamble/guard interval
- BCC/LDPC
- nss

ieee80211_subif_start_xmit() call chain
=======================================
- MSDUs are transmitted following this call chain.
- This function is called from the tasklet.

1. ieee80211_subif_start_xmit(skb, dev)
- __ieee80211_subif_start_xmit(skb, dev, 0)

2. __ieee80211_subif_start_xmit(skb, dev, info_flags)
- sdata = IEEE80211_DEV_TO_SUB_IF(dev)
- ieee80211_lookup_ra_sta(sdata, skb, &sta)
  : this is where sta information is obtained.
  : sta can be NULL if
    (1) vif is AP and skb is a multicast frame
    (2) TDLS peer that is not setup.
    (3) unknown peer - is this possible?
- ieee80211_xmit_fast(sdata, sta, pn_offs, key, skb)
  : if sta is valid and sta->fast_tx is true
- OR
- ieee80211_xmit(sdata, sta, skb, 0)

3. ieee80211_xmit(sdata, sta, skb, txdata_flags)
: @sta can be NULL
: Common for both TX call chains
- info = IEEE80211_SKB_CB(skb)
- info->control.vif = &sdata->vif
  : This is where @info->control.vif is first set
- ieee80211_set_qos_hdr(sdata, skb)
- ieee80211_tx(sdata, sta, skb, false, txdata_flags)

4. ieee80211_tx(sdata, sta, skb, txpending, txdata_flags)
- info = IEEE80211_SKB_CB(skb)
- ieee80211_tx_prepare(sdata, &tx, sta, skb)
- info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)] (no off-channel tx)
- invoke_tx_handlers_early(&tx)
- ieee80211_queue_skb(local, sdata, tx.sta, tx.skb)
  : fall-through if return value is false
- invoke_tx_handlers_late(&tx)
- __ieee80211_tx(local, &tx.skbs, led_len, tx.sta, txpending)
  - ieee80211_tx_frags(local, vif, pubsta, skbs, txpending

5. invoke_tx_handlers_early(tx)
- ieee80211_tx_h_dynamic_ps(tx)
- ieee80211_tx_h_check_assoc(tx)
- ieee80211_tx_h_ps_buf(tx)
- ieee80211_tx_h_check_control_port_control(tx)
- ieee80211_tx_h_select_key(tx)
- ieee80211_tx_h_rate_ctrl(tx) (IEEE80211_HW_HAS_RATE_CONTROL)

6. ieee80211_queue_skb(local, sdata, sta, skb)
- vif = &sdata->vif
- txqi = ieee80211_get_txq(local, vif, sta, skb)
- ieee80211_txq_enqueue(local, txqi, skb)
- drv_wake_tx_queue(local, txqi);

6.1. ieee80211_get_txq(local, vif, sta, skb)
```
	if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
		if ((!ieee80211_is_mgmt(hdr->frame_control) ||
		     ieee80211_is_bufferable_mmpdu(hdr->frame_control) ||
		     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 if (vif) {
		txq = vif->txq;
	}
```
- sta->sta.txq[IEEE80211_NUM_TIDS(=16)]
  - (control or bufferable_mmpdu or vif is station) && sta && sta->uploaded
  - That is, once STA vif is associated to an AP, all individually
    addressed control and management frames go to this queue.
  - If vif is an AP, only individually addressed control and
    bufferable management frames go to this queue
- sta->sta.txq[tid]
  - data && sta && sta->uploaded
  - individually addressed data
- vif->txq
  - vif is not NULL
  - group addressed data frames go to this queue
- NULL
  - otherwise
  - Group addressed control and management frames (beacon)
  - NL80211_IFTYPE_STATION: management frame before association (probe
    req, auth, assoc request)
  - NL80211_IFTYPE_AP: non-bufferable mmpdu, and etc.
  -



7. invoke_tx_handlers_late(tx)
- ieee80211_tx_h_michael_mic_add(tx)
- ieee80211_tx_h_sequence(tx)
- ieee80211_tx_h_fragment(tx)
- ieee80211_tx_h_stats(tx)
- ieee80211_tx_h_encrypt(tx)
- ieee80211_tx_h_calculate_duration(tx)
- This function is also called in ieee80211_txq_dequeue() (should be)

8. ieee80211_tx_frags(local, vif, sta, skbs, txpending)
- for each skb in skbs
  info = IEEE80211_SKB_CB(skb)
  ...
  info->control.vif = vif
  control.sta = sta
  drv_tx(local, &control, skb)

9. ieee80211_tx_dequeue(hw, txq)

10.

Questions:
Q: Can control.sta or IEEE80211_SKB_CB(skb)->control.vif be NULL? If so
   in what occasions?
A: control.sta can be NULL (see above). vif is not likely to be NULL

ieee80211_tx_skb_tid() call chains
==================================
This function is called by mac80211 stack to send frames directly to a vif.

1. ieee80211_tx_skb(sdata, skb)
- ieee80211_tx_skb_tid(sdata, skb, 7)

2. ieee80211_tx_skb_tid(sdata, skb, tid)
- chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf)
- __ieee80211_tx_skb_tid_band(sdata, skb, tid, chanctx_conf->def.chan->band, 0)

3. __ieee80211_tx_skb_tid_band(sdata, skb, tid, band, txdata_flags)
- skb_set_queue_mapping(skb, ac) (ac = IEEE80211_AC_VO)
- skb->priority = tid (= 7)
- IEEE80211_SKB_CB(skb)->band = band
- ieee80211_xmit(sdata, NULL, skb, txdata_flags)
  : NB: @sta is set to NULL

Callers:
  - ieee80211_send_addba_resp()
  - ieee80211_send_addba_request()
  - ieee80211_send_delba()
  - ieee80211_send_smps_action()
  - ieee80211_rx_mgmt_probe_req()
  - ieee80211_mesh_rx_probe_req()
  - mesh_fwd_csa_frame()
  - mesh_path_sel_frame_tx()
  - mesh_plink_frame_tx()
  - mps_qos_null_tx()
  - mpsp_trigger_send()
  - ieee80211_send_assoc()
  - ieee80211_send_pspoll()
  - ieee80211_send_nullfunc()
  - ieee80211_send_4addr_nullfunc()
  - ieee80211_mlme_send_probe_req()
  - ieee80211_mgmt_tx() (offchannel.c, from user space)
  - ieee80211_process_sa_query_req()
  - ieee80211_send_refuse_meseasurement_request() (spectmgmt.c)
  - ieee80211_send_auth()
  - ieee80211_send_deauth_disassoc()
  - ieee80211_send_action_csa()
  - ieee80211_handle_roc_started()
  - ieee80211_send_scan_probe_req()

Note:
 - The skb's sent via ieee80211_tx_skb() reach ieee80211_get_txq() with @sta being
   NULL. They are expected to be enqueued to @vif->txq if skb is
   bufferable management frame.

A call chain leading to drv_tx() during software scan
=====================================================
ieee80211_scan_state_send_probe+0xd5/0x190 [mac80211]
ieee80211_send_scan_probe_req
__ieee80211_tx_skb_tid_band+0x5c/0x70 [mac80211]
ieee80211_xmit+0xbf/0x100 [mac80211]
ieee80211_tx+0x109/0x140 [mac80211]
__ieee80211_tx+0x72/0x120 [mac80211]
ieee80211_tx_frags+0x150/0x230 [mac80211]
drv_tx()

The reason this call did not lead to enqueue() is that ieee80211_get_txq()
returned NULL.


queue mapping (skb --> txq --> hwq)
===================================
skb classification (skb->priority (tid), skb->queue_mapping (ac)):
- ieee80211_netdev_select_queue(dev, skb, sk_dev, fallback)
  : ndo_select_queue of netdev
  - ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb)
    - skb->priority = cfg80211_classify8021d(skb, qos_map or NULL)
    - ieee80211_downgrade_queue(sdata, sta, skb)
  : returns IEEE80211_ACS_{BE,BK,VI,VO}
  : skb->queue_mapping is set to this return value.

IEEE80211_SKB_CB(skb)->hw_queue:
- ieee80211_mgmt_tx(): hw->offchannel_tx_hw_queue
- ieee80211_tx_h_multicast_ps_buf(): vif->cab_queue (AP only)
- ieee80211_tx():
  ieee80211_tx_prepare_skb():
  _ieee80211_tx():
  ieee80211_xmit_fast_finish():
  ieee80211_tx_dequeue(): vif->hw_queue[skb_get_queue_mapping(skb)]

skb --> txq (ieee80211_get_txq())
(1) txq = sta->txq[IEEE80211_NUM_TIDS]
    : bufferable MMPDU (HW_BUFF_MMPDU_TXQ or HW_STA_MMPDU_TXQ)
    : Action, Disassociation, Deauthentication (11.2.2)
    : txq->ac = IEEE80211_AC_VO
(2) txq = sta->txq[tid (= skb->priority & IEEE80211_QOS_CTL_TID_MASK)]
    : (skb != NULL)
(3) txq = vif->txq (!sta && vif)
    : tid = 0, ac = IEEE80211_AC_BE (skb->priority = 7,
      skb->queue_mapping=AC_VO?)
    : See ieee80211_tx_skb() above.
(4) NULL
    : tx() is called. Is this ever possible? yes unfortantely.

txq --> hwqueue
(1) hwqueue = txq->vif->hw_queue[txq->ac]
   : Is this all?
   : When to use hw->offchannel_tx_hw_queue or vif->cab_queue?

skb --> hwqueue
- If a skb fails to be enqueued to a software queue (!sta && !vif), it is
  then transmitted via tx() callback via hw queue indicated by the hw_queue
  field of &struct ieee80211_tx_info.


Retry limit
===========
SRC: MSDU or MMPDU short retry count
LRC: MSDU or MMPDU long retry count
SSRC: STA short retry count
SLRC: STA long retry count
QSRC[AC]: QoS short retry count
QLRC[AC]: QoS long retry count
QSDRC[AC}: QoS short drop-eligible retry count
QLDRC[AC]: Qos long drop-eligible retry count



/**
 * DOC: TXVECTOR
 *                                    Non-HT  HT  VHT  HE
 * ---------------------------------------------------------
 * - FORMAT                            o      o   o    o
 * - MCS                               o      o   o    o
 * - FEC_CODING                        -      o   o    o
 * - STBC
 * - NUM_STS                           -      -   o    -
 * - PREAMBLE_TYPE                     o      -   -    -  (DSSS, DSSS/CCK)
 * - GI_TYPE                           o      o   o    o  (OFDM)
 * - CH_BANDWIDTH                     20      o   o    o
 * - AGGREGATION                       -      o   -    -
 * - PARTIAL_AID                       -      -   o    -
 * - GROUP_ID                          -      -   o    -
 * - DYN_BANDWIDTH_IN_NON_HT                  -   -    -
 * - CH_BANDWIDTH_IN_NON_HT                   -   -    -
 * - SCRAMBLER_INITIAL_VALUE           o      o   o    o  (zero value)
 * - BSS_COLOR                                         o

 * ---------------------------------------------------------
 * - L_LENGTH                          o      -   -    -
 * - LENGTH                            -      o   -    -
 * - APEP_LENGTH                       -      -   o    o
 *
 * - TXPWR_LEVEL_INDEX
 * - SPATIAL_REUSE                     -      -   -    o
 * - RU_ALLOCATION
 * - HE_SIG_A2_RESERVED
 * - TXOP_DURATION
 * - MIDAMBLE_PERIODICITY
 * - RU_TONE_SET_INDEX
 * - LDPC_EXTRA_SYMBOL
 * - HE_LTF_TYPE
 * - TOTAL_NUM_STS
 * - NUM_HE_LTF
 * - NOMINAL_PACKET_PADDING
 * - DEFAULT_PE_DURATION
 * - STARTING_STS_NUM
 * - SMOOTHING
 * - DCM
 * - DOPPLER
 * - HE_LTF_MODE
 * - TX_OP_PS_NOT_ALLOWED
 * - TRIGGER_METHOD
 * - UPLINK_FLAG
 * - TRIGGER_RESPONDING
 * - HE_TB_DATA_SYMBOLS
 * - PRE_FEC
 * - FEEDBACK_STATUS
 * - HE_TB_PE_DISAMBIGUIRTY
 */
