12.7 High Throughput (802.11n) —— 高速公路的入场券
上一节我们聊完 mac80211 的骨架和肌肉时,我提到了无线世界不仅需要「通」,更需要「快」。
如果你用过 2005 年之前的 Wi-Fi,你应该记得那种感觉:连上是连上了,传个大文件能把人急死。
问题不在于信号强弱,而在于物理规则的天花板。
这就到了 802.11n 登场的时候了。 这一节,我们要看它是如何打破这个天花板的。
1. 提速的代价:MIMO 和多天线
在 802.11g 刚获批没多久,IEEE 里面就成立了一个「高吞吐量任务组」(TGn),目标很明确——把无线网搞成光纤的速度。 这一搞就是好几年,直到 2009 年才正式定稿。
但在标准正式发布之前,厂商早就按捺不住了。 Broadcom 开了个先河:他们在 2003 年就发布了基于 802.11g 草案的芯片。 既然有先例,到了 2005 年,市面上就开始出现基于 802.11n 草案的设备了。 Intel 的 Santa Rosa 平台里的 Intel WiFi Link 5000 系列,以及 4965AGN,都算是那个时代的「超前体验」。 Atheros 和 Ralink 也没闲着。 到了 2007 年 6 月,Wi-Fi 联盟甚至开始给这些草案 2.0 的设备发证书。 可以说,这是一场「草台班子」先把产品做出来,标准组织在后头追的游戏。
频段与 MIMO
802.11n 和前辈们最大的不同在于它的野心——它同时霸占了 2.4 GHz 和 5 GHz 两个频段。 相比之下,11b/g 只能在 2.4 GHz 这个拥堵的菜市场里挤,11a 虽然在 5 GHz,但兼容性一般。
但光换频段是不够的。 802.11n 引入了一个核心杀手锏:MIMO(Multiple Input, Multiple Output,多输入多输出)。
这个技术的原理其实并不复杂,但效果拔群: 它在 AP 和客户端两边都装上了多根天线。 这就像以前是你一张嘴喊,我一只耳朵听; 现在是你三四张嘴一起喊,我三四只耳朵同时听,而且每张嘴喊的还不太一样,我这边还能通过算法把它们区分开。
这就带来了两个直接的好处:
- 距离更远:通过多天线的信号合并,可靠性大幅提升。
- 速度更快:理论上,802.11n 的物理层速率能飙到 600 Mbps。 当然,实际上你是跑不到这个数的,毕竟还要扣除介质访问的开销、干扰、协议头……但比起以前的 54 Mbps,这已经是质的飞跃了。
2. 打包的艺术:Packet Aggregation
除了在物理层上堆天线,802.11n 还在 MAC 层动了大手术。 这就像你以前寄信都是一封一封寄,信封本身就有成本;现在改成了寄一本厚书,把一百封信塞进一个包裹里一次性发走。
这个技术叫 Packet Aggregation(数据包聚合)。 它把好几个应用层的数据包塞进一个传输帧里发出去。 为了配合这个机制,802.11e 修正案引入了 Block Acknowledgment(块确认,简称 BA)。
以前发一个包要等一个 ACK,发十个包就要等十个 ACK。 有了 BA 之后,你可以发一堆包,然后对方回一个 BA 就说:「刚才那十个我都收到了」。 中间那种傻等的间隔被砍掉了,效率自然就上来了。
这里有两种聚合方式,千万别搞混:
- A-MSDU (Aggregated MAC Service Data Unit):
把好几个 MSDU(也就是上层下来的数据包)捏在一起,外面只包一个 MAC 头。
⚠️ 注意:在
mac80211里,A-MSDU 只在接收方向支持,发送方向是不支持的。 而且它不依赖我们要讲的 Block Ack 机制。 - A-MPDU (Aggregated MAC Protocol Data Unit): 这才是本节的主角。 它是把好几个已经包好 MAC 头的完整 MPDU 打包在一起。 它必须配合 Block Ack 机制使用。 我们接下来要讲的,全是关于 A-MPDU 的故事。
3. 握手:建立 Block Ack 会话
Block Ack 不是你想开就能开的,这得先办个手续。 这个过程涉及两方:发起者 和 接收者。 每个 Block Ack 会话都绑定在一个特定的 TID(Traffic Identifier,流量标识符) 上。
第一步:发起请求
一切始于驱动里的速率控制算法。
比如拿 ath9k 驱动来说,它的 ath_tx_status() 函数(在 drivers/net/wireless/ath/ath9k/rc.c 里)会在合适的时候调用 ieee80211_start_tx_ba_session()。
这个函数干了两件事:
- 把状态标记为
HT_ADDBA_REQUESTED_MSK(正在请求中)。 - 调用
ieee80211_send_addba_request()发送 ADDBA Request 帧。
这个请求帧里带着两个关键参数:
- Buffer Size:重排序缓冲区的大小。
这个值是有上限的,最大不能超过 64K(见
ieee80211_max_ampdu_length_exp)。 这个参数塞在struct addba_req的capab成员里发出去。 - TID:标识这是哪一股流量。
第二步:倒计时与响应
请求发出去之后,倒计时就开始了。
留给对方响应的时间是 1 秒(定义里的 ADDBA_RESP_INTERVAL)。
这是个硬性规定。
如果在 x86_64 上跑过了 1 秒还没收到回音,sta_addba_resp_timer_expired() 这个回调就会被触发。
它会毫不留情地调用 ___ieee80211_stop_tx_ba_session(),把这场会话掐死在摇篮里。
如果对方收到了 ADDBA 请求,流程是这样的:
- 先回一个 ACK: 这和所有 802.11 帧一样,规矩不能坏。
- 处理请求:
调用
ieee80211_process_addba_request()。 如果一切顺利,它会把自己的状态设为HT_AGG_STATE_OPERATIONAL(开始干活)。 - 发送 ADDBA Response:
调用
ieee80211_send_addba_resp()告诉对方:「成交,参数我收到了」。 - 关掉定时器:
调用
del_timer_sync()把刚才那个 1 秒的倒计时炸弹拆了。
第三步:发包与 BAR
握手完成后,狂欢就开始了。 发起者会把一大包数据(包含多个 MPDU 的 A-MPDU)呼啸着发过去。 发完这一波之后,为了确认对方真的收到了,它需要发送一个 Block Ack Request (BAR)。
这是通过调用 ieee80211_send_bar() 方法完成的。
4. BAR:催命符
Block Ack Request (BAR) 是一种控制帧。
它的子类型是 IEEE80211_STYPE_BACK_REQ。
你可以把它理解为发起者拍着接收者的肩膀问:「刚才发过去那一大坨,到底收齐了没?」
这个包里最重要的信息是 SSN (Start Sequence Number,起始序列号)。 它告诉接收者:「从这个序号开始的那一批包,我要确认」。 接收方收到 BAR 后,会去检查自己的 ampdu 缓冲区,如果需要重排就整理一下。
来看看 BAR 长什么样(内核里的结构体 struct ieee80211_bar):
struct ieee80211_bar {
__le16 frame_control;
__le16 duration;
__u8 ra[6]; /* 接收者地址 */
__u8 ta[6]; /* 发送者地址 */
__le16 control; /* 包含 TID 等信息 */
__le16 start_seq_num; /* 起始序列号 SSN */
} __packed;
(include/linux/ieee80211.h)
在这里,帧控制里的类型是 IEEE80211_FTYPE_CTL,子类型是 IEEE80211_STYPE_BACK_REQ。
ra 是接收者的 MAC 地址,ta 是发送者的。
control 字段里藏着 TID。
start_seq_num 自然就是那个 SSN。
5. Block Ack:两种确认方式
收到 BAR 之后,接收方必须回一个 Block Ack (BA)。 这里有两种策略,取决于当时的硬件能力和协议配置:
- Immediate Block Ack(立即块确认): 收到 BAR 后,立马回 BA。 不拖泥带水,性能最好,但对处理速度要求高。
- Delayed Block Ack(延迟块确认):
这种方式比较从容:
- 先给 BAR 回一个普通的 ACK。
- 等一会儿,处理完了,再发 BA。 这适合那种软件处理能力有限、需要一点缓冲时间的场景。
当然,BA 帧本身也是需要被确认的。
曲终人散:DELBA
天下没有不散的筵席。
当发起者没数据发了,或者想结束这场会话,它会调用 ieee80211_send_delba() 发送 DELBA 请求。
对方收到后,通过 ieee80211_process_delba() 处理,并把这套 Block Ack 会话拆掉。
这个 DELBA 包,谁都能发——不管是发起者还是接收者,想离场随时能提。
6. 限制与边界
最后,有几个硬性的边界你得心里有数:
- 最大长度:A-MPDU 的最大长度是 65535 字节。
- 模式限制:数据包聚合只支持 AP 模式 和 Managed 模式(客户端)。 如果你用 IBSS(Ad Hoc)模式,别想了,规范里压根没支持这个。
这一套机制下来,无线网络才真正有了「高速」的样子。 但别忘了,这只是高速公路的规则之一。 下一节,我们将进入另一个更复杂的拓扑世界——Mesh Networking (802.11s)。 在那里,路由和传输的逻辑会纠缠在一起,形成一张更复杂的网。