BLOCK ACK方式概述
接收端对帧接受情况进行确认的方式有整体确认和分别确认。整体确认是对所有MPDU的接收状态进行确认,而分别确认可对各个子帧进行检查分别确认。与整体确认的方式相比,在分别确认机制中每个FCS检测的数据长度变短,检测到误码的概率便随之降低,进而提高数据传输的成功率。
之前的反馈机制是发送一个数据帧必须等待一个ACK,这样增大了开销,降低了信道的利用率。802.11N提出的块确认(Block Acknowledgement,BA)机制,检查A-MPDU的所有MPDU均包含的FCS,通过BA 帧中包含的BA 位图(bitmap),指示每一个MPDU 的接收状态(一一对应),BA位图中的第一个比特对应指示BA 起始序列控制字段中第一个序列号(sequence number,SN) 的MSDU 的接收状态,以此类推。
发送方若没有收到应答帧BA,则认为AMPDU 中所有子帧发送失败,MAC 需要重传发送失败的子帧;若收到BA,则MAC 可以清除BA 成功应答的子帧,继续重传没有应答的子帧。
BLOCK ACK处理方式
根据对Block ACK Req帧和Block ACK帧的不同处理方式,块确认可分为立即块确认和延迟块确认。
立即块确认中,发送端要求接收端即时回应Block ACK帧;延迟块确认时,接收端通过ACK帧来表明对A-MPDU帧或Block ACK Req帧的正确接收,Block ACK帧则在另外的信道接入机会中被返回,并需要发送端再发送一个ACK帧进行确认。另外,如果发送端和接收端均己经默认采用BlockACK机制进行数据的确认,那么便可以免去BlockACKReq帧的发送。
在802.11n标准中一般情况下默认使用立即块确认,而延迟块确认属于可选项,用户可以根据需要来设定使用哪一种块确认方式。
BLOCK ACK机制的建立流程
收发双方通过Beacon, Association/Reassociation Request/Response 帧交互双方的块确认的能力。
-
当发送端决定采用A-MPDU机制发送数据时,需要首先发送一个“ADDBA request”给接收端;
-
接收端正确收到“ADDBA request”后,先响应一个ACK,后会发送一个“ADDBA response”给发送端;
-
发射端正确收到“ADDBA response”,相应一个ACK;
-
发送端和接收端便开始数据的交互;
-
发送端在每发完一个A-MPDU帧后,会紧接着发送一个BlockACKReq帧;
-
收端则以Block ACK帧进行响应,以实现对A-MPDU帧中的各个子帧的确认;
-
发送端MAC层决定终止使用A-MPDU机制时,需要向接收端发送一个"DELBA请求”,接收端则发送一个ACK帧作为确认。
注意,当双方发现有预期的ACK没有收到的时候,会重发ADDBA request/response。
帧格式和内容
ADDBA request 和ADDBA response
主要字段 | 意义 | 取值 |
---|---|---|
DialogToken | ADDBA业务ID | 0-255 |
Block Ack Policy | 决定了接收端是采用立即块确认还是延迟块确认。 | immediate block ack或者delayed block ack |
TID | Traffic ID即传输流标识号 | 0–15 |
Buffer Size | 应答方允许有多少帧缓存(每个错序的包之后的包都缓存着并没有发送到LLC),意思就是数据发送方请求一个block ack之前不允许有这么多buffer size的包未解决(未上传LLC)。 | 023。如果是数据发送方设置这个值,则是个期望值;需要结合数据接收方配置的值一起考虑。 |
A-MSDU Supported | DBA Request里,指示了发送数据方在BA这段时间发送A-MSDU的能力;在ADDBA Response里,指示了接收数据方在BA这段时间接收A-MSDU的能力;显然需要双方都支持才会真的发送 | 支持;0:不支持 |
block Ack | Timeout Value | block ack超时的门限。超时后BLOCK ack的链接流程终止 0 – 65 535 |
Sequence Number (SSN) | 发送方的第一个数据帧的序列号(SN) |
Qos frame
- 发送方:
在BA建立后,数据发送方可以传输一块Qos data frame,要么是一个个单独的burst由SIFS/RIFS分开,要么是A-MPDU的一部分。数据块可以在单独一个TXOP里完整发完或者多个TXOP里发。
每个Qos data frame里都有Ack Policy field告知接收方Block Acknowledgement的发送方法。
- 接收方:
维护一个scoreboard追踪MPDU的接收情况。
BlockACKReq
发完数据后发送BAR 帧,包含的SSN指示了需要对端反馈接收情况的最老的MSDU的序列号SN。
BlockACKReq帧由四部分组成,分别为MAC header,BAR Control域、BAR Information域和FCS。
其中BAR ControlControl域决定了BlockACKReq帧的属性和块确认的方式。
- BAR ACK Policy:
决定了接收端是采用立即块确认还是延迟块确认。
- Multi-TID和Compressed Bitmap:
共同决定了三种不同的块确认实现方式,即不同的BlockACKReq帧帧格式,包括Basic BlockACKReq,Compressed BlockACKReq和Multi-TID BlockACKReq。
Multi-TID | commpressed Bitmap | Block ACK type |
---|---|---|
0 | 0 | Basic BlockACKReq |
0 | 1 | Compressed BlockACKReq |
1 | 0 | Reverved |
1 | 1 | Multi-TID BlockACKReq |
- GCR
- TID_INFO
不同BlockACKReq帧格式TID_INFO字段和BAR Information字段的含义也不相同
其中Basic BlockACKReq和Compressed BlockACKReq具有相同的帧格式,TID_INFO字段负责记录数据的TID,BAR Information字段的格式如图。
其中表示分段个数的Fragment Number字段被置0,Starting Sequence Number字段记录了即将被发送的A-MPDU帧中的第一个MPDU的序号。
- 对于Multi-TID BlockACKReq帧,TID_INFO字段的内容为聚合帧中出现的TID的数量。此时BA Information字段的格式如图。
Multi-TID BlockACKReq帧的BA Information子域由数个重复出现的per TID InfO、Fragment Number以及Starting SequenceNumber组成,Per TID Info记录了该TID的值,Fragment Number字段被置0,Starting Sequence Number字段记录了同一TID中第一个MPDU的序号。
Block ACK
接收机接收到BAR后要做两件事:
-
准备一个BA response将数据接收情况转换为bitmap,其中第一个bit和BAR里的SSN对应,之后的bit则是连续的SN接收情况。
-
检查乱序缓存里的MPDU的SN,如果在BAR里的SSN之前,这些MPDU要么重新组装成完整的MSDU并转发到高层,或者无法组装成完整MSDU时就把该MSDU弃掉。
Block ACK帧由四部分组成,分别为MAC头部、BA Control、BA Information和FCS。
BA Control字段决定了Block ACK帧的具体帧格式和属性,其格式如图
BA ACK Policy字段决定了块确认的策略,即立即块确认和延迟块确认。
Multi-TID字段和Compressed Bitmap字段共同决定了三种不同的块确认方式,即不同的Block ACK帧格式,包括Basic BlockACK、compressed Block ACK、Multi-TID Block ACK。
不同的BlockACK帧格式中,TID_INFO字段和BA Information字段具有不同的含义。
- 在基本块确认(Basic BlockACK)机制下,TID_INFO字段记录了数据的TID。BA Information子域由BASSC和Bitmap组成。
Block Ack
Starting Sequence Control(BASSC)字段给出了聚合帧中第一个MPDU的序号;Block ACK Bitmap字段负责记录聚合帧的子帧是否被正确接收 ,该字段的第n个比特标志着序号为BASSC+n的MSDU是否被正确接收。若该比特为1,则表示MPDU被正确接收,否则表明该MPDU中有误码存在。
- 在压缩块确认(Compressed BlockACK)机制下,TID_INFO字段记录了数据的TID BA Information的格式如图所示。
该机制的最大特点便是采用了压缩的BlockACK Bitmap,即采用64个比特对聚合帧进行确认。各MSDU与Bitmap中的比特数据依据先后顺序一一对应。若MPDU被正确接收,则将比特位置1,否则置0。由于只有64个比特位,因此聚合帧最多只能包含64个子帧。
- 在多TID(Multi-TID)块确认机制下,TIDINFO字段记录的内容为该聚合帧中出现的TID的数量。BA Information的格式如图所示。
对于拥有相同TID的MPDU子帧,依然按照压缩块确认的方式对各个子帧进行确认。
DELBA
数据发送方发现没有数据要发了并且最后的block ack交互完成了,会发送DELBA关闭BA对话。接收方收到后反馈ACK并把该BA对话的资源释放掉。
另外,BA对话期间任意BA, BAR, or QoS Data frame没有接收到而超时到block ack timeout,也会关闭BA对话。
接收端重排序
接收端的重排序缓存区(reorder buffer)缓存MPDU,当从reorder buffer 开头开始的MPDU可以组装成完整MSDU时,就把该完整的MSDU发往LLC;那么当中间出现某个MPDU没收到导致整个MSDU无法组装,那么MPDU就会一直缓存,缓存个数与ADDBA req/repsonse里设置的Buffer Size有关。此时当buffer满了,那么reorder buffer里的第一个MSDU就要被丢弃(因为该MSDU不完整)。
当收到BAR,BAR里有SSN,所有序列号低于该SSN的完整的MSDU将发往LLC;所有序列号低于该SSN的不完整的MSDU将被丢弃。
上图中,MSDU1的分段1.0和1.1接收成功因此可以组装完整MSDU1,可以发往LLC;
MSDU2的分段2.0接收成功而2.1接收失败因此不可以组装完整MSDU2,因此接收机必须缓存2.0直到可以组装完整MSDU2;
后面的MSDU3可以组装完整,但是因为MSDU2不完整所以也被放在缓存区;
…
发送方BAR 要求SSN=1开始的接收情况;
BAR/BA交互后,发送方重新发送以后未发送成功的分段,并BAR要求SSN=2开始的接受情况;
MSDU2的分段接收成功后,接收方把MSDU及后面的完整MSDU转发到LLC。
每个包有自己的生命周期,结合上文提到的通过BAR将包丢弃的操作。
这里就要提及BAR帧两个功能:
- 请求一个BA response
- 清空接收缓存里早期的不完整的MSDU。当发射机发现某个MSDU的ACK迟迟没有收到,最终该MSDU的生命期超时,发射机决定丢弃该MSDU,若不通知接收方,接收方的重拍缓存就一直无法把后面的完整包发送到LLC,即形成一个缺口。为了通知接收方,发射方发送一个BAR去跳过该失败MSDU,将之后的成功的完整的MSDU转发到LLC。
如下图所示,MSDU3多次重传后都未能成功,其生命期超时后,发送方丢弃了MSDU3,并发送一个大于3的SSN,一般是最新一个未发送SSN,如这里因为MSDU4~7已经发送成功,因此SSN=8。
因此 BA下数据接收端只有在数据帧接收成功,才会将该是帧及之后连续接收成功的数据帧上传到LLC,否则会一直放置在缓存中,一定时间后包会被丢弃。所以我们需要考虑设置一个合理的重传次数,否则会导致在BLOCK ACK机制中重传次数过多而导致接收缓存溢出。