ch12_5
12.5 MAC 层管理实体 (MLME)
上一节我们聊了「睡觉」的事——客户端怎么睡,AP 怎么帮忙守着包。但这里有一个前提:在睡觉之前,客户端得先确信自己找对了「枕头」(AP),而且这个「枕头」允许它靠上去。
这种信任关系的建立,以及日常的维护(比如我想换个 WiFi,或者我在房间里走动想换个信号更强的 AP),都不属于数据传输的范畴,而是属于管理层的事。
在 802.11 的宏大架构里,管理任务被分给了三座大山:物理层管理实体 (PLME)、系统管理实体 (SME),以及我们要重点讨论的 MAC 层管理实体 (MLME)。
这一节,我们把目光从数据包的搬运上移开,看看 MLME 是如何像一个繁忙的接线员一样,处理扫描、认证、关联以及漫游这些琐事的。
12.5.1 扫描:寻找空气中的信号
想象你带着收音机走进一个深山老林,你想知道有没有电台广播。你有两种办法:
一种是静静地听。你调到一个频段,听有没有声音,没有就换下一个。 另一种是大声喊。你调到一个频段,对着麦克风喊「有人吗?」,如果有人听到,他就会回你一句「有」。
在无线网络里,这就是 Passive Scanning (被动扫描) 和 Active Scanning (主动扫描) 的区别。
被动扫描
有些频段——特别是 5GHz 的高端频段(雷达常出没的地方)——法律是禁止你乱说话的。你不能一上来就发 Probe Request,那是违法的。你只能闭上嘴,把耳朵竖起来。
在 mac80211 里,当扫描请求的标志位包含了 IEEE80211_CHAN_PASSIVE_SCAN 时,驱动就会进入这种「静默聆听」模式。
站点会一个频道接一个频道地跳(Channel Hopping),在每个频道上停留一小会儿,等待接收 Beacon 帧。
因为 Beacon 是 AP 周期性广播的「心跳」,只要 AP 在,你迟早能听到。
主动扫描
在家里或办公室这种普通的 2.4GHz/5GHz 频段,时间就是金钱。等待 Beacon 周期太慢了,我们通常会主动出击。
主动扫描的逻辑很简单,甚至有点粗暴:
- 跳到一个频道。
- 大喊一声:「谁是 AP?」(发送 Probe Request 帧)。
- 听一秒钟,看谁喊回来(接收 Probe Response)。
- 没人理就换下一个频道,重复上述过程。
在内核代码里,这一连串动作是由 ieee80211_request_scan() 方法触发的。
而那个「大喊一声」的动作,具体是由 ieee80211_send_probe_req() 完成的。
这个函数会构造一个管理帧,其帧控制子类型被设置为 IEEE80211_STYPE_PROBE_REQ。
在这个过程中,切换频道 是个技术活。
它不是改个变量那么简单,而是要告诉硬件去调整无线电的频率。这是通过调用 ieee80211_hw_config() 方法实现的,并传入参数 IEEE80211_CONF_CHANGE_CHANNEL。
⚠️ 这里有个容易混淆的概念
我们在上层应用(比如 wpa_supplicant)里常说「Channel 6」,但在硬件驱动眼里,它只知道「Frequency 2.437 GHz」。
这是一一对应的映射关系。
内核里有一个专门的函数 ieee80211_channel_to_frequency() (位于 net/wireless/util.c) 负责把人类可读的频道号翻译成硬件懂的频率。
如果你在写驱动时直接把 Channel 6 塞给寄存器,硬件只会一脸懵逼地看着你。
12.5.2 认证:最初的握手
现在,假设通过扫描,你的客户端发现了一个信号很好的 AP。它想连接过去。 但在允许它发送数据之前,802.11 协议要求先进行一个形式上的流程:认证。
注意,认证不等于加密。 现在的 WiFi 网络(WPA2/WPA3)里的「加密密钥协商」其实是发生在四步握手 (4-Way Handshake) 阶段的。 而这里说的 MLME 层面的「认证」,更像是「敲门问好」。
内核里负责这步的是 ieee80211_send_auth() 方法 (在 net/mac80211/util.c 中)。
它会发送一个管理帧,子类型为 IEEE80211_STYPE_AUTH。
开放系统认证
最古老的 802.11 标准定义了两种认证算法。其中一种被强制要求支持的,叫做 Open System Authentication (开放系统认证),对应宏 WLAN_AUTH_OPEN。
这可能是世界上最虚伪的安全机制。 它的流程是这样的:
- 客户端:「我想认证。」
- AP:「通过。」 是的,只要你是个人类(或者机器),发送请求,AP 就会让你通过。这就是所谓的「Null Authentication」。 虽然在安全上它等于零,但它是协议流程的必经之路。哪怕你后面要用 WPA2 加密,第一步也得先走这个「开放系统认证」把状态机推过去。
共享密钥认证
另一种古老的方法是 Shared Key Authentication (共享密钥认证),对应宏 WLAN_AUTH_SHARED_KEY。
这就涉及到 WEP (Wired Equivalent Privacy) 那个已经被证明不仅烂而且漏洞百出的加密标准了。
流程大概是 AP 发个挑战码,客户端用 WEP 密钥加密回去,AP 验证正确性。
因为 WEP 已经被彻底淘汰,这种认证方式在现代驱动里更多是「我知道它的存在,但我尽量不碰它」。
12.5.3 关联:建立正式连接
认证通过后,客户端和 AP 算是「认识了」。 但要真正传输数据,客户端还得发起 Association (关联)。
你可以把「认证」理解为见面握手,把「关联」理解为入座登记。 只有关联成功,AP 才会给你分配资源,把你加入它的内部表格,告诉交换机这个 MAC 地址在我的无线端口里。
这一步由 ieee80211_send_assoc() 方法 (在 net/mac80211/mlme.c) 完成。
它发送一个管理帧,子类型为 IEEE80211_STYPE_ASSOC_REQ。
这个帧里包含了很多关键信息:客户端支持哪些速率、支持哪些 802.11n/ac/ax 特性、要不要省电等等。
AP 收到后,会回复 Association Response,里面如果带有一个状态码 0,表示成功。
12.5.4 漫游:换个 AP 继续用
作为用户,你肯定遇到过这种事:你在客厅连着路由器 A,走到卧室,信号变弱了,但系统自动切到了路由器 B(或者同一个路由器的另一个频段),中间网络几乎没有断开。
这就是 Roaming (漫游)。
漫游本质上发生在两个 AP 之间(属于同一个 ESS,即同一个 SSID)。 当你的客户端发现当前 AP 的信号质量差到无法忍受,或者周围出现了另一个信号更好的 AP 时,它会决定「跳槽」。
这个过程叫 Reassociation (重新关联)。
在内核里,复用了 ieee80211_send_assoc() 这个函数。
为什么?因为「关联」和「重新关联」99% 的内容是一样的——都要发能力集、都要等回复。
唯一的区别在于帧的子类型是 IEEE80211_STYPE_REASSOC_REQ,并且在这个请求帧里,客户端会带上一个额外的信息:我上一个连的 AP 叫啥 (BSSID)。
这个信息非常重要。 这就好比你告诉新东家:「我刚从老东家那边离职,这是我的离职证明。」 新的 AP 会拿着这个地址去查表,发现是同一个网络里的兄弟,就会去老 AP 那里把你的缓存数据(比如你睡觉时没取走的包)同步过来,实现无缝切换。
如果一切顺利,新 AP 会回复 Reassociation Response,并顺便分配一个新的 AID (Association ID)。
拿到这个 AID,你就正式在这个新地盘落脚了。
这一节,我们像是搬着板凳看了场戏。 看客户端怎么像个雷达一样扫描频道,怎么毫无防备地进行「开放认证」,怎么正式入座关联。 这是 MLME 作为管理层的日常——琐碎,但缺一不可。
现在,我们已经有了数据传输的基础(TX/RX),也有了生命周期的管理(Power Save, MLME)。
接下来,我们将深入 mac80211 的内核实现细节,看看那些支撑起整个无线框架的核心数据结构。
如果不去看看 ieee80211_hw 和 sta_info 长什么样,你对 Linux 无线栈的理解就永远是隔着一层纱。