12.1 Mac80211 Subsystem
在深入 Linux 内核的无线实现之前,我们需要先面对一个现实:无线网络和有线网络虽然都在 /etc/network/interfaces 里长得差不多,但在内核眼里,它们完全是两个物种。
你可能会觉得,不就是网卡吗?插上驱动,分配个 eth0 或 wlan0,能发包不就行了?
如果你真这么想,写驱动的时候会死得很惨。
无线网络不是一条「线」,它是一片混乱的空气。两个最核心的差异决定了它的复杂性:第一,你不能像以太网那样一边说话一边监听有没有撞车(半双工),你只能在说之前先听听有没有人说话(CSMA/CA,Collision Avoidance);第二,这空气里充满了干扰,微波炉、蓝牙邻居、隔壁老家的路由器都在抢通道。
所以在 Linux 内核里,无线网络不是以太网卡的一个简单变种,它有一套自己独立的、庞大的子系统——mac80211。
这就是本章的主角。但在完全展开这个子系统之前,让我们先回到它诞生之前的那段混乱岁月,看看为什么我们非得要这么一套复杂的东西。
旧时代的遗产:为了「能用」而付出的代价
把时钟拨回 1997 年。IEEE 发布了第一版 802.11 规范。那时候无线网卡还是稀罕物,到了 2001 年左右,笔记本电脑开始普及,WiFi 才逐渐成为标配。
那时候 Linux 社区面临巨大的压力:Windows 的无线驱动已经很成熟了,Linux 还是一片空白。正如当时的内核无线维护者 Jeff Garzik 所说:「他们只想让硬件动起来。」
在这种焦虑下,第一代 Linux 无线驱动诞生了。它们有两个特点:
- 没有统一架构:每个驱动都从零开始写,代码重复率极高。
- FullMAC 泛滥:为了偷懒,驱动开发者把大部分脏活累活(比如管理层的 MLME)都扔给了硬件固件去处理。
这就像造汽车时,因为不懂发动机原理,直接买了个成套的动力总成塞进去。能跑,但你也别想修它,更别想优化它。
但是,无线世界变了。新的协议 amendments(修正案)像雨后春笋一样冒出来:802.11a/b/g(物理层提速)、802.11e(QoS)、802.11i(安全)、802.11n(MIMO 高吞吐)……到了 2012 年,802.11 规范已经膨胀到 2793 页。
靠「让硬件自己搞定」的 FullMAC 方案,根本适应不了这种速度。Linux 社区意识到,必须把控制权拿回来。
于是,mac80211 诞生了。
它于 2007 年 7 月并入 Linux 2.6.22 内核,前身是一个叫 Devicescape 的公司开发的 d80211 栈(GPL 协议)。它的核心思想很简单:把通用的软 MAC 实现放进内核,驱动只负责和硬件打交道。
这不仅是技术的进步,更是话语权的转移——从固件闭源世界,夺回到了开源内核里。
MAC 层的本质差异:为什么不能直接复用以太网?
在 mac80211 的代码里,你会看到很多在以太网驱动里从未见过的东西。这不是为了炫技,是因为物理规则变了。
1. 从「撞车检测」到「撞车避免」
以太网用的是 CSMA/CD(Carrier Sense Multiple Access / Collision Detection)。这很直观:我说话的时候,如果听到有人也在说话(检测到冲突),我就停下来,大家随机退避一下再试。
但在无线世界里,这招行不通。
想象一下,你离 A 很近,离 B 很远。A 和 B 同时在说话,你能听到 A,但听不到 B(因为信号弱)。你以为信道空闲,开始说话——结果在 B 那里,你就成了干扰源。这就是「隐藏节点问题」。无线设备在发送时无法侦听信道(因为它自己的发射功率太大,盖住了所有信号),所以它根本无法检测冲突。
所以 802.11 采用了 CSMA/CA(Collision Avoidance)。重点在于 Avoidance(避免)。它在发送前要先侦听,并且引入了确认机制:我发给你,你必须回 ACK。如果没收到 ACK,我就默认撞车了,然后重传。
这机制听起来简单,但它意味着内核必须维护重传队列、定时器和状态机——这些在以太网里都是不需要操心的事。
2. 链路是不可靠的
在双绞线上,丢包是罕见事件。但在空气中,丢包是常态。微波炉一开,信号可能就掉了一半。
802.11 规范强制要求(除了广播和组播):每个收到的帧都必须回一个 ACK。如果 sender 发出一帧,在规定时间内没收到 ACK,它必须重传。
(注:从 802.11e 开始,引入了 QoSNoAck 模式可以不发 ACK,但在实际应用中,为了保证可靠性,这个模式很少被使用。)
这意味着你的无线驱动不仅仅是在「搬运数据」,它还在不停地进行握手。
FullMAC 与 SoftMAC:分界的抉择
在 mac80211 框架下,驱动通常分为两类,我们在本章后续会反复提到这个区别:
- FullMAC 驱动:硬件自己处理大部分 MAC 层管理功能(MLME),比如扫描、认证、关联。内核驱动非常「薄」,只负责数据包的发送和接收。这类驱动写起来简单,但很难利用新特性,因为很多逻辑在闭源固件里。
- SoftMAC 驱动(基于 mac80211):硬件只负责收发原始波形(或者稍微处理一下物理层头),所有的 MAC 层逻辑——组帧、解析、加密、重传——都由内核里的 mac80211 完成。这是目前 Linux 主流的方向。
mac80211 子系统就是为 SoftMAC 驱动准备的舞台。
在这个舞台上,内核不再是一个被动的数据搬运工,它必须理解 802.11 协议的每一个细节。这带来了复杂度,但也带来了无与伦比的灵活性和控制力——这正是我们所追求的。
现在,舞台已经搭好,让我们来看看台上的布景——802.11 的帧格式和拓扑结构,是如何在这套子系统里被呈现出来的。