Mesh Profile (3.5)低传输层

Posted minnowbin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mesh Profile (3.5)低传输层相关的知识,希望对你有一定的参考价值。

(翻译自《MeshProfile v1.0》3.5 Lower Transport Layer)

综述

低传输层利用来自高传输层的PDU组成自身的消息,并且将这些消息发送给对侧的低传输层。这些高传输层PDU的大小可能适合一个单独的地传输层PDU,也可能被分片为多个低传输层PDU。当接收到消息时,低传输层处理低传输层PDU,可能需要将多个PDUs重组为高传输层PDU,一旦重组完成便将他们递交给高传输层。

低传输层PDU

低传输层PDU用于将高传输层PDU发送给其他节点。

低传输层PDU第一个octet的最高有效位是SEG字段。该字段用于表示该低传输层PDU是否是一个分片消息。

和网络层PDU中CTL字段配合,有四种不同的情况。

CTL = 0, SEG = 0, 未分片的访问消息

CTL = 0, SEG = 1, 分片的访问消息

CTL = 1, SEG = 0, 未分片的控制消息

CTL = 1, SEG = 1, 分片的控制消息

未分片的访问消息

未分片访问消息用于传输一个大小适合一个单独的网络层PDU的高传输层访问消息。

SEG字段应该被设置为0,1bit。

AKF字段表示应用秘钥标志,1bit。AID字段表示应用秘钥标识符,6bit。这两个字段由高传输层根据对访问层数据加密使用应用秘钥还是设备秘钥来设置。

然后是高传输层PDU,大小为40~120bit,即最大15octets。由高传输层提供数据。

该消息并没有SZMIC字段。这种情况高传输层的TransMCI应该是一个32bit的值。(存在疑问,NordicSDK在这里做了某种赋值,需要确认)

分片的访问消息

分片的访问消息用于传输高传输层访问PDU的一个分片。

SEG字段应该设置为1,1bit。

AKF字段表示应用秘钥标志,1bit。AID字段表示应用秘钥标识符,6bit。根据访问层数据的加密方式决定。

SZMIC字段用于表示TransMIC的大小,1bit。如果SZMIC字段为0,表示TransMIC是32bit,如果SZMIC为1,表示TransMIC为64bit。

SeqZero字段,13bits,用于表示SeqAuth的最低的13个bit。有高传输层设置。

SeqO字段,5bits,用于表示分片偏移序号。(从0开始)

SeqN字段,5bits,用于标志最后一个分片的序号。

Seqment m,8~96bits,即1~12octets。用于填充高传输层PDU的分片。最多12octets是应为其他字段占去了4octets。

来自于同一个高传输层访问PDU的每一个访问消息的分片,应该具有相同的AKF,AID,SZMIC,SeqZero,SeqN。

未分片的控制消息

一个未分片的控制消息用于传输一个分片确认消息或者一个传输层控制消息。

SEG字段,应该设置为0,表示没有分片,1bit

Opcode字段,7bit。0x00,表示一个分片确认消息;0x01~0x7F表示传输层控制消息的Opcode。

数据参数,0~88bit,即最大11octet。用于传输层控制消息的参数。

分片确认消息

分片确认消息用于低传输层确认由对侧低传输层发来的分片消息。

SEG字段,1bit,运营官设置为0,表示没有分片。

Opcode字段,7bit,设置为0x00。

OBO字段,1bit,设置为0表示接收到的消息直接寻址到该节点;设置为1表示该消息为朋友节点用于维护低功耗节点发出的确认,非直接寻址到该节点。

SeqZero字段,13bit,表示高传输层PDU的SeqZero。

RFU字段,2bit,待设置。

BlockAck,32bit,分片的块确认。最低有效位,bit0,代表分片0;最高有效位,bit31,代表分片31。如果bit n 设置为1,则表示分片n被确认。如果bit n设置为0,则表示分片n没有被确认。大于SeqN的位应该别忽略。

如果收到的分片的TTL被设置为0,建议将相应的分片确认消息在发送时将TTL设置为0。

分片的控制消息

分片的控制消息用于在传输层控制消息的尺寸不适合一个单独的网络PDU时将该消息分片发送出去。

SEG字段,1bit,设置为1。

Opcode字段,7bit,0x01~0x7F,表示传输层控制消息的命令码。

RFU,1bit。

SeqZero,13bit,表示SeqAuth的最低13bit有效位。

SeqO,5bit,表示分片偏移序号。

SeqN,5bit,表示最后一个分片的序号。

Seqment m,8~64bit,即1~8octets、用于传输第m包高传输层控制PDU。

(由上面计算,分片控制消息最大12octets。)

分片和重组

传输大小超过15octets高传输层PDU时,低传输层需要分片和重组高传输层PDU。这些分片发送给对侧时使用块确认方案,这样可以是低传输层发送的消息最小化。高传输层访问PDU和高传输层控制PDU的分片过程是完全相同的。

注意:分片的尺寸对于高传输层控制PDU和高传输层访问PDU是不同的。

技术分享图片

上面这张图阐释了一个高传输层访问PDU被发送的的情景。该PDU包含一个octet的命令码,3个用于网络秘钥索引和应用秘钥索引字段的octets,16个octets的应用秘钥。这样当使用应用秘钥对其加密和认证后,高传输层PDU大小是24octets(包括4octets的TransMIC)。这个PDU会被低传输层分为两个分片:分片0和分片1。每一个分片有一个用于区分分片序号的包头,然后这两个PDU被递交给网络层,并计算完成完整的网络层PDU。然后网络层将使用网络层PDU序号对该PDU加密,以为了保证只有NID字段(和IV index)处于明文可见而混淆这些消息。因此上述的访问层消息最终可以通过两个网络层PDU发送出去。

对于高传输层访问PUD和高传输层控制PDU的分片过程是完全相同的。并且在下面的描述中,考虑这两个PDU类型是完全相同的,除非明天的描述。

注意:对于高传输层访问PDU和控制PDU的分片大小和尺寸是不同的。

分片

低传输层将高传输层PDU分片为一个或者多个低传输层PDU、低传输层在同一时间只能将一条单独的,发送给同一个目的地址的高传输层PDU分片后的访问消息或者分片的控制消息发送出去。在一条高传输层PDU被确认或者取消之前,低传输层只可以发送该PDU一次。(这里需要关注协议栈中对于确认,取消和发送的关系的处理方式。)

如果一个高传输层PDU的大小适合一个单独的使用未分片消息格式的低传输层PDU,那么低传输层应该使用一个未分片消息发送这个高传输层PDU。

如果一个高传输层PDU的大小适合一个单独的使用分片消息格式的低传输层PDU,那么低传输层应该使用一个单独的分片消息发送这个高传输层PDU。

否则,需要使用两个或者多个分片的消息发送。

分片消息在低传输层完成确认,但是非分片消息并非如此。因此在发送高传输层PDU时,使用一个单独的分片格式的消息效率要比使用一个非分片格式的消息更高效。(疑问,这里有的选吗,不是应该按照长度选择吗)

例如,如果一个用来确认的消息在传输层被发送,此时在传输层已经有多分片的消息被收到,而如果这个用于确认的消息发生了丢失,那么全部的多分片消息必须再被全部发送一次。相反,如果一个应用的确认消息在一个单独的分片格式的访问消息中发送,那么这个发送应该发生在低传输层,可以多次发送确认消息,因而避免了再次重传多分片的消息。(这里好混乱啊!!!总之是能用单独的分片消息,就不要用非分片消息。)

每一个高传输层访问PDU的分片应该为12octets,除了最后一个分片。

每一个高传输层控制PDU的分片应该为8octets,除了最后一个分片。

例如,当使用一个32bit的TransMIC时,如果高传输层访问PDU长度有42octets,那么0~11octets为分片0;12~23octets为分片1;24~35octets为分片2;剩余的6个octets,36~41octets为分片3。

如果高传输层控制PDU长度42octets,那么0~7octets为分片0,8~15octets为分片1;16~23octets为分片2;24~31为分片3;32~39为分片4;剩下的2octets,40~42为分片5。

高传输层PDU的每一个分片通过SeqO字段区分。各个分片通过用于加密和认证高传输层访问PDU的SeqAuth值连接组织在一起(表示为同一个高传输层PDU的分片)。一个高传输层访问PDU的每一个低传输层分片具有相同的IV index作为SeqAuth。

与访问PDU类似,控制PDU也使用SeqO区分,使用SeqAuth值完成连接组织(表示为同一个高传输层PDU的分片)。

SeqAuth有IV index和第一个分片的序列号(SEQ)组成,56bit。其中从最高有效位开始是IV index,从最低有效位开始是序列号。SeqAuth中只有最低的13个bit(被称作SeqZero)被包括在分片消息和分片确认消息中。当重组一个完整的访问消息时,SeqAuth可以通过IV index,SeqZero和SEQ计算出来,由最大的SeqAuth决定(这里SeqZero最大为8191,即0x1FFF,并且使用相同的IV index)。

例如,如果收到一个消息的SEQ是0x647262,IV index是0x58437AF2,

当SeqZero是0x1849时,SeqAuth是 0x58437AF2 645 849;

当SeqZero是0x1263时,SeqAuth是 0x58437AF2 645 263;

(如何计算SeqAuth呢)

由于SeqZero大小的限制,不可以发送一个SEQ比8192大的分片消息。如果一个分片消息没有在时间内被确认,那么高传输层PDU的发送应该被取消。

消息的每一个分片都包括了分片偏移序列号和最后分片号这两个信息。

例如,在上面的42octets的高传输层控制PDU中,分片为0,1,2,3,4,5 最后分片号是5。分片偏移号和最后分片号都包括在分片消息中,可以让接收方计算出高传输层PDU的大小尺寸。

重组

重组动作在接收设备上执行。

对于低功耗节点,它的确认消息将由朋友节点处理,低功耗节点不需要发送分片的确认消息。

当接收到一个分片消息时,会检查SeqAuth,以确定该高传输层PDU是否之前已经被接收到。如果分片消息没有被接收到,那么接收设备需要按照SegN(最后一个分片序号)的描述开辟额外的内存,来保存该高传输层PDU的分片,并维持对接收到的分片的追踪,并且认为该消息已经被接收。

如果节点不是低功耗节点,并且消息的目的地址是一个单播地址,如果该节点不能在此时收到高传输层PDU(比如节点忙碌或则资源受限),那么该节点需要向源节点发送块确认值为0x0000000的信号。

如果分片消息正在接收处理的过程中,那么分片偏移序号(SegO)将确定在这个分片消息中哪一个高传输层PDU的etet需要替换之前为本条消息开辟的内存空间。然后,接收方会更新快确认值,来记录锁发送消息的成功分发。

一旦对于一个给定的SeqZero的高传输层PDU被完全接收,那么高传输层将检查高传输层PDU。

分片行为

(需要重新翻译)

一旦高传输层消息被分片,低传输层将发送消息中的每一个分片。

如果消息的目的地址是一个单播地址,那么低传输层期望收到来自源节电或者朋友节点的确认消息。

如果消息的目的地址是一个虚拟地址或者组地址,那么不会接收到确认消息。

如果分片包被发送给一个组地址或者虚拟地址,那么低传输层需要发送全部的分片包。建议发送全部的分片包多次,并在每次重复中引入智能随机延时。(Nordic如何处理该延时呢?)

 当低传输层PDU发送给单播地址时需要主要一下必要的应用方式

当低传输层PDU被发送,一个分片的传输定时器应该开始计时,在一定时间范围内,分片的确认消息应该被收到。这个时间最小应该设置为 200 + 50 * TTL ms。

一个有效的分片确认消息需要满足

  • 分片确认消息的OBO字段设置为0
  • DST字段设置为元素的单播地址
  • SeqZero字段设置为分片消息的SeqZero字段
  • SRC字段设置为分片消息的目的地址

如果一个分片确认消息的OBO字段设置为1, 并且DST字段设置为元素的单播地址,并且SeqZero字段设置为分片消息的SeqZero字段,那么这个分片确认消息是一个有效的分片确认消息。

对于一个给定的SeqAuth,只有从第一个SRC地址接收到的分片确认消息可以被认作有效的分片确认消息。

???OBO字段的含义于朋友关系

如果一个有效的分片确认消息被接收,低传输层需要重置分片传输定时器并且重传全部没有确认的低传输层PDU。

如果一个确认了全部低传输层消息的分片确认消息被接收,那么表明高传输层PDU是完整的。

如果一个将BlockAck字段设置为0x00000000的分片确认消息被接收,那么高传输层PDU应该立即取消,并且更高的层次应该接到这个取消通知。

如果分片传输定时器超时,并且没有有效的确认被接收,那么低传输层应该重发全部没有被确认的低传输层PDU。

每一个低传输层PDU至少要被发送两次,除非确认更早的到达。如果在全部确认消息到达前,低传输层停止发送低传输层PDU,那么高传输层PDU将被取消。

重组行为

(需要重新翻译)

不适用于低功耗特性。

低传输层对于每一个源设备的SeqAuth有一个序列认证值和一个块确认值。

如果低传输层收到一个SeqAuth比序列认证值小的分片消息,需要忽略这个分片消息。

如果低传输层收到一个新的消息,应该保存来自分片包的SeqAuth值作为新的序列认证值。

注意:序列认证值逻辑上包含了 IV index 信息,因此如果一个低传输层PDU通过使用一个较早的IV index被接收,那么这个PDU应该有一个比序列认证值更小的SeqAuth。

如果一个低传输层接收到一个多分片消息中的一个分片包,但是不能在此时接收这个多分片消息。这是因为当前接收方正处于忙碌或者资源用尽的情况。

如果一个 消息的目的地址是一个单播地址,低传输层应该回应一哥BlockAck字段设置为0x00000000的确认包。

低传输层收到一个SeqAuth比序列确认值大的多分片消息中的一个分片时,应该开启一个未完成定时器。这个定时器定义了低传输层等待最大时间数。这个未完成的定时器最小应该别设置为10s。

 低传输层收到一个SeqAuth比序列确认值大的,并且目的地址是一个单播地址的多分片消息中的一个分片时,应该开启一个确认定时器。这个定时器定义了低传输层发送一个分片确认消息后的时间次数。这个确认定时器应该最小设置为 150 + 50 * TTL ms。

 注意:NT

如果一个低传输层在未完成定时器结束后收到了无论任何分片消息,未完成定时器应该重新打开。

低传输层应该标记每一个接收到一个块确认值的分片包,这个块确认值能够在之后传回发送的源节点。

当全部分片信息的分片被接收时,低传输层应该发送一个BlockAck字段设置为块确认值的分片确认消息

低功耗特性的重组行为

低传输层行为

发送一个低传输层PDU

接收一个低传输层PDU

朋友队列

以上是关于Mesh Profile (3.5)低传输层的主要内容,如果未能解决你的问题,请参考以下文章

蓝牙Mesh的基本架构/配网流程/节点定义

低功耗蓝牙LE Audio Profile 详细介绍

详解基于UDP的低延时网络传输层协议——QUIC

传输层协议应用层协议

网络七层协议

DTLS数据包传输层安全性协议详解