mac80211 子系统(高级)

本书的这一部分内容仅对 mac80211 与驱动程序的高级交互感兴趣,以利用更多的硬件功能并提高性能。

LED 支持

Mac80211 支持多种闪烁 LED 的方式。在可能的情况下,设备 LED 应作为 LED 类设备公开,并连接到适当的触发器,然后由 mac80211 适当触发。

吞吐量闪烁描述

定义:

struct ieee80211_tpt_blink {
    int throughput;
    int blink_time;
};

成员

throughput

吞吐量,单位为千比特/秒

blink_time

闪烁时间,单位为毫秒(完整周期,即一个关闭周期 + 一个开启周期)

enum ieee80211_tpt_led_trigger_flags

吞吐量触发标志

常量

IEEE80211_TPT_LEDTRIG_FL_RADIO

启用无线电闪烁

IEEE80211_TPT_LEDTRIG_FL_WORK

启用工作时闪烁

IEEE80211_TPT_LEDTRIG_FL_CONNECTED

启用当至少一个接口以某种方式连接(包括作为 AP)时闪烁

const char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw)

获取 TX LED 的名称

参数

struct ieee80211_hw *hw

要获取 LED 触发器名称的硬件

描述

mac80211 为每个无线硬件创建一个传输 LED 触发器,如果您的驱动程序注册了一个 LED 设备,则可以使用该触发器来驱动 LED。此函数返回触发器的名称(如果未配置 LED,则返回 NULL),以便您可以自动链接 LED 设备。

返回

LED 触发器的名称。如果未配置 LED,则返回 NULL

const char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw)

获取 RX LED 的名称

参数

struct ieee80211_hw *hw

要获取 LED 触发器名称的硬件

描述

mac80211 为每个无线硬件创建一个接收 LED 触发器,如果您的驱动程序注册了一个 LED 设备,则可以使用该触发器来驱动 LED。此函数返回触发器的名称(如果未配置 LED,则返回 NULL),以便您可以自动链接 LED 设备。

返回

LED 触发器的名称。如果未配置 LED,则返回 NULL

const char *ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)

获取关联 LED 的名称

参数

struct ieee80211_hw *hw

要获取 LED 触发器名称的硬件

描述

mac80211 为每个无线硬件创建一个关联 LED 触发器,如果您的驱动程序注册了一个 LED 设备,则可以使用该触发器来驱动 LED。此函数返回触发器的名称(如果未配置 LED,则返回 NULL),以便您可以自动链接 LED 设备。

返回

LED 触发器的名称。如果未配置 LED,则返回 NULL

const char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw)

获取无线电 LED 的名称

参数

struct ieee80211_hw *hw

要获取 LED 触发器名称的硬件

描述

mac80211 为每个无线硬件创建一个无线电更改 LED 触发器,如果您的驱动程序注册了一个 LED 设备,则可以使用该触发器来驱动 LED。此函数返回触发器的名称(如果未配置 LED,则返回 NULL),以便您可以自动链接 LED 设备。

返回

LED 触发器的名称。如果未配置 LED,则返回 NULL

const char *ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw, unsigned int flags, const struct ieee80211_tpt_blink *blink_table, unsigned int blink_table_len)

创建吞吐量 LED 触发器

参数

struct ieee80211_hw *hw

要为其创建触发器的硬件

unsigned int flags

触发器标志,请参见enum ieee80211_tpt_led_trigger_flags

const struct ieee80211_tpt_blink *blink_table

闪烁表 - 需要按吞吐量排序

unsigned int blink_table_len

闪烁表的大小

返回

NULL(如果出错或未配置 LED 触发器)或新触发器的名称。

注意

此函数必须在ieee80211_register_hw()之前调用。

硬件加密加速

mac80211 能够利用许多用于加密和解密操作的硬件加速设计。

调用给定设备的 struct ieee80211_ops 中的 set_key() 回调函数是为了启用硬件加速加密和解密。该回调函数接受一个 sta 参数,对于默认密钥或仅用于传输的密钥,该参数将为 NULL;对于单个密钥,该参数将指向对等方的站点信息。当为接入点配置 VLAN 时,可以使用具有相同密钥索引的多个传输密钥。

在传输时,TX 控制数据将使用驱动程序通过修改 struct ieee80211_key_conf (由 set_key() 函数的 key 参数指向)所选择的 hw_key_idx

如果密钥现在正在使用,则用于 SET_KEY 命令的 set_key() 调用应返回 0;如果无法添加密钥,则返回 -EOPNOTSUPP 或 -ENOSPC;如果您返回 0,则必须将 hw_key_idx 分配给硬件密钥索引。您可以自由使用整个 u8 范围。

请注意,如果设置了 IEEE80211_HW_SW_CRYPTO_CONTROL 标志,则如果启用硬件加密失败,mac80211 不会自动回退到软件加密。set_key() 调用也可能返回 1,以允许在软件中完成此特定密钥/算法。

当 cmd 为 DISABLE_KEY 时,它必须成功。

请注意,即使已将密钥上传到硬件,也允许不对帧进行解密。堆栈不会根据密钥是否已上传来做出任何决定,而是根据接收标志做出决定。

key 参数指向的 struct ieee80211_key_conf 结构保证在另一次 set_key() 调用将其删除之前有效,但它只能用作区分密钥的 cookie。

在 TKIP 中,一些硬件需要提供一个第 1 阶段密钥,用于 RX 解密加速(例如 iwlwifi)。这些驱动程序应提供 update_tkip_key 处理程序。update_tkip_key() 调用会使用新的第 1 阶段密钥更新驱动程序。这在每次 iv16 环绕时(每 65536 个数据包)都会发生。set_key() 调用对于每个密钥只会发生一次(除非 AP 进行了重新密钥);它不会包含有效的第 1 阶段密钥。有效的第 1 阶段密钥仅由 update_tkip_key 提供。使 mac80211 调用此处理程序的触发器是软件解密,并且 iv16 发生环绕。

set_default_unicast_key() 调用会更新为 WEP 加密类型配置给硬件的默认 WEP 密钥索引。对于支持数据包卸载(例如 ARP 响应)的设备,这是必需的。

当 mac80211 驱动程序能够根据以下要求替换正在使用的 PTK 密钥时,它们应设置 NL80211_EXT_FEATURE_CAN_REPLACE_PTK0 标志:1) 它们不会将使用旧密钥解密的帧移交给 mac80211。

enum ieee80211_key_flags

密钥标志

常量

IEEE80211_KEY_FLAG_GENERATE_IV_MGMT

驱动程序应为 CCMP/GCMP 密钥设置此标志,以指示它仅需要为管理帧 (MFP) 生成 IV。

IEEE80211_KEY_FLAG_GENERATE_IV

驱动程序应设置此标志,以指示它需要为此特定密钥生成 IV。设置此标志并不一定意味着 SKB 将有足够的尾部空间用于 ICV 或 MIC。

IEEE80211_KEY_FLAG_GENERATE_MMIC

如果驱动程序需要在软件中生成 Michael MIC,则应为 TKIP 密钥设置此标志。

IEEE80211_KEY_FLAG_PAIRWISE

由 mac80211 设置,此标志指示密钥是成对密钥而不是共享密钥。

IEEE80211_KEY_FLAG_SW_MGMT_TX

如果驱动程序需要使用软件完成管理帧 (MFP) 的 CCMP/GCMP 加密,则应为 CCMP/GCMP 密钥设置此标志。

IEEE80211_KEY_FLAG_PUT_IV_SPACE

如果应为 IV 准备空间,但不应生成 IV 本身,则应由驱动程序设置此标志。请勿在同一密钥上与 IEEE80211_KEY_FLAG_GENERATE_IV 一起设置。设置此标志并不一定意味着 SKB 将有足够的尾部空间用于 ICV 或 MIC。

IEEE80211_KEY_FLAG_RX_MGMT

此密钥将用于解密接收到的管理帧。此标志可以通过允许驱动程序不将密钥上传到硬件并回退到软件加密来帮助那些硬件加密实现不能正确处理管理帧的驱动程序。请注意,此标志仅处理 RX,如果您的加密引擎不能处理 TX,您还可以设置 IEEE80211_KEY_FLAG_SW_MGMT_TX 标志以在 SW 中加密此类帧。

IEEE80211_KEY_FLAG_RESERVE_TAILROOM

驱动程序应为密钥设置此标志,以指示必须始终为 ICV 或 MIC 保留足够的尾部空间,即使启用了硬件加密也是如此。

IEEE80211_KEY_FLAG_PUT_MIC_SPACE

如果驱动程序仅需要 MIC 空间,则应为 TKIP 密钥设置此标志。请勿在同一密钥上与 IEEE80211_KEY_FLAG_GENERATE_MMIC 一起设置。

IEEE80211_KEY_FLAG_NO_AUTO_TX

密钥需要显式 Tx 激活。

IEEE80211_KEY_FLAG_GENERATE_MMIE

驱动程序应为 AES_CMAC 或 AES_GMAC 密钥设置此标志,以指示它仅需要序列号生成

IEEE80211_KEY_FLAG_SPP_AMSDU

SPP A-MSDU 可与此密钥一起使用(由 mac80211 从 sta->spp_amsdu 标志设置)

描述

这些标志用于驱动程序和 mac80211 之间关于密钥的通信,使用 struct ieee80211_key_confflags 参数。

struct ieee80211_key_conf

密钥信息

定义:

struct ieee80211_key_conf {
    atomic64_t tx_pn;
    u32 cipher;
    u8 icv_len;
    u8 iv_len;
    u8 hw_key_idx;
    s8 keyidx;
    u16 flags;
    s8 link_id;
    u8 keylen;
    u8 key[];
};

成员

tx_pn

用于 TX 密钥的 PN,如果驱动程序需要自己进行软件 PN 分配(例如,由于 TSO),也可以使用此 PN。

cipher

密钥的密码套件选择器。

icv_len

此密钥类型的 ICV 长度

iv_len

此密钥类型的 IV 长度

hw_key_idx

由驱动程序设置,这是当帧需要传输并需要在硬件中加密时,驱动程序希望提供的密钥索引。

keyidx

密钥索引 (0-3)

flags

密钥标志,请参阅 enum ieee80211_key_flags

link_id

MLO 的链接 ID,对于非 MLO 或成对密钥,则为 -1

keylen

密钥材料长度

key

密钥材料。对于 ALG_TKIP,密钥编码为一个 256 位(32 字节)数据块:- 临时加密密钥(128 位)- 临时身份验证器 Tx MIC 密钥(64 位)- 临时身份验证器 Rx MIC 密钥(64 位)

描述

此密钥信息由 mac80211 通过 struct ieee80211_ops 中的 set_key() 回调函数提供给驱动程序。

enum set_key_cmd

密钥命令

常量

SET_KEY

设置密钥

DISABLE_KEY

必须禁用密钥

描述

struct ieee80211_ops 中的 set_key() 回调函数一起使用,这指示密钥是被删除还是被添加。

void ieee80211_get_tkip_p1k_iv(struct ieee80211_key_conf *keyconf, u32 iv32, u16 *p1k)

获取 IV32 的 TKIP 第 1 阶段密钥

参数

struct ieee80211_key_conf *keyconf

使用 set key 传递的参数

u32 iv32

用于获取 P1K 的 IV32

u16 *p1k

将写入密钥的缓冲区,作为 5 个 u16 值

描述

此函数返回给定 IV32 的 TKIP 第 1 阶段密钥。

void ieee80211_get_tkip_p1k(struct ieee80211_key_conf *keyconf, struct sk_buff *skb, u16 *p1k)

获取 TKIP 第 1 阶段密钥

参数

struct ieee80211_key_conf *keyconf

使用 set key 传递的参数

struct sk_buff *skb

要从中提取 IV32 值的包,该值将使用此 P1K 加密

u16 *p1k

将写入密钥的缓冲区,作为 5 个 u16 值

描述

此函数返回从给定数据包获取的 IV32 的 TKIP 第 1 阶段密钥。

void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf, struct sk_buff *skb, u8 *p2k)

获取 TKIP 第二阶段密钥

参数

struct ieee80211_key_conf *keyconf

使用 set key 传递的参数

struct sk_buff *skb

要从中获取 IV32/IV16 值的,将使用此密钥加密的数据包

u8 *p2k

用于写入密钥的缓冲区,16 字节

描述

此函数计算数据包中 IV 值的 TKIP RC4 密钥。

省电支持

mac80211 支持各种省电实现。

首先,它可以支持由硬件本身处理所有省电的硬件;此类硬件应仅设置 IEEE80211_HW_SUPPORTS_PS 硬件标志。在这种情况下,它将根据关联状态,通过 IEEE80211_CONF_PS 标志得知所需的省电模式。硬件必须在必要时发送 nullfunc 帧,即在进入和离开省电模式时。硬件需要查看信标中的 AID,并在发现指向它的流量时向 AP 发出它已唤醒的信号。

IEEE80211_CONF_PS 标志启用表示启用了 IEEE 802.11-2007 第 11.2 节中定义的省电模式。这不应与硬件唤醒和睡眠状态相混淆。驱动程序负责在向硬件发出命令之前唤醒硬件,并在适当的时候使其恢复睡眠状态。

启用 PS 后,硬件需要唤醒以接收信标,并在信标之后接收缓冲的多播/广播帧。此外,必须可以发送帧并接收确认帧。

其他硬件设计无法自行发送 nullfunc 帧,还需要软件支持来解析 TIM 位图。mac80211 也通过结合 IEEE80211_HW_SUPPORTS_PSIEEE80211_HW_PS_NULLFUNC_STACK 标志来支持此功能。硬件当然仍然需要传递信标。硬件仍然需要处理多播流量的唤醒;如果不能,驱动程序必须尽力处理;mac80211 太慢而无法做到这一点。

动态省电是普通省电的扩展,其中硬件在发送帧后保持唤醒一段用户指定的时间,以便回复帧无需缓冲,因此无需延迟到下次唤醒。这是在有数据流量时获得足够好的延迟,并且在空闲期间仍然显着节省电量的折衷方案。

mac80211 只需根据流量启用和禁用 PS 即可支持动态省电。驱动程序只需要设置 IEEE80211_HW_SUPPORTS_PS 标志,mac80211 将自动处理所有事情。此外,支持动态 PS 功能的硬件可以设置 IEEE80211_HW_SUPPORTS_DYNAMIC_PS 标志,以指示它可以自行支持动态 PS 模式。驱动程序需要查看 dynamic_ps_timeout 硬件配置值,并在设置 IEEE80211_CONF_PS 时使用该值。在这种情况下,mac80211 将禁用堆栈中的动态 PS 功能,并且只要用户启用了省电,就只保持 IEEE80211_CONF_PS 启用。

驱动程序通过启用 IEEE80211_VIF_SUPPORTS_UAPSD 标志来通知 U-APSD 客户端支持。该模式通过 conf_tx() 操作中的 uapsd 参数进行配置。硬件需要发送 QoS Nullfunc 帧,并保持唤醒直到服务周期结束。要利用 U-APSD,将禁用 voip AC 的动态省电,并且来自该 AC 的所有帧都以启用省电的方式传输。

注意:IEEE80211_HW_PS_NULLFUNC_STACK 尚不支持 U-APSD 客户端模式。

信标过滤器支持

某些硬件具有信标过滤器支持,以减少主机 CPU 唤醒,从而降低系统功耗。它通常的工作方式是固件创建信标的校验和,但省略所有不断变化的元素(TSF、TIM 等)。每当校验和更改时,信标都会转发到主机,否则将直接丢弃。这样,主机将仅接收某些相关信息(例如 ERP 保护或 WMM 设置)已更改的信标。

信标过滤器支持通过 IEEE80211_VIF_BEACON_FILTER 接口功能进行通告。驱动程序需要在启用省电时启用信标过滤器支持,即设置 IEEE80211_CONF_PS。启用省电后,堆栈将不检查信标丢失,驱动程序需要使用 ieee80211_beacon_loss() 通知信标丢失。

固件通知驱动程序发生信标丢失事件(进而导致驱动程序调用 ieee80211_beacon_loss())之前的时间(或错过的信标数量)应该是可配置的,并且将在未来由 mac80211 和漫游算法控制。

由于可能存在软件堆栈中没有任何内容关心的不断变化的信息元素,因此未来我们将让 mac80211 告诉驱动程序哪些信息元素很有趣,因为我们希望看到它们发生变化。这将包括

  • 信息元素 ID 列表

  • 供应商信息元素的 OUI 列表

理想情况下,硬件将过滤掉任何请求元素中没有变化的信标,但如果它不支持该功能,则可能会以一些效率为代价,仅过滤掉一个子集。例如,如果设备不支持检查 OUI,则应传递所有供应商信息元素中的所有更改。

请注意,为简单起见,更改还包括信息元素在信标中出现或消失。

某些硬件支持“忽略列表”。只需确保请求的任何内容都不在忽略列表中,并在忽略列表中包含常见的更改信息元素 ID,例如 11 (BSS 负载) 以及具有未知内容的各种供应商分配的 IE (128、129、133-136、149、150、155、156、173、176、178、179、219);为了向前兼容,它还可以包含一些当前未使用的 ID。

除了这些功能外,硬件还应支持通知主机信标 RSSI 的变化。当没有流量流动时(当流量流动时,我们会看到接收到的数据包的 RSSI),这与实现漫游有关。这可以包括在 RSSI 显着变化或降至低于或高于可配置阈值时通知主机。将来,这些阈值也将由 mac80211(从用户空间获取)进行配置,以根据漫游算法的要求实现它们。

如果硬件无法实现此功能,驱动程序应要求它定期将信标帧传递给主机,以便软件可以执行信号强度阈值检查。

void ieee80211_beacon_loss(struct ieee80211_vif *vif)

通知硬件未接收到信标

参数

struct ieee80211_vif *vif

来自 add_interface 回调的 struct ieee80211_vif 指针。

描述

当启用信标过滤 IEEE80211_VIF_BEACON_FILTER 并且设置 IEEE80211_CONF_PS 时,驱动程序需要在硬件未通过此函数接收信标时通知。

多队列和 QoS 支持

待定

struct ieee80211_tx_queue_params

传输队列配置

定义:

struct ieee80211_tx_queue_params {
    u16 txop;
    u16 cw_min;
    u16 cw_max;
    u8 aifs;
    bool acm;
    bool uapsd;
    bool mu_edca;
    struct ieee80211_he_mu_edca_param_ac_rec mu_edca_param_rec;
};

成员

txop

最大突发时间,单位为 32 微秒,0 表示禁用

cw_min

最小竞争窗口 [范围为 1..32767 的 2^n-1 形式的值]

cw_max

最大竞争窗口 [与 cw_min 相同]

aifs

仲裁帧间间隔 [0..255]

acm

访问类别是否需要强制准入控制

uapsd

是否为队列启用 U-APSD 模式

mu_edca

是否配置了 MU EDCA

mu_edca_param_rec

HE 的 MU EDCA 参数记录

描述

此结构中提供的信息是 QoS 传输队列配置所必需的。参见 IEEE 802.11 7.3.2.29。

接入点模式支持

待定

if_conf 的某些部分应该在这里讨论

在此处或硬件加密章节中插入有关带有硬件加密的 VLAN 接口的说明。

支持省电客户端

为了实现 AP 和 P2P GO 模式,mac80211 支持客户端省电,包括“传统” PS(PS-Poll/空数据)和 uAPSD。目前不支持 sAPSD。

mac80211 有一个假设,即客户端不会同时使用 PS-Poll 轮询和 uAPSD 触发。两者都支持,并且可以由同一客户端使用,但它们不能由同一客户端同时使用。这简化了驱动程序代码。

首先要记住的是,有一个用于完整驱动程序实现的标志:IEEE80211_HW_AP_LINK_PS。如果设置了此标志,mac80211 会期望驱动程序处理省电客户端的大部分状态机,并忽略传入帧中的 PM 位。然后,驱动程序使用 ieee80211_sta_ps_transition() 来通知 mac80211 站点的省电转换。在此模式下,mac80211 也不处理 PS-Poll/uAPSD。

在没有 IEEE80211_HW_AP_LINK_PS 的模式下,mac80211 将检查传入帧中的 PM 位以进行客户端省电转换。当站点进入睡眠状态时,我们将停止向其传输。但是,存在一个竞争条件:站点可能会在硬件队列中有数据缓冲时进入睡眠状态。如果设备支持此功能,它将拒绝帧,并且驱动程序应将带有 IEEE80211_TX_STAT_TX_FILTERED 标志的帧返回给 mac80211,这将导致 mac80211 在站点唤醒时重试该帧。驱动程序还会通过调用其 sta_notify 回调来收到省电转换的通知。

当站点处于睡眠状态时,它有三种选择:它可以唤醒、它可以进行 PS-Poll 或它可以开始 uAPSD 服务周期。唤醒是通过简单地将所有缓冲的(和过滤的)帧传输到站点来实现的。这是最简单的情况。当站点发送 PS-Poll 或 uAPSD 触发帧时,mac80211 将使用 allow_buffered_frames 回调通知驱动程序;此回调是可选的。然后,mac80211 将像往常一样传输帧,并在每个帧上设置 IEEE80211_TX_CTL_NO_PS_BUFFER。服务周期中的最后一个帧(或对 PS-Poll 的唯一响应)也设置了 IEEE80211_TX_STATUS_EOSP 以指示它结束服务周期;由于此帧必须具有 TX 状态报告,因此它还设置 IEEE80211_TX_CTL_REQ_TX_STATUS。当为此帧报告 TX 状态时,服务周期被标记为已结束,并且对等方可以启动一个新的服务周期。

此外,mac80211 也可以传输带有 IEEE80211_TX_CTL_NO_PS_BUFFER 设置的不可缓冲的 MMPDU。

在某些设备(例如 iwlwifi)上,当站点有帧排队并且它唤醒或轮询时,可能会发生另一个竞争条件;已经排队的帧最终可能会先传输,从而导致重新排序和/或 EOSP 的错误处理。原因是允许将帧传输到某个站点的带外通信到设备。为了解决此问题,如果帧在站点进入睡眠状态时被通知时被缓冲,则驱动程序可以调用 ieee80211_sta_block_awake()。当所有这些帧都被过滤后(见上文),它必须再次调用该函数以指示该站点不再被阻止。

如果驱动程序以任何方式缓冲帧以进行聚合,则在通知站点进入睡眠状态时,它必须使用 ieee80211_sta_set_buffered() 调用来通知 mac80211 哪些 TID 有缓冲的帧。请注意,当站点唤醒时,此信息将重置(因此需要在通知站点进入睡眠状态时调用它)。然后,当出于任何原因开始服务周期时,将使用要释放的帧数以及它们来自哪些 TID 来调用 release_buffered_frames。在这种情况下,驱动程序负责在释放的帧中设置 EOSP(对于 uAPSD)和 MORE_DATA 位。为了帮助 more_data 参数,将传递给驱动程序,以告知其他 TID 上是否有更多数据 — 由于 mac80211 不知道这些 TID 的缓冲区包含多少帧,因此将忽略要从中释放帧的 TID。

如果驱动程序还实现 GO 模式,其中不存在时间段可能会缩短服务时间段(或中止 PS-Poll 响应),则它必须过滤那些响应帧,除非帧被缓冲在驱动程序中 — 这些帧必须保持缓冲,以避免重新排序。因为在这种情况下可能不会释放任何帧,所以驱动程序必须调用 ieee80211_sta_eosp() 以向 mac80211 指示服务周期仍然结束。

最后,如果从 mac80211 释放来自多个 TID 的帧,但驱动程序可能会对它们进行重新排序,则必须正确清除并设置标志(只有最后一个帧可能具有 IEEE80211_TX_STATUS_EOSP),并且还必须注意帧中的 EOSP 和 MORE_DATA 位。驱动程序也可以在这种情况下使用 ieee80211_sta_eosp()

请注意,如果驱动程序缓冲的帧不是 QoS 数据帧,则必须注意永远不要将非 QoS 数据帧作为服务周期中的最后一个帧发送,如果需要,则在非 QoS 数据帧之后添加 QoS-nulldata 帧。

enum ieee80211_frame_release_type

帧释放原因

常量

IEEE80211_FRAME_RELEASE_PSPOLL

为 PS-Poll 释放的帧

IEEE80211_FRAME_RELEASE_UAPSD

由于在启用触发的 AC 上接收到的帧而释放的帧

int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start)

已连接站点的 PS 转换

参数

struct ieee80211_sta *sta

当前连接的站点

bool start

启动或停止 PS

描述

当在设置了 IEEE80211_HW_AP_LINK_PS 标志的 AP 模式下运行时,请使用此函数通知 mac80211 已连接的站点正在进入/离开 PS 模式。

不得在 IRQ 上下文中或启用软中断的情况下调用此函数。

对单个硬件的此函数的调用必须相互同步。

返回

成功时返回 0。当请求的 PS 模式已设置时返回 -EINVAL。

int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta, bool start)

已连接站点的 PS 转换(在进程上下文中)

参数

struct ieee80211_sta *sta

当前连接的站点

bool start

启动或停止 PS

描述

类似于 ieee80211_sta_ps_transition(),但可以在进程上下文中调用(内部禁用底部半部分)。并发调用限制仍然适用。

返回

类似于 ieee80211_sta_ps_transition()

void ieee80211_sta_set_buffered(struct ieee80211_sta *sta, u8 tid, bool buffered)

通知 mac80211 有关驱动程序缓冲的帧

参数

struct ieee80211_sta *sta

睡眠站点的 struct ieee80211_sta 指针

u8 tid

具有缓冲帧的 TID

bool buffered

指示此 TID 是否缓冲了帧

描述

如果驱动程序为省电站点缓冲帧而不是将它们传递回 mac80211 以进行重传,则可能仍需要通过 TIM 位告知该站点有缓冲的帧。

此函数通知 mac80211 驱动程序中是否为给定 TID 缓冲了帧;然后,mac80211 可以使用此数据来设置 TIM 位(注意:这可能会回调到驱动程序的 set_tim 调用中!请注意锁定!)

如果所有帧都释放到站点(由于 PS-poll 或 uAPSD),则驱动程序需要通知 mac80211 不再有缓冲的帧。但是,当站点唤醒时,mac80211 会假设所有缓冲的帧都将传输并清除此数据,驱动程序需要确保它们在睡眠转换时(使用 STA_NOTIFY_SLEEP 的 sta_notify())通知 mac80211 所有缓冲的帧。

请注意,从技术上讲,mac80211 只需要知道每个 AC 的信息,而不是每个 TID 的信息,但是由于驱动程序缓冲不可避免地会发生在每个 TID 上(因为它与聚合相关),因此使 mac80211 将 TID 映射到 AC 更容易,而不是在所有使用此 API 的驱动程序中进行跟踪。

struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, unsigned int link_id)

信标生成函数

参数

struct ieee80211_hw *hw

ieee80211_alloc_hw() 获取的指针。

struct ieee80211_vif *vif

来自 add_interface 回调的 struct ieee80211_vif 指针。

unsigned int link_id

信标所属的链路 ID(对于未与 AP MLD 关联的 AP STA,则为 0)。

描述

请参阅 ieee80211_beacon_get_tim()。

返回

请参阅 ieee80211_beacon_get_tim()。

struct sk_buff *ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif)

访问缓冲的广播和组播帧

参数

struct ieee80211_hw *hw

ieee80211_alloc_hw() 获取的指针。

struct ieee80211_vif *vif

来自 add_interface 回调的 struct ieee80211_vif 指针。

描述

用于访问缓冲的广播和组播帧的函数。如果硬件/固件在节能模式下不实现广播/组播帧的缓冲,则 802.11 代码会将它们缓冲在主机内存中。底层驱动程序使用此函数来获取下一个缓冲帧。在大多数情况下,这在生成信标帧时使用。

返回

指向下一个缓冲的 skb 的指针,如果没有更多缓冲帧可用,则为 NULL。

注意

只有在生成了 DTIM 信标帧并使用 ieee80211_beacon_get() 之后,才会返回缓冲的帧,因此底层驱动程序必须首先调用 ieee80211_beacon_get()ieee80211_get_buffered_bc() 如果上一个生成的信标不是 DTIM,则返回 NULL,因此底层驱动程序不需要单独检查 DTIM 信标,并且应该能够对所有信标使用通用代码。

void ieee80211_sta_block_awake(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta, bool block)

阻止站点唤醒

参数

struct ieee80211_hw *hw

硬件

struct ieee80211_sta *pubsta

站点

bool block

是否阻止或取消阻止

描述

某些设备要求在向睡眠状态的特定站点发送轮询响应或该站点唤醒后的帧之前,必须刷新该站点队列中的所有帧。请注意,驱动程序必须将此类帧作为已过滤帧拒绝,并带有适当的状态标志。

此函数允许以无竞争的方式实现此模式。

为此,驱动程序必须跟踪仍为特定站点排队的帧数。如果当站点进入睡眠状态时此数字不为零,则驱动程序必须调用此函数,以强制 mac80211 认为该站点处于睡眠状态,而不管该站点的实际状态如何。一旦未完成的帧数达到零,驱动程序必须再次调用此函数以取消阻止该站点。这将导致 mac80211 能够发送 ps-poll 响应,如果站点在此期间进行了查询,则也会因此发送帧。此外,驱动程序将收到该站点在取消阻止后一段时间唤醒的通知,无论该站点是否在被阻止时实际唤醒。

void ieee80211_sta_eosp(struct ieee80211_sta *pubsta)

通知 mac80211 SP 结束

参数

struct ieee80211_sta *pubsta

站点

描述

当设备以无法在 TX 状态中告知 mac80211 关于 EOSP 的方式传输帧时,它必须清除 IEEE80211_TX_STATUS_EOSP 位并改为调用此函数。这适用于 PS-Poll 以及 uAPSD。

请注意,就像 _tx_status() 和 _rx() 一样,驱动程序不得混合调用 irqsafe/non-irqsafe 版本,此函数也不得与这些版本混合使用。使用全部 irqsafe,或全部 non-irqsafe,不要混合!

注意:此函数的 _irqsafe 版本不存在,现在没有

驱动程序需要它。如果您需要 _irqsafe 版本,请不要调用此函数,请查看 git 历史记录并恢复 _irqsafe 版本!

支持多个虚拟接口

待定

注意:具有相同 MAC 地址的 WDS 几乎总是可以的

在此处插入关于具有不同 MAC 地址的多个虚拟接口的说明,注意 mac80211 支持哪些配置,添加关于使用它支持硬件加密的说明。

void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw, u32 iter_flags, void (*iterator)(void *data, u8 *mac, struct ieee80211_vif *vif), void *data)

迭代活动接口

参数

struct ieee80211_hw *hw

应该迭代其接口的硬件结构

u32 iter_flags

迭代标志,请参阅 enum ieee80211_interface_iteration_flags

void (*iterator)(void *data, u8 *mac, struct ieee80211_vif *vif)

要调用的迭代器函数

void *data

迭代器函数的第一个参数

描述

此函数迭代与给定硬件关联的当前活动的接口,并为它们调用回调。当迭代器函数可以休眠时,可以使用此函数。当迭代器函数是原子的时,可以使用 ieee80211_iterate_active_interfaces_atomic。在 add_interface() 期间不会迭代新的接口。

void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw, u32 iter_flags, void (*iterator)(void *data, u8 *mac, struct ieee80211_vif *vif), void *data)

迭代活动接口

参数

struct ieee80211_hw *hw

应该迭代其接口的硬件结构

u32 iter_flags

迭代标志,请参阅 enum ieee80211_interface_iteration_flags

void (*iterator)(void *data, u8 *mac, struct ieee80211_vif *vif)

要调用的迭代器函数,不能休眠

void *data

迭代器函数的第一个参数

描述

此函数迭代给定硬件的当前活动接口,并为它们调用回调函数。此函数要求迭代器回调函数是原子的,如果不需要原子性,请改用 ieee80211_iterate_active_interfaces 。在 add_interface() 期间不会迭代新的接口。

站点处理

待办事项

struct ieee80211_sta

站点表条目

定义:

struct ieee80211_sta {
    u8 addr[ETH_ALEN] ;
    u16 aid;
    u16 max_rx_aggregation_subframes;
    bool wme;
    u8 uapsd_queues;
    u8 max_sp;
    struct ieee80211_sta_rates __rcu *rates;
    bool tdls;
    bool tdls_initiator;
    bool mfp;
    bool mlo;
    bool spp_amsdu;
    u8 max_amsdu_subframes;
    struct ieee80211_sta_aggregates *cur;
    bool support_p2p_ps;
    struct ieee80211_txq *txq[IEEE80211_NUM_TIDS + 1];
    u16 valid_links;
    struct ieee80211_link_sta deflink;
    struct ieee80211_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
    u8 drv_priv[] ;
};

成员

addr

MAC 地址

aid

如果我们是 AP,分配给站点的 AID

max_rx_aggregation_subframes

此站点允许向我们传输的单个 AMPDU 中的最大帧数。 可以由驱动程序修改。

wme

指示 STA 是否支持 QoS/WME(如果本地设备支持,否则始终为 false)

uapsd_queues

配置为 uapsd 的队列的位图。 仅当支持 wme 时有效。 位顺序与 IEEE80211_WMM_IE_STA_QOSINFO_AC_* 中的顺序相同。

max_sp

最大服务周期。仅当支持 wme 时有效。

rates

速率控制选择表

tdls

指示 STA 是否为 TDLS 对等方

tdls_initiator

指示 STA 是否为 TDLS 链路的发起方。 仅当 STA 首先是 TDLS 对等方时有效。

mfp

指示 STA 是否使用管理帧保护。

mlo

指示 STA 是否为 MLO 站点。

spp_amsdu

指示 STA 是否使用 SPP A-MSDU。

max_amsdu_subframes

指示单个 A-MSDU 中的最大 MSDU 数量。 取自扩展功能元素。 0 表示无限制。

cur

当前有效数据,从活动链接聚合而来。 对于非 MLO STA,它将指向 deflink 数据。 对于 MLO STA,必须调用 ieee80211_sta_recalc_aggregates() 来更新它。

support_p2p_ps

指示 STA 是否支持 P2P PS 机制。

txq

每个 TID 数据 TX 队列;请注意,最后一个条目 (IEEE80211_NUM_TIDS) 用于非数据帧

valid_links

有效链接的位图,对于非 MLO,则为 0

deflink

这保存默认链路 STA 信息,对于非 MLO STA,所有链路特定的 STA 信息都通过 deflink 或通过指向 deflink 地址的 link[0] 访问。 对于 MLO 链路 STA,第一个添加的链路 STA 将指向 deflink。

link

对链路 STA 条目的引用。 对于非 MLO STA,除了第一个链路,即 link[0] 之外,所有链路默认都将分配为 NULL,并将通过 deflink 或 link[0] 访问链路信息。 对于 MLO STA,添加的第一个链路 STA 将其链路指针指向 deflink 地址,剩余的将分配,并且该地址将分配给 link[link_id],其中 link_id 是 AP 分配的 ID。

drv_priv

供驱动程序使用的数据区域,将始终与 sizeof(void *) 对齐,大小在硬件信息中确定。

描述

站点表条目表示我们可能正在与之通信的站点。由于站点在 mac80211 中由 RCU 管理,因此您访问的任何 ieee80211_sta 指针都必须由 rcu_read_lock() 显式或隐式保护,或者您必须小心不要在调用删除该指针的 sta_remove 回调后使用此类指针。 这也表示 MLO 关联情况下的 MLD STA,并保存指向各个链路 STA 的指针

enum sta_notify_cmd

sta 通知命令

常量

STA_NOTIFY_SLEEP

一个站点现在正在休眠

STA_NOTIFY_AWAKE

一个休眠的站点已唤醒

描述

struct ieee80211_ops 中的 sta_notify() 回调一起使用,这表示关联的站点是否进行了电源状态转换。

struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, const u8 *addr)

查找站点

参数

struct ieee80211_vif *vif

要在其上查找站点的虚拟接口

const u8 *addr

站点的地址

返回

如果找到,则返回站点。否则返回 NULL

注意

此函数必须在 RCU 锁下调用,并且生成的指针也仅在 RCU 锁下有效。

struct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw, const u8 *addr, const u8 *localaddr)

在硬件上查找站点

参数

struct ieee80211_hw *hw

ieee80211_alloc_hw() 获取的指针

const u8 *addr

远程站点的地址

const u8 *localaddr

本地地址 (vif->sdata->vif.addr)。 对于“任何”地址,使用 NULL。

返回

如果找到,则返回站点。否则返回 NULL

注意

此函数必须在 RCU 锁下调用,并且生成的指针也仅在 RCU 锁下有效。

注意

您可以为 localaddr 传递 NULL,但这样您将只获得

第一个与远程地址 “addr” 匹配的 STA。 我们可以有多个与多个逻辑站点关联的 STA(例如,考虑一个站点在同一 AP 硬件上连接到另一个 BSSID,而无需先断开连接)。 在这种情况下,使用 localaddr NULL 的此方法的结果是不可靠的。

描述

如果可能,请勿对 localaddr 使用 NULL 来使用此函数。

硬件扫描卸载

待定

void ieee80211_scan_completed(struct ieee80211_hw *hw, struct cfg80211_scan_info *info)

已完成的硬件扫描

参数

struct ieee80211_hw *hw

完成扫描的硬件

struct cfg80211_scan_info *info

有关已完成扫描的信息

描述

当使用硬件扫描卸载(即分配了 hw_scan() 回调)时,驱动程序需要调用此函数来通知 mac80211 扫描已完成。 此函数可以从任何上下文调用,包括硬中断上下文。

聚合

TX A-MPDU 聚合

TX 端的聚合需要设置硬件标志 IEEE80211_HW_AMPDU_AGGREGATION。 然后,驱动程序将收到带有指示 A-MPDU 聚合的标志的数据包。 驱动程序或设备负责实际聚合帧,以及决定聚合多少个帧和聚合哪些帧。

当通过调用 ieee80211_start_tx_ba_session() 函数来启动一些子系统(通常是速率控制算法)的 TX 聚合时,将通过其 ampdu_action 函数通知驱动程序,操作为 IEEE80211_AMPDU_TX_START

作为响应,驱动程序稍后需要调用 ieee80211_start_tx_ba_cb_irqsafe() 函数,该函数将在对等方也做出响应后真正启动聚合会话。 如果对等方做出否定响应,则会立即再次停止会话。 请注意,可能会在驱动程序指示已完成设置之前停止聚合会话,在这种情况下,它不得指示设置完成。

另请注意,由于我们还需要等待对等方的响应,因此会通过 ampdu_action 回调的 IEEE80211_AMPDU_TX_OPERATIONAL 操作来通知驱动程序握手的完成。

类似地,当聚合会话被对等方停止或某些调用 ieee80211_stop_tx_ba_session() 的操作停止时,驱动程序的 ampdu_action 函数将以 IEEE80211_AMPDU_TX_STOP 操作被调用。在这种情况下,调用不得失败,并且驱动程序稍后必须调用 ieee80211_stop_tx_ba_cb_irqsafe()。请注意,sta 可能会在 BA 拆除完成之前被销毁。

RX A-MPDU 聚合

RX 端的聚合只需要实现 ampdu_action 回调,该回调被调用以启动/停止用于 RX 聚合的任何块确认会话。

当对等方启动 RX 聚合时,驱动程序会通过 ampdu_action 函数收到通知,操作为 IEEE80211_AMPDU_RX_START,并且可以拒绝该请求,在这种情况下,会向对等方发送否定响应;如果接受该请求,则发送肯定响应。

当会话处于活动状态时,设备/驱动程序需要解聚帧,并将它们逐个传递给 mac80211,这将处理重排序缓冲区。

当聚合会话再次被对等方或我们自己停止时,驱动程序的 ampdu_action 函数将以 IEEE80211_AMPDU_RX_STOP 操作被调用。在这种情况下,调用不得失败。

enum ieee80211_ampdu_mlme_action

A-MPDU 操作

常量

IEEE80211_AMPDU_RX_START

启动 RX 聚合

IEEE80211_AMPDU_RX_STOP

停止 RX 聚合

IEEE80211_AMPDU_TX_START

启动 TX 聚合,驱动程序必须调用 ieee80211_start_tx_ba_cb_irqsafe() 或以状态 IEEE80211_AMPDU_TX_START_DELAY_ADDBA 调用 ieee80211_start_tx_ba_cb_irqsafe(),以便在调用 ieee80211_start_tx_ba_cb_irqsafe 之后延迟 addba,或者仅返回特殊状态 IEEE80211_AMPDU_TX_START_IMMEDIATE

IEEE80211_AMPDU_TX_STOP_CONT

停止 TX 聚合,但继续发送排队的未聚合的数据包。在发送完所有数据包后,驱动程序必须调用 ieee80211_stop_tx_ba_cb_irqsafe()

IEEE80211_AMPDU_TX_STOP_FLUSH

停止 TX 聚合并刷新所有数据包,当站点被移除时调用。在这种情况下,无需或没有理由调用 ieee80211_stop_tx_ba_cb_irqsafe(),因为 mac80211 假设会话已结束并移除该站点。

IEEE80211_AMPDU_TX_STOP_FLUSH_CONT

当 TX 聚合停止但驱动程序尚未调用 ieee80211_stop_tx_ba_cb_irqsafe() 时调用,现在连接已断开,该站点将被移除。当调用此函数时,驱动程序应清理并丢弃剩余的数据包。

IEEE80211_AMPDU_TX_OPERATIONAL

TX 聚合已开始运行

描述

这些标志与 struct ieee80211_ops 中的 ampdu_action() 回调一起使用,以指示需要哪个操作。

请注意,驱动程序必须能够处理 TX 聚合会话被停止的情况,即使在它们通过调用 ieee80211_start_tx_ba_cb_irqsafe 确认开始之前,因为对等方可能会收到 addBA 帧并立即发送 delBA!

空间复用节能 (SMPS)

SMPS(空间复用节能)是一种在 802.11n 实现中节省功耗的机制。有关该机制和原理的详细信息,请参阅 802.11(由 802.11n-2009 修订)“11.2.3 SM 节能”。

mac80211 实现能够发送操作帧来更新 AP 关于站点的 SMPS 模式,并将指示驱动程序进入特定的模式。它还将在关联握手期间宣布请求的 SMPS 模式。需要硬件支持此功能,并且可以通过硬件标志指示。

默认模式将为“自动”,nl80211/cfg80211 将其定义为在(常规)节能模式下为动态 SMPS,否则关闭 SMPS。

要支持此功能,驱动程序必须设置相应的硬件支持标志,并将 SMPS 标志处理到 config() 操作。然后,将通过此机制指示驱动程序在与 HT AP 关联时进入请求的 SMPS 模式。

enum ieee80211_smps_mode

空间复用节能模式

常量

IEEE80211_SMPS_AUTOMATIC

自动

IEEE80211_SMPS_OFF

关闭

IEEE80211_SMPS_STATIC

静态

IEEE80211_SMPS_DYNAMIC

动态

IEEE80211_SMPS_NUM_MODES

内部使用,请勿使用

void ieee80211_request_smps(struct ieee80211_vif *vif, unsigned int link_id, enum ieee80211_smps_mode smps_mode)

请求 SM PS 转换

参数

struct ieee80211_vif *vif

来自 add_interface 回调的 struct ieee80211_vif 指针。

unsigned int link_id

MLO 的链接 ID,或 0

enum ieee80211_smps_mode smps_mode

新的 SM PS 模式

描述

这允许驱动程序在管理模式下请求 SM PS 转换。当驱动程序具有比堆栈更多的关于可能干扰的信息(例如通过蓝牙)时,这非常有用。

待定

本书的这一部分描述了速率控制算法接口及其与 mac80211 和驱动程序的关系。

速率控制 API

待定

enum ieee80211_rate_control_changed

指示更改内容的标志

常量

IEEE80211_RC_BW_CHANGED

可用于向此站点发送数据的带宽已更改。实际带宽在站点信息中——对于 HT20/40,IEEE80211_HT_CAP_SUP_WIDTH_20_40 标志会更改,对于 HT 和 VHT,带宽字段会更改。

IEEE80211_RC_SMPS_CHANGED

站点的 SMPS 状态已更改。

IEEE80211_RC_SUPP_RATES_CHANGED

由于发现了有关对等方的更多信息,此对等方的支持速率集已更改(在 IBSS 模式下)。

IEEE80211_RC_NSS_CHANGED

N_SS(空间流数)由对等方更改

int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid, u16 timeout)

启动 tx 块确认会话。

参数

struct ieee80211_sta *sta

要启动 BA 会话的站点

u16 tid

要进行 BA 的 TID。

u16 timeout

会话超时值(以 TUs 为单位)

返回

如果发送了 addBA 请求,则成功;否则失败

描述

尽管 mac80211/底层驱动程序/用户空间应用程序可以估计需要在某个 RA/TID 上启动聚合,但会话级别将由 mac80211 管理。

void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, u16 tid)

底层驱动程序已准备好聚合。

参数

struct ieee80211_vif *vif

来自 add_interface 回调的 struct ieee80211_vif 指针

const u8 *ra

BA 会话接收方的接收地址。

u16 tid

要进行 BA 的 TID。

描述

此函数必须由底层驱动程序在完成 BA 会话的准备工作后调用。它可以从任何上下文中调用。

int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid)

停止块确认会话。

参数

struct ieee80211_sta *sta

要停止其 BA 会话的站点

u16 tid

要停止 BA 的 TID。

返回

如果 TID 无效或没有活动聚合,则返回负错误

描述

尽管 mac80211/底层驱动程序/用户空间应用程序可以估计需要在某个 RA/TID 上停止聚合,但会话级别将由 mac80211 管理。

void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra, u16 tid)

底层驱动准备停止聚合。

参数

struct ieee80211_vif *vif

来自 add_interface 回调的 struct ieee80211_vif 指针

const u8 *ra

BA 会话接收方的接收地址。

u16 tid

需要在其上执行 BA 的目标 TID。

描述

此函数必须由底层驱动在完成 BA 会话拆除的准备工作后调用。它可以从任何上下文中调用。

struct ieee80211_tx_rate_control

用于/来自 RC 算法的速率控制信息

定义:

struct ieee80211_tx_rate_control {
    struct ieee80211_hw *hw;
    struct ieee80211_supported_band *sband;
    struct ieee80211_bss_conf *bss_conf;
    struct sk_buff *skb;
    struct ieee80211_tx_rate reported_rate;
    bool rts, short_preamble;
    u32 rate_idx_mask;
    u8 *rate_idx_mcs_mask;
    bool bss;
};

成员

hw

调用算法的硬件。

sband

此帧正在其上发送的频段。

bss_conf

当前的 BSS 配置

skb

将要发送的 skb,需要填充其中的控制信息

reported_rate

速率控制算法可以填充此项,以指示应向用户空间报告哪个速率作为当前速率,并用于网状网络中的速率计算。

rts

是否将为此帧使用 RTS,因为它比 RTS 阈值长

short_preamble

如果所选速率支持,mac80211 是否将请求短前导码传输

rate_idx_mask

用户请求的(传统)速率掩码

rate_idx_mcs_mask

用户请求的 MCS 速率掩码(如果未使用,则为 NULL)

bss

此帧是在 AP 还是 IBSS 模式下发送的

待定

本书的这一部分描述了 mac80211 的内部结构。

密钥处理

密钥处理基础

mac80211 中的密钥处理基于每个接口 (sub_if_data) 的密钥和每个站点的密钥完成。由于每个站点都属于一个接口,因此每个站点的密钥也属于该接口。

对于软件中实现的算法,硬件加速是尽力而为的,对于每个密钥,都会要求硬件启用该密钥以进行卸载,但如果硬件无法执行此操作,则该密钥将仅保留用于软件加密(除非它是用于软件中未实现的算法)。目前,除了查看 debugfs 之外,没有办法知道密钥是在 SW 还是 HW 中处理的。

所有密钥管理都在内部受到互斥锁的保护。在 mac80211 的所有其他部分中,密钥引用与 STA 结构引用一样,都受到 RCU 的保护。但是请注意,有些东西是不受保护的,即硬件加速函数中的 key->sta 解引用。这意味着 sta_info_destroy() 必须删除等待 RCU 宽限期的密钥。

更多内容待定

待定

接收处理

待定

发送处理

待定

站点信息处理

编程信息

enum ieee80211_sta_info_flags

站点标志

常量

WLAN_STA_AUTH

站点已通过身份验证。

WLAN_STA_ASSOC

站点已关联。

WLAN_STA_PS_STA

站点处于省电模式

WLAN_STA_AUTHORIZED

站点被授权发送/接收流量。始终检查此位,因此当不使用虚拟端口控制时,需要为所有站点启用此位。

WLAN_STA_SHORT_PREAMBLE

站点能够接收短前导码帧。

WLAN_STA_WDS

站点是我们的 WDS 对等方之一。

WLAN_STA_CLEAR_PS_FILT

当发送到此站点的下一个帧时,清除硬件中的 PS 筛选器(使用 IEEE80211_TX_CTL_CLEAR_PS_FILT 控制标志)。

WLAN_STA_MFP

此 STA 使用管理帧保护。

WLAN_STA_BLOCK_BA

用于在暂停/恢复和站点移除期间拒绝 ADDBA 请求(TX 和 RX)。

WLAN_STA_PS_DRIVER

驱动程序需要逻辑上将此站点保持在省电模式,以刷新可能仍在队列中的帧

WLAN_STA_PSPOLL

驱动程序将站点保持在省电模式时,站点发送了 PS-poll,当驱动程序解除阻塞时回复。

WLAN_STA_TDLS_PEER

站点是 TDLS 对等方。

WLAN_STA_TDLS_PEER_AUTH

此 TDLS 对等方被授权发送直接数据包。这意味着已启用链接。

WLAN_STA_TDLS_INITIATOR

我们是与此站点建立 TDLS 链接的发起者。

WLAN_STA_TDLS_CHAN_SWITCH

此 TDLS 对等方支持 TDLS 信道切换

WLAN_STA_TDLS_OFF_CHANNEL

本地 STA 当前与此 TDLS 对等方处于非信道状态

WLAN_STA_TDLS_WIDER_BW

此 TDLS 对等方支持在 BSS 基本信道上以更宽的带宽工作。

WLAN_STA_UAPSD

驱动程序将站点保持在省电模式时,站点请求了未计划的 SP,当驱动程序解除阻塞站点时回复。

WLAN_STA_SP

站点处于服务期间,因此请勿尝试回复其他 uAPSD 触发帧或 PS-Poll。

WLAN_STA_4ADDR_EVENT

已为此帧发送 4 地址事件。

WLAN_STA_INSERTED

此站点已插入到哈希表中。

WLAN_STA_RATE_CONTROL

已为此站点初始化速率控制。

WLAN_STA_TOFFSET_KNOWN

为此站点计算的 toffset 有效。

WLAN_STA_MPSP_OWNER

本地 STA 是网格对等方服务期间的所有者。

WLAN_STA_MPSP_RECIPIENT

本地 STA 是 MPSP 的接收方。

WLAN_STA_PS_DELIVER

站点已唤醒,但我们仍在阻止 TX,直到交付待处理的帧

WLAN_STA_USES_ENCRYPTION

此站点配置为加密,因此稍后删除所有没有密钥的数据包。

WLAN_STA_DECAP_OFFLOAD

此站点使用 rx 解封装卸载

NUM_WLAN_STA_FLAGS

定义的标志数量

描述

这些标志与struct sta_infoflags 成员一起使用,但仅通过 set_sta_flag() 和相关函数间接使用。

struct sta_info

STA 信息

定义:

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 *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;
#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;
    __le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1];
    u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
    struct airtime_info airtime[IEEE80211_NUM_ACS];
    u16 airtime_weight;
    struct sta_ampdu_mlme ampdu_mlme;
#ifdef CONFIG_MAC80211_DEBUGFS;
    struct dentry *debugfs_dir;
#endif;
    struct codel_params cparams;
    u8 reserved_tid;
    s8 amsdu_mesh_control;
    struct cfg80211_chan_def tdls_chandef;
    struct ieee80211_fragment_cache frags;
    struct ieee80211_sta_aggregates cur;
    struct link_sta_info deflink;
    struct link_sta_info __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
    struct ieee80211_sta sta;
};

成员

list

全局链表条目

free_list

用于跟踪要释放的站点的列表条目

rcu_head

用于释放此站点结构的 RCU 头

hash_node

rhashtable 的哈希节点

addr

站点的 MAC 地址 - 从公共部分复制,以便哈希表仅使用单个缓存行工作

local

指向全局信息的指针

sdata

此站点所属的虚拟接口

ptk

与此站点协商的对等密钥(如果有)

ptk_idx

最后安装的对等密钥索引

rate_ctrl

速率控制算法引用

rate_ctrl_priv

每个 STA 的速率控制私有指针

rate_ctrl_lock

用于保护速率控制数据的自旋锁(算法内部的数据,因此会序列化对该算法的调用)

lock

用于锁定所有需要锁定的字段,请参阅头文件中的注释。

fast_tx

TX 快速通道信息

fast_rx

RX 快速通道信息

mesh

网格 STA 信息

drv_deliver_wk

用于在驱动程序 PS 解除阻塞后传递帧

listen_interval

当我们将充当 AP 时,此站点的侦听间隔

dead

当 sta 被取消链接时设置为 true

removed

当 sta 正在从 sta_list 中移除时设置为 true

uploaded

当 sta 上传到驱动程序时设置为 true

sta_state

复制有关站点状态的信息(用于调试)

_flags

STA 标志,请参阅enum ieee80211_sta_info_flags,请勿直接使用

ps_lock

用于与省电相关的锁定(当 mac80211 是 AP 时)

ps_tx_buf

当站点离开省电状态或轮询时,要发送到此站点的帧的缓冲区(每个 AC)

tx_filtered

我们已经尝试发送但由于 STA 进入省电状态而被硬件过滤的帧的缓冲区(每个 AC),当站点离开省电状态或轮询帧时,这些帧也会传递到该站点

driver_buffered_tids

驱动程序在其上缓冲数据的 TID 的位图

txq_buffered_tids

mac80211 在其上缓冲 txq 数据的 TID 的位图

assoc_at

上次关联的时钟启动时间(以纳秒为单位)

last_connected

站点连接的时间(以秒为单位)

last_seq_ctrl

从此 STA 收到的最后一个 seq/frag 号(每个 TID 加一个非 QoS 帧)

tid_seq

用于发送到此 STA 的每个 TID 的序列号

airtime

描述此站点空口时间统计信息的每个 AC 的 struct airtime_info

airtime_weight

用于空口时间公平性计算的站点权重

ampdu_mlme

A-MPDU 状态机状态

debugfs_dir

调试文件系统目录条目

cparams

此站点的 CoDel 参数。

reserved_tid

保留的 TID(如果有,否则为 IEEE80211_TID_UNRESERVED)

amsdu_mesh_control

跟踪对等方使用的网格 A-MSDU 格式

  • -1:尚不知道

  • 0:非网格 A-MSDU 长度字段

  • 1:大端网格 A-MSDU 长度字段

  • 2:小端网格 A-MSDU 长度字段

tdls_chandef

TDLS 对等方可能具有与 BSS 兼容的更宽的 chandef。

frags

分段缓存

cur

聚合数据的存储区 struct ieee80211_sta 指向此处或 deflink.agg。

deflink

这是默认的链路 STA 信息,对于非 MLO STA,所有特定于链路的 STA 信息都通过 deflink 或通过指向 deflink 地址的 link[0] 访问。对于 MLO 链路 STA,第一个添加的链路 STA 将指向 deflink。

link

对链路 STA 条目的引用。 对于非 MLO STA,除了第一个链路,即 link[0] 之外,所有链路默认都将分配为 NULL,并将通过 deflink 或 link[0] 访问链路信息。 对于 MLO STA,添加的第一个链路 STA 将其链路指针指向 deflink 地址,剩余的将分配,并且该地址将分配给 link[link_id],其中 link_id 是 AP 分配的 ID。

sta

我们与驱动程序共享的站点信息

描述

此结构收集有关 mac80211 与之通信的站点的信息。

STA 信息生命周期规则

STA 信息结构体(struct sta_info)在一个哈希表中进行管理,以便快速查找,并在一个列表中进行迭代。它们使用 RCU 进行管理,即对列表和哈希表的访问受到 RCU 的保护。

使用 sta_info_alloc() 分配一个 STA 信息结构体后,调用者拥有该结构体。然后,它必须使用 sta_info_insert() 或 sta_info_insert_rcu() 将其插入到哈希表中;只有在后一种情况下(它获取一个 rcu 读取区,但不能从内部调用),指针在调用后仍然有效。请注意,调用者在插入 STA 信息之前不能对其进行太多操作;特别是,它不能启动任何网格对等链接管理或添加加密密钥。

当插入失败(sta_info_insert() 返回非零值)时,该结构体将被 sta_info_insert() 释放!

当您与对等方建立链接时,mac80211 会添加站点条目。对于我们支持的不同类型的接口,这意味着不同的事情。对于常规站点,这意味着当收到来自 AP 的关联响应时,我们会添加 AP sta。对于 IBSS,当我们在同一个 IBSS 上了解对等方时,会发生这种情况。对于 WDS,我们会在设备打开后立即添加对等方的 sta。当使用 AP 模式时,我们会根据来自用户空间通过 nl80211 的请求为每个相应的站点添加站点。

为了删除 STA 信息结构体,可以使用各种 sta_info_destroy_*() 调用。

在 STA 条目上没有所有权的概念;每个结构体都由全局哈希表/列表拥有,直到它被删除。该结构体的所有用户都需要受到 RCU 的保护,以便该结构体不会在他们完成使用之前被释放。

聚合函数

struct tid_ampdu_tx

TID 聚合信息 (Tx)。

定义:

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;
};

成员

rcu_head

用于释放结构的 rcu head

session_timer

检查我们是否在 TID 上保持 Tx (通过超时值)

addba_resp_timer

用于对等方对 addba 请求的响应的计时器

pending

挂起的帧队列 -- 使用 sta 的自旋锁来保护

sta

我们所连接的站点

state

会话状态 (见上文)

last_tx

上次 tx 活动的 jiffies

timeout

要在 ADDBA 请求中填充的会话超时值

dialog_token

聚合会话的对话令牌

stop_initiator

会话停止的发起者

tx_stop

停止时的 TX DelBA 帧

buf_size

接收器的重排序缓冲区大小

ssn

会话的起始序列号

failed_bar_ssn

上次失败的 BAR tx 尝试的 ssn

bar_pending

需要重新发送 BAR

amsdu

支持 A-MDPU 中的 A-MSDU

tid

TID 号

描述

此结构的生命周期由 RCU 管理,对持有它的数组的赋值必须持有聚合互斥锁。

如果状态设置了标志 HT_AGG_STATE_OPERATIONAL,则 TX 路径可以在 RCU 无锁情况下访问它。否则,TX 路径还必须获取自旋锁并重新检查状态,请参阅触摸它的 tx 代码中的注释。

struct tid_ampdu_rx

TID 聚合信息 (Rx)。

定义:

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;
};

成员

rcu_head

用于释放此结构的 RCU head

reorder_lock

序列化对重排序缓冲区的访问,请参见下文。

reorder_buf_filtered

位图,指示重排序缓冲区中存在应在释放帧时忽略的已过滤帧

reorder_buf

用于对传入的聚合 MPDU 进行重排序的缓冲区。MPDU 可以是具有单独报告的子帧的 A-MSDU。

reorder_time

添加 skb 时的 jiffies

sta

我们所连接的站点

session_timer

检查对等方是否在 TID 上保持 Tx (通过超时值)

reorder_timer

从重排序缓冲区中释放过期的帧。

last_rx

上次 rx 活动的 jiffies

head_seq_num

重排序缓冲区中的头部序列号。

stored_mpdu_num

重排序缓冲区中的 MPDU 数量

ssn

预期要聚合的起始序列号。

buf_size

传入的 A-MPDU 的缓冲区大小

timeout

重置计时器值(以 TU 为单位)。

tid

TID 号

auto_seq

用于卸载的 BA 会话,以自动选择 head_seq_and 和 ssn。

removed

此会话已删除(但可能由于 RCU 而被找到)

started

此会话已启动(已收到头部 ssn 或更高)

描述

此结构的生命周期由 RCU 管理,对持有它的数组的赋值必须持有聚合互斥锁。

reorder_lock 用于保护此结构的成员,除了 timeoutbuf_sizedialog_token,它们在结构的整个生命周期中是常量(对话令牌仅用于调试)。

struct sta_ampdu_mlme

STA 聚合信息。

定义:

struct sta_ampdu_mlme {
    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 wiphy_work 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;
};

成员

tid_rx

每个 TID 的 Rx 聚合信息 -- 受 RCU 保护

tid_rx_token

有效聚合会话的对话令牌

tid_rx_timer_expired

位图,指示在运行工作之前,哪些 TID 上的 RX 计时器已过期

tid_rx_stop_requested

位图,指示每个 TID 的哪些 BA 会话在运行工作之前,驱动程序请求关闭

tid_rx_manage_offl

位图,指示由于卸载而请求将哪些 BA 会话视为已启动/停止

agg_session_valid

位图,指示哪个 TID 上打开了 rx BA 会话

unexpected_agg

位图,指示哪个 TID 由于会话外与意外聚合相关的帧而发送了 delBA

work

用于启动/停止聚合的工作结构

tid_tx

每个 TID 的 Tx 聚合信息

tid_start_tx

请求启动的会话,不仅受 wiphy 互斥锁保护,还受 sta->lock 保护

last_addba_req_time

上次 addBA 请求的时间戳。

addba_req_num

已发送 addBA 请求的次数。

dialog_token_allocator

每个新会话的对话令牌枚举器;

同步函数

待定

锁定,大量的 RCU