# 第4章 MAC 帧格式
所有 LoRa 上下行消息都会携带 PHY 载荷(Payload),PHY载荷以单一八位字节 MAC 头(MHDR)开始,紧接着 MAC 载荷(MACPayload)[1],最后是4字节的消息校验码(MIC)。
- 射频PHY层:
Preamble | PHDR | PHDR_CRC | PHYPayload | CRC |
- PHY载荷:
MHDR | MACPayload | MIC |
或
MHDR | Join-Request 或 Rejoin-Request | MIC |
或[2]
MHDR | Join-Accept |
- MAC载荷:
FHDR | FPort | FRMPayload |
- FHDR:
DevAddr | FCtrl | FCnt | FOpts |
# 4.1 MAC层
MAC 层(PHYPayload)
Size (bytes) | 1 | 7..M | 4 |
PHYPayload | MHDR | MACPayload | MIC |
MACPayload字段的最大长度M,在第6章有详细说明。
# 4.2 MAC头
MAC 头(MHDR字段)
Bit# | 7..5 | 4..2 | 1..0 |
MHDR bits | MType | RFU | Major |
MAC 头中指定了消息类型(MType),以及根据 LoRaWAN 层规范中已经过编码的帧格式的主版本号(Major)。
# 4.2.1 消息类型
消息类型(MType 位字段)
LoRaWAN 区分八种 MAC 消息类型:Join-request, Rejoin-request, Join-accept, unconfirmed data up/down, confirmed data up/down,以及 proprietary 协议消息。
MType | 描述 |
000 | Join Request |
001 | Join Accept |
010 | Unconfirmed Data Up |
011 | Unconfirmed Data Down |
100 | Confirmed Data Up |
101 | Confirmed Data Down |
110 | Rejoin-request |
111 | Proprietary |
# 4.2.1.1 入网请求和接受消息
join-request、Rejoin-request 和 join-accept 都是用在空中激活(OTAA)流程中,具体见章节6.2,以及用于漫游。
# 4.2.1.2 数据消息
Data messages 用来传输 MAC 指令数据和应用数据,这两种数据也可以合并在单个消息中发送。Confirmed-data message 接收者需要(MUST)应答,Unconfirmed-data message 接收者则不需要应答[3]。 Proprietary messages 用来处理非标准的消息格式,不能和标准消息互通,只能用来和对于专有扩展具有共识的设备间进行通信。当终端设备或网络服务器收到未知的专有消息类型时,应当(SHALL)静默丢弃。
消息完整性的保证根据消息类型所采用的方式不同,下面会具体介绍。
# 4.2.2 数据消息的主版本
主版本(Major 位字段)
Major位字段 | 描述 |
00 | LoRaWAN R1 |
01..11 | RFU |
注意:主版本号定义了连接过程(join procedure,见章节6.2)和 MAC Payload 的前4字节(见第4章)使用的消息格式。终端可实现不同的次版本号消息格式。必须事先使用带外消息(即,作为设备个性化信息的一部分)使网络服务器知道终端设备使用的次要版本。当设备或网络服务器收到携带未知或不受支持的 LoRaWAN 版本的帧时,应当(SHALL)静默丢弃。
# 4.3 数据消息的 MAC 载荷
数据消息的 MAC 载荷(MACPayload),包含一个帧头(FHDR)、可选的端口字段(FPort)以及可选的帧载荷(FRMPayload)。
当一个帧具有有效 FHDR,但没有 Fopts(FoptsLen = 0)、Fport 和 FRMPayload,这样的帧也是有效帧。
# 4.3.1 帧头
帧头 FHDR 是包含终端短地址(DevAddr)、一个八位帧控制(FCtrl)字节、2字节帧计数器(FCnt)和最大 15 字节的帧选项(FOpts)用来传输 MAC 命令。FOpts 字段如果存在,应使用 NwkSEncKey 加密,如 4.3.1.6 节所述。
Size(bytes) | 4 | 1 | 2 | 0..15 |
FHDR | DevAddr | FCtrl | FCnt | FOpts |
下行帧中,帧头的 FCtrl 内容如下:
Bit# | 7 | 6 | 5 | 4 | [3..0] |
FCtrl bits | ADR | RFU | ACK | FPending | FOptsLen |
上行帧中,帧头的 FCtrl 内容如下:
Bit# | 7 | 6 | 5 | 4 | [3..0] |
FCtrl bits | ADR | ADRACKReq | ACK | ClassB | FOptsLen |
# 4.3.1.1 帧头中自适应数据速率的控制
(ADR, ADRACKReq in FCtrl)
LoRa 网络允许终端采用任何可能的数据速率和发射功率。LoRaWAN 协议利用该特性来优化固定终端的数据速率。这就是自适应数据速率(Adaptive Data Rate,ADR)。当该特性启用时,网络会优化使用最快的数据速率。
当无线电信道衰减快速且不断变化时,可能无法进行自适应数据速率控制。当网络服务器无法控制设备的数据速率时,设备的应用层应该控制它。 在这种情况下,建议使用各种不同的数据速率。应用层应该(SHOULD)总是尽量减少数据包的空中停留时间。
如果上行 ADR 位有设置,网络就会通过相应的 MAC 命令来控制终端设备的数据速率和发射功率。如果 ADR 位没设置,网络则无视终端的接收信号强度,不再控制终端设备的数据速率。网络仍能(MAY)发送命令来改变频道掩码或帧重复参数。
当下行链路 ADR 位有设置,它通知终端设备网络服务器将要发送 ADR 命令。设备可以(MAY)设置/取消上行链路 ADR 位。
当下行链路ADR位未设置时,它向终端设备发信号通知由于无线电信道的快速变化,网络暂时无法估计最佳数据速率。在这种情况下,设备可以选择
将上行 ADR 置零,并按照自己的策略控制其上行链路数据速率。这应该(SHOULD)是移动终端设备的典型策略。
忽略(保持上行链路 ADR 设置)并在没有 ADR 下行链路命令的情况下应用正常数据速率衰减。这应该(SHOULD)是固定式终端设备的典型策略。
ADR 位可以由终端设备或网络服务器按需设置或置零。但是,只要有可能,应该启用 ADR 方案以延长终端设备的电池寿命,并使网络容量最大化。
注意:即使是移动的终端,可能在大部分时间也是处于非移动状态。因此根据它的移动状态,终端也可以请求网络使用上行ADR位来帮助优化数据速率。
默认发送功率是在考虑设备功能和区域监管限制时,设备允许的最大传输功率。设备应使用此功率水平,直到网络通过 LinkADRReq MAC 命令减小功率。
如果终端被网络优化过的数据速率高于自己默认的数据速率,或者发送功率低于默认功率,它需要定期检查网络仍能收到上行帧。每次上行帧计数都会递增(是针对于每个新的上行包,重传包不增加计数),终端增加 ADR_ACK_CNT 计数。如在 ADR_ACK_LIMIT 次上行之后(ADR_ACK_CNT >= ADR_ACK_LIMIT)都没有收到下行回复,它就得设置 ADR 应答请求位(ADRACKReq)。 网络需要在下面 ADR_ACK_CNT 个帧之内回复一个下行帧,上行之后收到任何下行帧就将计数器 ADR_ACK_CNT 重置。
下行ACK位不需要设置,因为在终端设备的接收时隙期间的任何响应都表明网关仍然从该设备接收上行消息。
如果在下一个 ADR_ACK_DELAY 上行时间内都没收到回复(即,在总时间ADR_ACK_LIMIT + ADR_ACK_DELAY之后),如果可能,终端必须(MUST)首先跳回默认功率,然后切换到下一个更低速率来获得更远无线距离来重连网络。
终端如果在每次 ADR_ACK_DELAY 到了之后依旧连接不上,就要(MUST)逐步降低数据速率。一旦设备到达最低数据速率,那么就要(MUST)重新启用所有默认上行频道。
如果终端用它的默认数据速率和发射功率,那就不要(SHALL)置位 ADRACKReq,因为这时无法帮助提高链路距离。
注意:不要求立即响应一个 ADR 应答请求给了网络一些灵活性来优化下行调度处理。
注意:上行传输时在这些情况下要设置 ADRACKReq:如果 ADR_ACK_CNT >= ADR_ACK_LIMIT 并且当前数据速率比设备的最小数据速率高,或者发射功率比默认功率低,或者当前信道掩码仅使用默认通道的子集。其他情况下清除它。
下表提供了数据速率补偿序列的示例,假设ADR_ACK_LIMIT 和 ADR_ACK_DELAY 常量均等于32。
ADR_ACK_CNT | ADRACKReq bit | Data Rate | TX power | Channel Mask |
0 to 63 | 0 | SF11 | Max – 9dBm | Single channel enabled |
64 to 95 | 1 | Keep | Keep | Keep |
96 to 127 | 1 | Keep | Max | Keep |
128 to 159 | 1 | SF12 | Max | Keep |
>= 160 | 0 | SF12 | Max | All channels enabled |
# 4.3.1.2 消息应答位及应答流程
(ACK in FCtrl)
收到 confirmed 类型的消息时,接收端要(SHALL)回复一条设置了应答位(ACK)的数据帧。如果发送者是终端设备,网络就利用终端发送操作后打开的两个接收窗口之一进行回复。如果发送者是网关,终端就自行决定是否发送应答(见下面的注释)。
应答消息的发送只是为了回复收到的最后一条消息,并且永远不重发。
注意:为了让终端尽可能简单,尽可能减少状态,在收到confirmation类型需要确认的数据帧,需要立即发送一个显式(也可能是空的)的应答数据帧。或者,终端会延迟发送应答,在它下一个数据帧中再携带。
# 4.3.1.3 重传流程
下行帧:
下行“confirmed”或“unconfirmed”帧不应(SHALL not)使用相同的帧计数器值重传。下行“confirmed”通讯中,如果没有接收到确认帧,则应用服务器可以决定重新发送新的“confirmed”帧。
上行帧:
上行“confirmed”和“unconfirmed”帧被发送“NbTrans”次(见5.3节),除非在其中一次传输之后接收到有效的下行消息。网络管理器可以使用“NbTrans”参数来控制节点上行链路的冗余,以获得给定的服务质量。终端设备在重复传输之间应像通常一样进行跳频,每次重复后应等待直到接收窗口过期。重新传输之间的延迟由终端设备决定,并且对于每个终端设备可能是不同的。
如果接收到相应的下行链路确认帧,则设备应(SHALL)停止上行链路“confirmed”帧的重传。
只要在 RX1 时隙窗口期间接收到有效的单播下行链路消息,Class B 和 C 的设备应(SHALL)停止上行链路“unconfirmed”帧的重传。
每当在 RX1 或 RX2 时隙窗口期间接收到有效的下行链路消息时,Class A 设备应(SHALL)停止上行链路“unconfirmed”帧的重传。
如果网络接收到多于 NbTrans 次相同上行链路帧,表明可能是重复攻击,或者可能设备故障,因此网络不应(SHALL not)处理这些帧。
注意:检测到重复攻击的网络可以采取其他措施,例如将 NbTrans 参数减少为 1,或将原来信道接收的上行链路帧丢弃,这个信道已经传输了相同的帧,或者一些其他未指明的机制。
# 4.3.1.4 帧挂起位
(FPending in FCtrl,只在下行有效)
帧挂起位(FPending)只在下行通信中使用,表示网关还有下行数据等待下发,需要终端尽快发送上行消息来再打开一个接收窗口。
FPending 的详细用法在章节 19.3 说明。
# 4.3.1.5 帧计数器
(FCnt)
每个终端有3个计数器跟踪数据帧的个数,一个是上行链路计数器(FCntUp),由终端在每次上行数据给网络服务器时累加;另一个是下行链路计数器(FCntDown),由服务器在每次下行数据给终端时累计。
在下行链路方向上存在两种不同的帧计数器方案。单个计数器方案,其中所有端口在设备使用 LoRaWAN1.0 时共享相同的下行链路帧计数器 FCntDown。双计数器方案,在端口 0 和 FPort 字段缺失时,使用单独的 NFCntDown 进行 MAC 通信,当设备使用 LoRaWAN1.1 时,另一个AFCntDown 用于除端口 0 外的其他端口。
双计数器方案中,NFCntDown 由网络服务器管理,而 AFCntDown 由应用服务器管理。
注意:LoRaWAN v1.0 及更早版本仅支持一个 FCntDown 计数器(在所有端口之间共享),并且网络服务器必须注意支持 LoRaWAN v1.1 之前的设备。
每当 OTAA 设备成功处理 Join-accept 消息时,上行帧计数器(FCntUp)和下行帧计数器(NFCntDown 和 AFCntDown)将重置为0。
ABP 入网的设备帧计数器在制造时初始化为 0。在ABP设备中,帧计数器不能(MUST NEVER)在设备的运行期间复位。如果终端设备在其运行期间容易断电(例如更换电池),则在这种情况下帧计数器应该(SHALL)持久化。
之后 FCntUp 随每个上行链路递增,NFCntDown 随着每个下行链路递增(FPort 为 0 或 FPort 不存在)。AFCntDown随着每个下行链路递增(FPort 不为 0)。在接收侧,相应的计数器与接收的值保持同步,前提是接收的值与当前计数器值相比递增,并且消息 MIC 字段与利用网络会话密钥计算出的 MIC 匹配。在多次传输 confirmed 或 unconfirmed 的帧的情况下,FCnt不会递增(请参阅NbTrans参数)。网络服务器应(SHALL)删除重复传输的帧,并仅将单个实例转发到应用程序服务器。
帧计数器是32位宽,FCnt 字段对应于32位帧计数器的最低有效16位(例,用于发送上行链路的数据帧的 FCntUp 和用于下行链路发送的数据帧的 AFCntDown / NFCntDown)。
终端设备不应(SHALL NEVER)在相同应用重复使用相同的 FCntUp 值或网络会话密钥,除了重传相同的 confirmed 或 unconfirmed 的帧。
终端设备应该(SHALL)永远不会处理相同下行链路帧的任何重传。重传的帧应忽略,不做任何处理。
注意:这意味着一旦接收到下行链路 confirmed 帧,设备将仅回复消息(ACK),类似地,设备将仅在接收到设置了 FPending 位的帧之后生成单个上行链路消息。
注意:由于 FCnt 字段仅携带 32 位帧计数器的最低有效 16 位,因此服务器必须从通信状况推断出帧计数器的16个最高有效位。
# 4.3.1.6 帧选项
(FOptsLen in FCtrl, FOpts)
FCtrl 字节中的 FOptsLen 位字段描述了整个帧选项(FOpts)的字段长度。
FOpts 字段传送背负于数据帧的最大 15 字节 MAC 命令,第 5 章列出有效 MAC 指令。
如果 FOptsLen 为 0,FOpts 为空。在 FOptsLen 非 0 时,比如 MAC 命令在 FOpts 字段中体现,port 0 不能使用(FPort 要么不存在,要么非0)。
MAC 命令不能同时出现在 FRMPayload 和 FOpts 中,如果出现这种情况,设备将(SHALL)丢弃该组数据。
如果帧头部携带 FOpts,则必须(MUST)在计算消息完整性代码(MIC)之前对 FOpts 进行加密。
所使用的加密方案基于 IEEE 802.15.4/2006 Annex B [IEEE802154-DOC] 中描述的通用算法,其使用密钥长度为128位的AES。
使用的密钥 K 是上行和下行方向上的 FOpts 字段的 NwkSEncKey。
加密的字段是:pld = FOpts
对于每条消息,算法定义一个数据块 A:
Size(bytes) | 1 | 4 | 1 | 4 | 4 | 1 | 1 |
A | 0x01 | 4 x 0x00 | Dir | DevAddr | FCntUp or NFCntDwn | 0x00 | 0x00 |
方向字段(Dir)当上行链路帧为0,当下行链路帧为1。
数据块 A 被加密以获得数据块 S:
通过将 (pld | pad_16) xor S 截断到第一个len(pld) 八位字节来完成 FOpts 的加密和解密。
# 4.3.2 端口字段
(FPort)
如果帧载荷字段不为空,端口字段必须(MUST)体现出来。端口字段有体现时,若 FPort 的值为 0 表示 FRMPayload 只包含了MAC命令,接受到的任何具有这种 FPort 的帧都应由 LoRaWAN 实现处理,具体见第 5 章中的 MAC 命令。FPort 的值从 1 到 223(0x01..0xDF) 都是由应用层使用。FPort 值 224 专用于 LoRaWAN MAC 层测试协议。 LoRaWAN 实现应该丢弃 FPort 值不在 1..224 范围内的应用层的任何传输请求。
注意:FPort 值 224 的目的是提供专用的 FPort,以便在最终版本的设备上通过无线方式运行MAC一致性测试场景,而无需在实际方面依赖于设备的特定测试版本。该测试不应与实时操作同时进行,但设备的MAC层实现应完全是可正常的使用。通常使用 AppSKey 加密测试协议。这可确保网络服务器不能在没有设备所有者参与的情况下启用设备的测试模式。如果测试在实时网络连接设备上运行,则网络侧测试应用程序学习AppSKey的方式不在LoRaWAN规范的范围。如果测试在专用测试平台(不是实时网络)上使用OTAA运行,则 AppKey 与测试平台通信的方式,对于安全的 JOIN 过程,也不在规范范围内。
在应用层运行的测试协议是在LoRaWAN规范之外定义的,因为它是一个应用层协议。
FPort 值 225..255(0xE1..0xFF)保留用于将来的标准化应用程序扩展。
Size(bytes) | 7..22 | 0..1 | 0..N |
MACPayload | FHDR | FPort | FRMPayload |
N 是应用程序载荷的字节个数。N 的有效范围具体在 [PHY-DOC] 定义。
N 应该(MUST)小于等于:
N ≤ M - 1 - (FHDR长度)
M 是 MAC 载荷的最大长度。
# 4.3.3 MAC帧载荷加密
如果数据帧携带了载荷,FRMPayload 必须要在 MIC 计算前进行加密。
加密机制是采用 IEEE 802.15.4/2006 Annex B [IEEE802154-DOC] 的 AES128 算法。
使用的密钥 K 取决于数据消息的 FPort:
FPort | Direction | K |
0 | Uplink/downlink | NwkSEncKey |
1..255 | Uplink/downlink | AppSKey |
加密的字段是:
pld = FRMPayload
对于每个数据帧,算法定义了一个块序列 A_i,i 从 1 到 k,k = ceil(len(pld) / 16):
Size(bytes) | 1 | 4 | 1 | 4 | 4 | 1 | 1 |
Ai | 0x01 | 4 x 0x00 | Dir | DevAddr | FCntUp or NFCntDwn or AFCntDnw | 0x00 | i |
方向字段(Dir)在上行帧时为0,在下行帧时为1. 块 Ai 通过加密,得到一个由块 Si 组成的序列 S。
Si = aes128_encrypt(K, Ai) for i = 1..k S = S1 | S2 | .. | Sk
有效载荷的加密和解密通过截断来完成
(pld | pad16)xor S.
到第一个 len(pld) 八位字节。
# 4.4 消息校验码
消息检验码(MIC)要计算消息中所有字段。
msg = MHDR | FHDR | FPort | FRMPayload
其中 len(msg)表示以八位字节为单位的消息长度。
# 4.4.1 下行帧
下行链路帧的MIC计算如下 [RFC4493-DOC]:
cmac = aes128_cmac(SNwkSIntKey, B0 | msg) MIC = cmac[0..3]
数据块 B0 的定义如下:
Size (bytes) | 1 | 2 | 2 | 1 | 4 | 4 | 1 | 1 |
B0 | 0x49 | ConfFCnt | 2 x 0x00 | Dir=0x01 | DevAddr | AFCntDwn or NFCntDwn | 0x00 | len(msg) |
如果设备连接到 LoRaWAN1.1 网络服务器并且下行帧的 ACK 位被设置,意味着该帧确认上行“confirmed”帧,则 ConfFCnt 是正在应答的这个上行“confirmed”帧的帧计数器对 2^16 取模。在所有其他情况下,ConfFCnt = 0x0000。
# 4.4.2 上行帧
上行帧的 MIC 通过以下过程计算:
数据块 B0 的定义如下:
Size(bytes) | 1 | 4 | 1 | 4 | 4 | 1 | 1 |
B0 | 0x49 | 0x0000 | Dir = 0x00 | DevAddr | FCntUp | 0x00 | len(msg) |
数据块 B1 的定义如下:
Size (bytes) | 1 | 2 | 1 | 1 | 1 | 4 | 4 | 1 | 1 |
B1 | 0x49 | ConfFCnt | TxDr | TxCh | Dir = 0x00 | DevAddr | FCntUp | 0x00 | len(msg) |
其中:
- TxDr 是用于传输上行链路的数据速率。
- TxCh 是用于传输的信道的索引值。
- 如果设置了上行链路帧的 ACK 位,意味着该帧正在确认下行链路 “confirmed” 帧,这时 ConfFCnt 是正应答的该下行 “confirmed” 帧的帧计数器对 2^16 取模。在所有其他情况下,ConfFCnt = 0x0000。
cmacS = aes128_cmac(SNwkSIntKey, B1 | msg)
cmacF = aes128_cmac(FNwkSIntKey, B0 | msg)
如果设备连接到LoRaWAN1.0网络服务器,则:
MIC = cmacF[0..3]
如果设备连接到LoRaWAN1.1网络服务器,则:
MIC = cmacS[0..1] | cmacF[0..1]
← 第3章 物理消息格式 第5章 MAC 指令 →