跳到主要内容

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 和客户端两边都装上了多根天线。 这就像以前是你一张嘴喊,我一只耳朵听; 现在是你三四张嘴一起喊,我三四只耳朵同时听,而且每张嘴喊的还不太一样,我这边还能通过算法把它们区分开。

这就带来了两个直接的好处:

  1. 距离更远:通过多天线的信号合并,可靠性大幅提升。
  2. 速度更快:理论上,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()

这个函数干了两件事:

  1. 把状态标记为 HT_ADDBA_REQUESTED_MSK(正在请求中)。
  2. 调用 ieee80211_send_addba_request() 发送 ADDBA Request 帧。

这个请求帧里带着两个关键参数:

  • Buffer Size:重排序缓冲区的大小。 这个值是有上限的,最大不能超过 64K(见 ieee80211_max_ampdu_length_exp)。 这个参数塞在 struct addba_reqcapab 成员里发出去。
  • TID:标识这是哪一股流量。

第二步:倒计时与响应

请求发出去之后,倒计时就开始了。 留给对方响应的时间是 1 秒(定义里的 ADDBA_RESP_INTERVAL)。 这是个硬性规定。

如果在 x86_64 上跑过了 1 秒还没收到回音,sta_addba_resp_timer_expired() 这个回调就会被触发。 它会毫不留情地调用 ___ieee80211_stop_tx_ba_session(),把这场会话掐死在摇篮里。

如果对方收到了 ADDBA 请求,流程是这样的:

  1. 先回一个 ACK: 这和所有 802.11 帧一样,规矩不能坏。
  2. 处理请求: 调用 ieee80211_process_addba_request()。 如果一切顺利,它会把自己的状态设为 HT_AGG_STATE_OPERATIONAL(开始干活)。
  3. 发送 ADDBA Response: 调用 ieee80211_send_addba_resp() 告诉对方:「成交,参数我收到了」。
  4. 关掉定时器: 调用 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_REQra 是接收者的 MAC 地址,ta 是发送者的。 control 字段里藏着 TID。 start_seq_num 自然就是那个 SSN。


5. Block Ack:两种确认方式

收到 BAR 之后,接收方必须回一个 Block Ack (BA)。 这里有两种策略,取决于当时的硬件能力和协议配置:

  1. Immediate Block Ack(立即块确认): 收到 BAR 后,立马回 BA。 不拖泥带水,性能最好,但对处理速度要求高。
  2. 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)。 在那里,路由和传输的逻辑会纠缠在一起,形成一张更复杂的网。