mac80211 subsystem (advanced)

Information contained within this part of the book is of interest only for advanced interaction of mac80211 with drivers to exploit more hardware capabilities and improve performance.

LED support

Mac80211 supports various ways of blinking LEDs. Wherever possible, device LEDs should be exposed as LED class devices and hooked up to the appropriate trigger, which will then be triggered appropriately by mac80211.

Error

kernel-doc missing

Hardware crypto acceleration

Error

kernel-doc missing

Error

kernel-doc missing

Powersave support

Error

kernel-doc missing

Beacon filter support

Error

kernel-doc missing

Error

kernel-doc missing

Multiple queues and QoS support

TBD

Error

kernel-doc missing

Access point mode support

TBD

Some parts of the if_conf should be discussed here instead

Insert notes about VLAN interfaces with hw crypto here or in the hw crypto chapter.

support for powersaving clients

Error

kernel-doc missing

Error

kernel-doc missing

Supporting multiple virtual interfaces

TBD

Note: WDS with identical MAC address should almost always be OK

Insert notes about having multiple virtual interfaces with different MAC addresses here, note which configurations are supported by mac80211, add notes about supporting hw crypto with it.

Error

kernel-doc missing

Station handling

TODO

Error

kernel-doc missing

Hardware scan offload

TBD

Error

kernel-doc missing

Aggregation

TX A-MPDU aggregation

Aggregation on the TX side requires setting the hardware flag IEEE80211_HW_AMPDU_AGGREGATION. The driver will then be handed packets with a flag indicating A-MPDU aggregation. The driver or device is responsible for actually aggregating the frames, as well as deciding how many and which to aggregate.

When TX aggregation is started by some subsystem (usually the rate control algorithm would be appropriate) by calling the ieee80211_start_tx_ba_session() function, the driver will be notified via its ampdu_action function, with the IEEE80211_AMPDU_TX_START action.

In response to that, the driver is later required to call the ieee80211_start_tx_ba_cb_irqsafe() function, which will really start the aggregation session after the peer has also responded. If the peer responds negatively, the session will be stopped again right away. Note that it is possible for the aggregation session to be stopped before the driver has indicated that it is done setting it up, in which case it must not indicate the setup completion.

Also note that, since we also need to wait for a response from the peer, the driver is notified of the completion of the handshake by the IEEE80211_AMPDU_TX_OPERATIONAL action to the ampdu_action callback.

Similarly, when the aggregation session is stopped by the peer or something calling ieee80211_stop_tx_ba_session(), the driver’s ampdu_action function will be called with the action IEEE80211_AMPDU_TX_STOP. In this case, the call must not fail, and the driver must later call ieee80211_stop_tx_ba_cb_irqsafe(). Note that the sta can get destroyed before the BA tear down is complete.

RX A-MPDU aggregation

Aggregation on the RX side requires only implementing the ampdu_action callback that is invoked to start/stop any block-ack sessions for RX aggregation.

When RX aggregation is started by the peer, the driver is notified via ampdu_action function, with the IEEE80211_AMPDU_RX_START action, and may reject the request in which case a negative response is sent to the peer, if it accepts it a positive response is sent.

While the session is active, the device/driver are required to de-aggregate frames and pass them up one by one to mac80211, which will handle the reorder buffer.

When the aggregation session is stopped again by the peer or ourselves, the driver’s ampdu_action function will be called with the action IEEE80211_AMPDU_RX_STOP. In this case, the call must not fail.

Error

kernel-doc missing

Spatial Multiplexing Powersave (SMPS)

Error

kernel-doc missing

Error

kernel-doc missing

TBD

This part of the book describes the rate control algorithm interface and how it relates to mac80211 and drivers.

Rate Control API

TBD

Error

kernel-doc missing

TBD

This part of the book describes mac80211 internals.

Key handling

Key handling basics

Key handling in mac80211 is done based on per-interface (sub_if_data) keys and per-station keys. Since each station belongs to an interface, each station key also belongs to that interface.

Hardware acceleration is done on a best-effort basis for algorithms that are implemented in software, for each key the hardware is asked to enable that key for offloading but if it cannot do that the key is simply kept for software encryption (unless it is for an algorithm that isn’t implemented in software). There is currently no way of knowing whether a key is handled in SW or HW except by looking into debugfs.

All key management is internally protected by a mutex. Within all other parts of mac80211, key references are, just as STA structure references, protected by RCU. Note, however, that some things are unprotected, namely the key->sta dereferences within the hardware acceleration functions. This means that sta_info_destroy() must remove the key which waits for an RCU grace period.

MORE TBD

TBD

Receive processing

TBD

Transmit processing

TBD

Station info handling

Programming information

enum ieee80211_sta_info_flags

Stations flags

Constants

WLAN_STA_AUTH

Station is authenticated.

WLAN_STA_ASSOC

Station is associated.

WLAN_STA_PS_STA

Station is in power-save mode

WLAN_STA_AUTHORIZED

Station is authorized to send/receive traffic. This bit is always checked so needs to be enabled for all stations when virtual port control is not in use.

WLAN_STA_SHORT_PREAMBLE

Station is capable of receiving short-preamble frames.

WLAN_STA_WDS

Station is one of our WDS peers.

WLAN_STA_CLEAR_PS_FILT

Clear PS filter in hardware (using the IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next frame to this station is transmitted.

WLAN_STA_MFP

Management frame protection is used with this STA.

WLAN_STA_BLOCK_BA

Used to deny ADDBA requests (both TX and RX) during suspend/resume and station removal.

WLAN_STA_PS_DRIVER

driver requires keeping this station in power-save mode logically to flush frames that might still be in the queues

WLAN_STA_PSPOLL

Station sent PS-poll while driver was keeping station in power-save mode, reply when the driver unblocks.

WLAN_STA_TDLS_PEER

Station is a TDLS peer.

WLAN_STA_TDLS_PEER_AUTH

This TDLS peer is authorized to send direct packets. This means the link is enabled.

WLAN_STA_TDLS_INITIATOR

We are the initiator of the TDLS link with this station.

WLAN_STA_TDLS_CHAN_SWITCH

This TDLS peer supports TDLS channel-switching

WLAN_STA_TDLS_OFF_CHANNEL

The local STA is currently off-channel with this TDLS peer

WLAN_STA_TDLS_WIDER_BW

This TDLS peer supports working on a wider bw on the BSS base channel.

WLAN_STA_UAPSD

Station requested unscheduled SP while driver was keeping station in power-save mode, reply when the driver unblocks the station.

WLAN_STA_SP

Station is in a service period, so don’t try to reply to other uAPSD trigger frames or PS-Poll.

WLAN_STA_4ADDR_EVENT

4-addr event was already sent for this frame.

WLAN_STA_INSERTED

This station is inserted into the hash table.

WLAN_STA_RATE_CONTROL

rate control was initialized for this station.

WLAN_STA_TOFFSET_KNOWN

toffset calculated for this station is valid.

WLAN_STA_MPSP_OWNER

local STA is owner of a mesh Peer Service Period.

WLAN_STA_MPSP_RECIPIENT

local STA is recipient of a MPSP.

WLAN_STA_PS_DELIVER

station woke up, but we’re still blocking TX until pending frames are delivered

WLAN_STA_USES_ENCRYPTION

This station was configured for encryption, so drop all packets without a key later.

WLAN_STA_DECAP_OFFLOAD

This station uses rx decap offload

NUM_WLAN_STA_FLAGS

number of defined flags

Description

These flags are used with struct sta_info’s flags member, but only indirectly with set_sta_flag() and friends.

struct sta_info

STA information

Definition

struct sta_info {
  struct list_head list, free_list;
  struct rcu_head rcu_head;
  struct rhlist_head hash_node;
  u8 addr[ETH_ALEN];
  struct ieee80211_local *local;
  struct ieee80211_sub_if_data *sdata;
  struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS +NUM_DEFAULT_MGMT_KEYS + NUM_DEFAULT_BEACON_KEYS];
  struct ieee80211_key __rcu *ptk[NUM_DEFAULT_KEYS];
  u8 ptk_idx;
  struct rate_control_ref *rate_ctrl;
  void *rate_ctrl_priv;
  spinlock_t rate_ctrl_lock;
  spinlock_t lock;
  struct ieee80211_fast_tx __rcu *fast_tx;
  struct ieee80211_fast_rx __rcu *fast_rx;
  struct ieee80211_sta_rx_stats __percpu *pcpu_rx_stats;
#ifdef CONFIG_MAC80211_MESH;
  struct mesh_sta *mesh;
#endif;
  struct work_struct drv_deliver_wk;
  u16 listen_interval;
  bool dead;
  bool removed;
  bool uploaded;
  enum ieee80211_sta_state sta_state;
  unsigned long _flags;
  spinlock_t ps_lock;
  struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
  struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
  unsigned long driver_buffered_tids;
  unsigned long txq_buffered_tids;
  u64 assoc_at;
  long last_connected;
  struct ieee80211_sta_rx_stats rx_stats;
  struct {
    struct ewma_signal signal;
    struct ewma_signal chain_signal[IEEE80211_MAX_CHAINS];
  } rx_stats_avg;
  __le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1];
  struct {
    unsigned long filtered;
    unsigned long retry_failed, retry_count;
    unsigned int lost_packets;
    unsigned long last_pkt_time;
    u64 msdu_retries[IEEE80211_NUM_TIDS + 1];
    u64 msdu_failed[IEEE80211_NUM_TIDS + 1];
    unsigned long last_ack;
    s8 last_ack_signal;
    bool ack_signal_filled;
    struct ewma_avg_signal avg_ack_signal;
  } status_stats;
  struct {
    u64 packets[IEEE80211_NUM_ACS];
    u64 bytes[IEEE80211_NUM_ACS];
    struct ieee80211_tx_rate last_rate;
    struct rate_info last_rate_info;
    u64 msdu[IEEE80211_NUM_TIDS + 1];
  } tx_stats;
  u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
  struct airtime_info airtime[IEEE80211_NUM_ACS];
  struct sta_ampdu_mlme ampdu_mlme;
#ifdef CONFIG_MAC80211_DEBUGFS;
  struct dentry *debugfs_dir;
#endif;
  enum ieee80211_sta_rx_bandwidth cur_max_bandwidth;
  enum ieee80211_smps_mode known_smps_mode;
  const struct ieee80211_cipher_scheme *cipher_scheme;
  struct codel_params cparams;
  u8 reserved_tid;
  struct cfg80211_chan_def tdls_chandef;
  struct ieee80211_fragment_cache frags;
  struct ieee80211_sta sta;
};

Members

list

global linked list entry

free_list

list entry for keeping track of stations to free

rcu_head

RCU head used for freeing this station struct

hash_node

hash node for rhashtable

addr

station’s MAC address - duplicated from public part to let the hash table work with just a single cacheline

local

pointer to the global information

sdata

virtual interface this station belongs to

gtk

group keys negotiated with this station, if any

ptk

peer keys negotiated with this station, if any

ptk_idx

last installed peer key index

rate_ctrl

rate control algorithm reference

rate_ctrl_priv

rate control private per-STA pointer

rate_ctrl_lock

spinlock used to protect rate control data (data inside the algorithm, so serializes calls there)

lock

used for locking all fields that require locking, see comments in the header file.

fast_tx

TX fastpath information

fast_rx

RX fastpath information

pcpu_rx_stats

per-CPU RX statistics, assigned only if the driver needs this (by advertising the USES_RSS hw flag)

mesh

mesh STA information

drv_deliver_wk

used for delivering frames after driver PS unblocking

listen_interval

listen interval of this station, when we’re acting as AP

dead

set to true when sta is unlinked

removed

set to true when sta is being removed from sta_list

uploaded

set to true when sta is uploaded to the driver

sta_state

duplicates information about station state (for debug)

_flags

STA flags, see enum ieee80211_sta_info_flags, do not use directly

ps_lock

used for powersave (when mac80211 is the AP) related locking

ps_tx_buf

buffers (per AC) of frames to transmit to this station when it leaves power saving state or polls

tx_filtered

buffers (per AC) of frames we already tried to transmit but were filtered by hardware due to STA having entered power saving state, these are also delivered to the station when it leaves powersave or polls for frames

driver_buffered_tids

bitmap of TIDs the driver has data buffered on

txq_buffered_tids

bitmap of TIDs that mac80211 has txq data buffered on

assoc_at

clock boottime (in ns) of last association

last_connected

time (in seconds) when a station got connected

rx_stats

RX statistics

rx_stats_avg

averaged RX statistics

rx_stats_avg.signal

averaged signal

rx_stats_avg.chain_signal

averaged per-chain signal

last_seq_ctrl

last received seq/frag number from this STA (per TID plus one for non-QoS frames)

status_stats

TX status statistics

status_stats.filtered

# of filtered frames

status_stats.retry_failed

# of frames that failed after retry

status_stats.retry_count

# of retries attempted

status_stats.lost_packets

# of lost packets

status_stats.last_pkt_time

timestamp of last ACKed packet

status_stats.msdu_retries

# of MSDU retries

status_stats.msdu_failed

# of failed MSDUs

status_stats.last_ack

last ack timestamp (jiffies)

status_stats.last_ack_signal

last ACK signal

status_stats.ack_signal_filled

last ACK signal validity

status_stats.avg_ack_signal

average ACK signal

tx_stats

TX statistics

tx_stats.packets

# of packets transmitted

tx_stats.bytes

# of bytes in all packets transmitted

tx_stats.last_rate

last TX rate

tx_stats.msdu

# of transmitted MSDUs per TID

tid_seq

per-TID sequence numbers for sending to this STA

airtime

per-AC struct airtime_info describing airtime statistics for this station

ampdu_mlme

A-MPDU state machine state

debugfs_dir

debug filesystem directory dentry

cur_max_bandwidth

maximum bandwidth to use for TX to the station, taken from HT/VHT capabilities or VHT operating mode notification

known_smps_mode

the smps_mode the client thinks we are in. Relevant for AP only.

cipher_scheme

optional cipher scheme for this station

cparams

CoDel parameters for this station.

reserved_tid

reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED)

tdls_chandef

a TDLS peer can have a wider chandef that is compatible to the BSS one.

frags

fragment cache

sta

station information we share with the driver

Description

This structure collects information about a station that mac80211 is communicating with.

STA information lifetime rules

STA info structures (struct sta_info) are managed in a hash table for faster lookup and a list for iteration. They are managed using RCU, i.e. access to the list and hash table is protected by RCU.

Upon allocating a STA info structure with sta_info_alloc(), the caller owns that structure. It must then insert it into the hash table using either sta_info_insert() or sta_info_insert_rcu(); only in the latter case (which acquires an rcu read section but must not be called from within one) will the pointer still be valid after the call. Note that the caller may not do much with the STA info before inserting it, in particular, it may not start any mesh peer link management or add encryption keys.

When the insertion fails (sta_info_insert()) returns non-zero), the structure will have been freed by sta_info_insert()!

Station entries are added by mac80211 when you establish a link with a peer. This means different things for the different type of interfaces we support. For a regular station this mean we add the AP sta when we receive an association response from the AP. For IBSS this occurs when get to know about a peer on the same IBSS. For WDS we add the sta for the peer immediately upon device open. When using AP mode we add stations for each respective station upon request from userspace through nl80211.

In order to remove a STA info structure, various sta_info_destroy_*() calls are available.

There is no concept of ownership on a STA entry, each structure is owned by the global hash table/list until it is removed. All users of the structure need to be RCU protected so that the structure won’t be freed before they are done using it.

Aggregation Functions

struct tid_ampdu_tx

TID aggregation information (Tx).

Definition

struct tid_ampdu_tx {
  struct rcu_head rcu_head;
  struct timer_list session_timer;
  struct timer_list addba_resp_timer;
  struct sk_buff_head pending;
  struct sta_info *sta;
  unsigned long state;
  unsigned long last_tx;
  u16 timeout;
  u8 dialog_token;
  u8 stop_initiator;
  bool tx_stop;
  u16 buf_size;
  u16 ssn;
  u16 failed_bar_ssn;
  bool bar_pending;
  bool amsdu;
  u8 tid;
};

Members

rcu_head

rcu head for freeing structure

session_timer

check if we keep Tx-ing on the TID (by timeout value)

addba_resp_timer

timer for peer’s response to addba request

pending

pending frames queue – use sta’s spinlock to protect

sta

station we are attached to

state

session state (see above)

last_tx

jiffies of last tx activity

timeout

session timeout value to be filled in ADDBA requests

dialog_token

dialog token for aggregation session

stop_initiator

initiator of a session stop

tx_stop

TX DelBA frame when stopping

buf_size

reorder buffer size at receiver

failed_bar_ssn

ssn of the last failed BAR tx attempt

bar_pending

BAR needs to be re-sent

amsdu

support A-MSDU withing A-MDPU

tid

TID number

Description

This structure’s lifetime is managed by RCU, assignments to the array holding it must hold the aggregation mutex.

The TX path can access it under RCU lock-free if, and only if, the state has the flag HT_AGG_STATE_OPERATIONAL set. Otherwise, the TX path must also acquire the spinlock and re-check the state, see comments in the tx code touching it.

struct tid_ampdu_rx

TID aggregation information (Rx).

Definition

struct tid_ampdu_rx {
  struct rcu_head rcu_head;
  spinlock_t reorder_lock;
  u64 reorder_buf_filtered;
  struct sk_buff_head *reorder_buf;
  unsigned long *reorder_time;
  struct sta_info *sta;
  struct timer_list session_timer;
  struct timer_list reorder_timer;
  unsigned long last_rx;
  u16 head_seq_num;
  u16 stored_mpdu_num;
  u16 ssn;
  u16 buf_size;
  u16 timeout;
  u8 tid;
  u8 auto_seq:1,removed:1, started:1;
};

Members

rcu_head

RCU head used for freeing this struct

reorder_lock

serializes access to reorder buffer, see below.

reorder_buf_filtered

bitmap indicating where there are filtered frames in the reorder buffer that should be ignored when releasing frames

reorder_buf

buffer to reorder incoming aggregated MPDUs. An MPDU may be an A-MSDU with individually reported subframes.

reorder_time

jiffies when skb was added

sta

station we are attached to

session_timer

check if peer keeps Tx-ing on the TID (by timeout value)

reorder_timer

releases expired frames from the reorder buffer.

last_rx

jiffies of last rx activity

head_seq_num

head sequence number in reordering buffer.

stored_mpdu_num

number of MPDUs in reordering buffer

ssn

Starting Sequence Number expected to be aggregated.

buf_size

buffer size for incoming A-MPDUs

timeout

reset timer value (in TUs).

tid

TID number

auto_seq

used for offloaded BA sessions to automatically pick head_seq_and and ssn.

removed

this session is removed (but might have been found due to RCU)

started

this session has started (head ssn or higher was received)

Description

This structure’s lifetime is managed by RCU, assignments to the array holding it must hold the aggregation mutex.

The reorder_lock is used to protect the members of this struct, except for timeout, buf_size and dialog_token, which are constant across the lifetime of the struct (the dialog token being used only for debugging).

struct sta_ampdu_mlme

STA aggregation information.

Definition

struct sta_ampdu_mlme {
  struct mutex mtx;
  struct tid_ampdu_rx __rcu *tid_rx[IEEE80211_NUM_TIDS];
  u8 tid_rx_token[IEEE80211_NUM_TIDS];
  unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
  unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
  unsigned long tid_rx_manage_offl[BITS_TO_LONGS(2 * IEEE80211_NUM_TIDS)];
  unsigned long agg_session_valid[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
  unsigned long unexpected_agg[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
  struct work_struct work;
  struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS];
  struct tid_ampdu_tx *tid_start_tx[IEEE80211_NUM_TIDS];
  unsigned long last_addba_req_time[IEEE80211_NUM_TIDS];
  u8 addba_req_num[IEEE80211_NUM_TIDS];
  u8 dialog_token_allocator;
};

Members

mtx

mutex to protect all TX data (except non-NULL assignments to tid_tx[idx], which are protected by the sta spinlock) tid_start_tx is also protected by sta->lock.

tid_rx

aggregation info for Rx per TID – RCU protected

tid_rx_token

dialog tokens for valid aggregation sessions

tid_rx_timer_expired

bitmap indicating on which TIDs the RX timer expired until the work for it runs

tid_rx_stop_requested

bitmap indicating which BA sessions per TID the driver requested to close until the work for it runs

tid_rx_manage_offl

bitmap indicating which BA sessions were requested to be treated as started/stopped due to offloading

agg_session_valid

bitmap indicating which TID has a rx BA session open on

unexpected_agg

bitmap indicating which TID already sent a delBA due to unexpected aggregation related frames outside a session

work

work struct for starting/stopping aggregation

tid_tx

aggregation info for Tx per TID

tid_start_tx

sessions where start was requested

last_addba_req_time

timestamp of the last addBA request.

addba_req_num

number of times addBA request has been sent.

dialog_token_allocator

dialog token enumerator for each new session;

Synchronisation Functions

TBD

Locking, lots of RCU