<!--
继前面章节的Proxy和Relay节点之后,该篇将讲深入讲解朋友节点的作用及其工作的流程。其在整个BLE Mesh网络中是极其重要的一个特性,甚至可以认为如果没有朋友这个特性的话,BLE Mesh是不完整的或者说是有缺陷的;因为IoT领域充斥着大量的由电池供电的低功耗设备,这也导致需要一个特别的设备来临时缓存这些低功耗设备的信息,在BLE Mesh中我们称这个特殊的设备为朋友节点,而其他的Mesh网络则称之为父节点;反之,低功耗设备就称为低功耗节点;但是,它们本质的功能都是相同的。
由上图可以看出,朋友节点与低功耗设备的关系是树状通讯模型。
在整个BLE Mesh网络中朋友节点的作用就是帮周边的低功耗节点缓存消息;为了保持这种纯洁的友谊,Spec专门定义了以下相关的时间参数来维护它们之间的关系。
ReceiveDelay & ReceiveWindow
其中:
Request为下列消息:
Response为下列消息:
如果Low Power Node节点在ReceiveWindow超时之前,收到Friend节点的回复,则可以提前停止ReceiveWindow的计时器;
PollTimeout
由上图可知,该时间参数主要用于计算Low Power节点连续发送两个Request消息的时间,换句话说就是:“在PollTimeout时间内,正常情况LPN一定会发出Request消息”;如果Friend节点在PollTimeout超时之前,仍然没有收到Low Power节点的Requests,一旦超时则Friend节点中止与其的朋友关系 (因为计时器没法复位清零,导致超时);这也就是说 “朋友之间的友谊小船已经翻了”
!!!注意:该参数仅于友谊建立之后有效
基本上整个朋友节点与低功耗节点的数据交互 (这里指的是友谊关系建立之后的情况),均是建立在上述Spec规定的时间参数上。
如果Friend节点要帮忙缓存周边低功耗设备的消息,低功耗设备就必须跟Friend节点建立关系,然后一直维持这段关系;否则,这种友谊关系就会断了;老规矩先直接上图:
建立友谊的主要流程步骤
实际的友谊建立过程
由上面的两幅图,我们可以大概了解到友谊是如何建立的;这其实跟我们平时相亲的过程是极度类似的,先亮家底然后挑选一个喜欢的妹纸或者男子耍朋友;但是如果以后没精力去维护这段感情的话,那么就很容易导致分手或者离婚。接下来,由小编带领读者看看它们是如何耍朋友的:
当LPN需要朋友节点帮其缓存信息的时候,它会向其周边的所有朋友节点发送Friend Request消息 (这意味着该消息的目标地址为0xFFFD),该消息的帧格式如下所示:
Field Name | Size(octets) | Notes |
---|---|---|
Criteria | 1 | The criteria that a Friend node should support in order to participate in friendship negotiation |
ReceiveDelay | 1 | Receive delay requested by the Low Power node |
PollTimeout | 3 | The initial value of the PollTimeout timer set by the Low Power node |
PreviousAddress | 2 | Unicast address of the primary element of the previous friend |
NumElements | 1 | Number of elements in the Low Power node |
LPNCounter | 2 | Number of Friend Request messages that the Low Power node has sent |
Criteria
这个是LPN对朋友节点的要求,类似于"相亲时摆出自己对另一伴的要求;具体的内容如下表所示:
Field | Size(bits) | Notes |
---|---|---|
RFU | 1 | Reserved for Future Use |
RSSIFactor | 2 | The contribution of the RSSI measured by the Friend node used in Friend Offer Delay calculations |
ReceiveWindowFactor | 2 | The contribution of the supported Receive Window used in Friend Offer Delay calculations |
MinQueueSizeLog | 3 | The minimum number of messages that the Friend node can store in its Friend Queue |
各域的占位情况如下图所示:
RFU
保留
RSSIFactor
用于朋友节点在发送Friend Offer消息前,参与计算延时的一个参数,其取值如下所示:
Value | RSSI Factor |
---|---|
0b00 | 1 |
0b01 | 1.5 |
0b10 | 2 |
0b11 | 2.5 |
ReceiveWindowFactor
作用同RSSIFactor,其取值如下所示:
Value | Receive Window Factor |
---|---|
0b00 | 1 |
0b01 | 1.5 |
0b10 | 2 |
0b11 | 2.5 |
MinQueueSizeLog
该域表示朋友节点能为LPN存储在其Friend Queue中最少的消息数量,其取值范围如下所示:
Value | Description |
---|---|
0b000 | Prohibited |
0b001 | N = 2 |
0b010 | N = 4 |
0b011 | N = 8 |
0b100 | N = 16 |
0b101 | N = 32 |
0b110 | N = 64 |
0b111 | N = 128 |
其中计算公式如下:
MinQueueSizeLog = Log2(N) --> N = 2(MinQueueSizeLog)
其中N表示Friend节点可以存储在其Friend Queue中的最大Lower Transport PDUs的最小数量;什么意思呢?举个例子:
如果MinQueueSizeLog等于3,那么N就等于8,这说明Friend Queue中最少要能存储最长的Lower Transport PDU个数为8个 (其中Lower Transport PDU的最大值为16字节);但是,这不是表示Friend Queue此时最小的大小为8x16 Bytes,因为Friend Queue除了Lower Transport PDU之外还有很多其他的内容;其中,Nordic定义每个Friendship的Friend Queue存放的朋友数据包 (Network PDUs) 个数为35个,35 > 32这也就意味着,Friend Queue可以容纳一个最长的分段消息 (小编在SIG MESH协议各个层的作用.Mesh数据包帧格式就讲过,最大的分包个数为32);
ReceiveDelay
该域的内容用于设置LPN发送完Request消息之后,给ReceiveDelay这么多的时间给Friend节点准备一下response的内容;详情如ReceiveDelay & ReceiveWindow,其取值范围如下表所示:
Value | Description |
---|---|
0x00-0x09 | Prohibited |
0x0A-0xFF | Receive Delay in units of 1 millisecond |
!!!注意:该参数值用于上述ReceiveDelay & ReceiveWindow中的Request消息
PollTimeout
该域的作用请参考PollTimeout的内容,其取值范围如下表所示:
Value | Description |
---|---|
0x000000–0x000009 | Prohibited |
0x00000A–0x34BBFF | PollTimeout in units of 100 milliseconds |
0x34BC00–0xFFFFFF | Prohibited |
PreviousAddress
如果LPN之前与其他的朋友节点建立过友谊关系,那么该域就填充上一个朋友节点的首要元素的单播地址;如果之前从未与任何朋友节点建立过友谊关系,那么该域的值填充为0x0000;
NumElements
该域用于表示LPN有多少个元素,由于Friend Request消息的源地址是LPN的首要元素的单播地址,所以Friend节点可以根据该消息的源地址以及该域的值,计算出LPN其他元素的地址;该域值的取值范围如下所示:
Value | Description |
---|---|
0x00 | Prohibited |
0x01-0xFF | Number of elements |
LPNCounter
该域值表示LPN迄今为止所发送的Friend Request消息的次数,每发一次该值就会加1,默认从0开始累加;
至此,Friend Request的全部内容都讲完了,这也是交朋友的第一步;但是,小编觉得还有如下几点是需要注意的:
该消息由LPN主动发起
该消息的TTL必须要设置为0
该消息使用Master安全凭证加解密,具体的内容我们会放到Friendship Security中讲解
如果Friend Node接收到的Friend Request的源地址,是已经跟该朋友节点建立了友谊关系;那么,朋友节点应该与该LPN终止友谊关系
LPN发送完该消息之后等待100ms,紧接着监听来自于Friend Node的Friend Offer消息,最长时长为1秒;如果上述的1秒超时之后,LPN仍然没有收到Friend Offer的消息,那么协议栈一般就会向应用层上报Timeout事件;LPN此时可以选择重发Friend Request消息 (Spec没有强制要求,由用户自己决定,Nordic定义该值默认为5) ,只不过这两个连续的Friend Request消息的时间间隔要大于1.1秒(100ms+1秒)
当朋友节点接收到Friend Request之后,如果Friend Node符合其提及的Criteria内容,那么就响应该请求,其具体的内容如下表所示:
Field | Size(octets) | Notes |
---|---|---|
ReceiveWindow | 1 | Receive Window value supported by the Friend node |
QueueSize | 1 | Queue Size available on the Friend node |
SubscriptionListSize | 1 | Size of the Subscription List that can be supported by a Friend node for a Low Power node |
RSSI | 1 | RSSI measured by the Friend node |
FriendCounter | 2 | Number of Friend Offer messages that the Friend node has sent |
ReceiveWindow
由上述的ReceiveDelay& ReceiveWindow可知,该参数由Friend Offer消息提供给LPN,而LPN将该参数做为其监听朋友响应消息的接收窗口的时间;具体的取值范围如下表所示:
Value | Description |
---|---|
0x00 | Prohibited |
0x01-0xFF | Receive Window in units of 1 millisecond |
同样的,该参数值用于上述ReceiveDelay & ReceiveWindow中的Request消息
QueueSize
该域表示朋友节点可以帮LPN缓存的消息数量;
SubscriptionListSize
该域表示朋友节点可以为低功耗节点保存的订阅地址的数量;
RSSI
该值是朋友节点接收到的Friend Request消息后,计算得到的信号强度;如果朋友节点的信号强度指示不可用,则该域值默认为127dBm,即0x7F;由于RSSI都是负数,因此RSSI换算成16进制的公式如下:
RSSI(dBm) = RSSI - 256; 比如:Friend节点计算得到的RSSI是-70dBm,那么该域的RSSI = 256-70 = 0xBA;
FriendCounter
该域跟上述的LPNCounter的功能类似,用于统计同一个Friend节点发送Friend Offer的次数,每发送一次该值加1,默认从0开始叠加
至于,朋友节点接收到Friend Request之后,应该隔多久回复Friend Offer消息;Spec作出了如下规定:
Local Delay = ReceiveWindowFactor * ReceiveWindow - RSSIFactor * RSSI
这个时候,读者可能会有疑问 “不是说好给ReceiveWindow时间给Friend节点准备发送响应消息吗?”
起初,小编也有同样的疑问;不过,小编很快就释然了;首先,ReceiveWindow是由朋友节点发送给LPN的,可是这个时候LPN还没有收到呢?它怎么可能知道Friend Node会什么时候发response给它;其次,我们可以在ReceiveDelay& ReceiveWindow中可以看到,其中Request消息并不包含Friend Request的内容,Local Delay才是用于Friend节点响应Friend Request的间隔时长,其中该计算公式的各个参数来自于不同的消息:
ReceiveWindowFactor & RSSIFactor
该参数来自于LPN的Friend Request
ReceiveWindow
该参数则是出自于Friend Offer消息,用于通知LPN可以在这个时间间隔内接收朋友节点的响应消息,具体详情请参考ReceiveDelay& ReceiveWindow中的图示
RSSI
朋友节点计算接收到的Friend Request消息的信号强度
上述的公式再配合前面提及到的实际的友谊建立过程,我相信读者此时对Local Delay已经相对了解了吧。但是,Local Delay还有一点需要读者们注意:
如果计算出来的Local Delay的值大于100,那么实际的友谊建立过程中的Delay值,也就是Friend Offer Delay就等于Local Delay毫秒;否则,Delay值直接等于100ms
为了加深大家的理解,这里小编用实际捉包的示程向大家展示Local Delay、Friend Request、Friend Offer之间的关系:
由上图我们可以得知:
Local Delay = ReceiveWindowFactor * ReceiveWindow - RSSIFactor * RSSI = 1* 5 - 2* 225 = -445 < 100
所以,Local Delay = 100ms。同样的,如下两点是需要注意的:
LPN节点根据众多的朋友节点返回的Friend Offer中,选择最符合自己要求的一个Friend Node,然后向其发送Friend Poll消息;至于,LPN是如何选择最符合的Friend节点?
一般最先接收到Friend Offer消息的那个朋友节点就是最适合的,因为离LPN最近且LPN要求的Criteria的条件也满足;当然,用户可以继续监听其他的Friend节点,再根据Criteria的条件选择想要的Friend节点;
如果Friend Node接收该消息的话,就会返回Friend Update;除了该功能之外,该消息还用于建立友谊之后,获取朋友节点为LPN缓存的消息;该消息的帧格式如下表所示:
Field | Size(bits) | Notes |
---|---|---|
Padding | 7 | 0b0000000. All other values are Prohibited |
FSN | 1 | Friend Sequence Number, used to acknowledge receipt of previous messages from the Friend node to the Low Power node |
其中,FSN域主要的作用如下:
同样的,该消息有如下几点需要注意:
该消息的TTL必须要设置为0
该消息使用Friendship安全凭证加解密,该方面的内容我们会放到Friendship Security中讲解
响应Friend Poll的消息,可以是Friend Update,也可以是在Friend Node中缓存的消息;至于是哪一种,则要看当前的情况而定,具体将在Friend Update中细述
当Friend节点发送完Friend Offer消息1秒内,就接收到来自于LPN的Friend Poll消息;对于朋友节点来说,其认为与LPN友谊关系已经建立并保存此时的FSN域值,否则朋友节点认为此次友谊建立不成功
由上图可知,当LPN接收到Offer消息之后,很快就向朋友节点发送Poll消息了,远远小于1秒
当朋友节点收到来自于LPN的Friend Poll消息之后,应该在ReceiveDelay毫秒之后且(ReceiveDelay+ReceiveWindow)毫秒之前,将响应Friend Update消息发送给LPN
由上图可知,朋友节点在ReceiveDelay毫秒之后 (示例图中的ReceiveDelay为100ms),就已经回复Friend Update给LPN
如果LPN从Friend Offer消息中,选中一个Friend节点并向其发送Friend Poll消息,但是一直没有收到来自于朋友节点的Friend Update消息响应;显然该消息也不可能一直这样发下去,对这个发送的次数是有限制的,至于该限制的次数是多少,没有强制规定,Nordic的SDK定义的是5次;如果超过这个尝试次数还没有收到 Friend Update消息,那么就会上抛相应的事件给应用层处理,至于怎么处理由用户自己决定;然而,没有收到Friend Update又分为两种情况:
Friend节点没有响应
Friend节点响应了,但是LPN由于干扰而没有收到
接着上述的LPN发送的Friend Poll消息,那么此时朋友节点就会回复该消息给LPN;到了这个阶段,朋友节点这一端就认为其与LPN的友谊的关系已经建立了;如果LPN相对应也接收到Friend Update消息,那么LPN此时也认为其与朋友节点的友谊关系建立完成;同时,该消息还有如下的作用:
朋友节点通知LPN安全材料已经变化或者正在变化
安全材料指的就是Key Refresh Flag,IV Update Flag和IV Index,只要这三个中的任何一个变化,朋友节点都会将LPN发送该消息;这三个参数,小编在Mesh Beacon帧格式也有提及
朋友队列为空
这个又是什么意思呢?这个主要用于朋友节点告诉LPN,你存在我这边的缓存我都发给你了,在下一个Poll间隔之前不用再向我发POLL消息了;至于朋友队列的详细内容,小编会在Friend Queue中讲解
还没有建立友谊关系之前,收到LPN的Friend Poll消息,朋友回复该消息给LPN,这样LPN收到该消息之后就认为友谊关系已经建立
具体的帧格式如下所示:
Field | Size(octets) | Notes |
---|---|---|
Flags | 1 | Contains the IV Update Flag and the Key Refresh Flag |
IV Index | 4 | The current IV Index value known by the Friend node |
MD | 1 | Indicates if the Friend Queue is empty or not |
Flags
Bit | Definition |
---|---|
0 | Key Refresh Flag, 0:Not-In -Phase2 1:In -Phase2 |
1 | IV Update Flag, 0:Normal operation 1:IV Update active |
2–7 | Reserved for Future Use |
IV Index
表示朋友节点当前的IV Index值
MD
Value | Description |
---|---|
0 | Friend Queue is empty |
1 | Friend Queue is not empty |
2–255 | Prohibited |
同样的,该消息有如下几点需要注意:
至此,所有的友谊建立过程就已经介绍完成了;然而,上述的内容都相对比较离散,那么整个友谊建立流程是怎么样的呢?如下图所示:
当友谊关系建立之后,接下来的日常工作就是LPN隔一段时间就会向Friend节点发送Poll消息,而朋友节点就response消息给LPN,这也就是说此时它们两者之间的交互就仅剩Friend Poll、Friend Update以及缓存在Friend Queue的消息了;但是,除了上述的三个消息之外,可能还会存在如下几个消息的交互:
那这些消息在建立友谊关系之后,又是如何发挥它们的作用的呢?接下来,小编将一一给大家徐徐道来。
Friend Poll消息在整个友谊关系的生命周期中,占据了很大的数据流量,它没有什么其他的作用,LPN发这个消息就是向朋友节点索取暂存在Friend Queue中的消息。LPN之所以能省电也是得益于此该消息,如上述的Friendship Established中所说,LPN会隔一段时间向朋友节点发送Poll消息,从而得到Mesh网络中其他节点发送给LPN的消息。那么,LPN具体又是如何来运作的呢?小编这里先抛出两个参数:
Poll Interval
该参数就表示当友谊关系建立之后,LPN向朋友节点发送Friend Poll的间隔时长;那么问题来了:“这个间隔应该设置为多少才适合?是否可以随便设置?” 在开始讲解这个之前,小编先给大家看个图:
从上图我可以看到,单个Poll事件不是只发了一次Friend Poll,而且Poll Interval也不是指的单个Poll事件中的每个Friend Poll消息发送的时间间隔;其实,上图表达的含义已经很明显了;
单个Poll事件
其指的是LPN从朋友节点中取数据,直至返回MD域的值为0;这个时候又会有读者会问:“如果数据连绵不绝地传送LPN,那岂不是一下子就超出Poll Timeout的时间了?” 非也,非也;其实Poll Timeout其仅用于Friend Node计时;所以,单个Poll事件也就是LPN唤醒的那一刻起到取完朋友节点为其缓存的消息为止;那么,问题又来了 “单个poll事件里的Friend Request消息间隔又是多少?”,其实Spec并没有对此有相关规定,但是Nordic定义该间隔为50ms,其他的厂商该值可能不同而不同;
由上图可以看到,除去ReceiveDelay的100ms以及ReceiveWindow的5ms,剩下的就是单个poll事件中poll消息的间隔为50ms;为了让读者更加了解什么是单个poll事件,小编在这里再次上图:
而LPN的Poll Timeout是用于计算Poll Interval,为了能让LPN发送尽可能多的发Poll消息,所以Poll Interval就跟Poll Timeout挂钩了;例如:LPN和Friend Node短期间互相收不到对方的消息时,如果Poll Interval不按规矩来设置,那么在单个poll事件中就极有可能发没几个Poll消息,Friend节点那端就Poll Timeout;说了这么多,那么Poll Interval又是如何计算的,具体如下所示:
Poll Interval < Poll TimeOut - (ReceiveDelay + ReceiveWindow)*(POLL_ATTEMPTs+1);其它的参数上述均已提及,其中POLL_ATTEMPtS表示LPN发送Friend Poll消息的尝试次数
如上述的图示,那么此时Poll Interval应小于 (10000ms - (100+5) * 6 = 9370ms),即此时每个单Poll事件的时间间隔不要大于9370ms,也就是说从Friend Update结束到下一个Friend Request的时间;但是,Nordic的SDK首次默认的Poll Interval值却是等于Poll TimeOut - (ReceiveDelay + ReceiveWindow) * (POLL_ATTEMPTs+1) 即9370ms
Poll Timeout
该时间参数主要是朋友节点在使用,用于计时接收到来自于LPN的Poll消息,如果在Poll Timeout之前仍然还没有收到Poll消息,那么一超时Friend Node就认为其与对应LPN的友谊就断了,也就是说不再为该LPN缓存消息了;但是,只要收到LPN的Poll消息,那么朋友节点端的Poll Timeout就会重新计时
由上述的Friend Update可知,在建立友谊的过程中,朋友节点给LPN发送过一次Update消息,用于让LPN确定其与Friend节点的友谊建立完成;那么,友谊关系建立之后有如下两种情况,仍然会给LPN发送Update消息:
安全材料更新
当IV Update Flag、Key Refresh Flag以及IV Index发生变化时,朋友节点会向LPN发送Update消息
Friend Queue为空
在单个Poll事件中,获取缓存在Friend Queue的数据,直至数据被取完之后,朋友节点会向LPN发送Update消息(MD=0),告诉对方你在我这边的数据已经被你取完了
顾名思义,朋友队列用于缓存发送给LPN的底层传输PDUs,同时也会一并缓存CTL、TTL、SEQ以及DST等Network PDU的内容;这里还需要注意的是,朋友队列不是指的朋友节点为其所有LPN缓存的队列,而是每个LPN都会对应一个Friend Queue;因此,这就会带来两个问题:
那么,什么样的消息才会在朋友队列中缓存呢?
众所周知,朋友队列能缓存的消息是有限的;如果遇到Friend Queue已经满了,但是又有新的消息需要缓存;针对这种情况,为了腾出空间来,这个时候最先缓存的消息将会被丢掉,而且如果新消息的长度比较长,有可能会连续丢弃好几个先缓存的消息 (不包括Friend Update消息,这里的Friend Update指的是IV Update或者Key Refresh时的情形);
前面我们已经提及到Friend Queue的长度是有限的,只要已经被LPN从队列中取出来的消息,那么其就从队列中移出;这个时候问题来了 “朋友节点是如何知道其现在可以将该消息移出朋友队列?” 不知道读者还记不记得上述的Friend Poll.FSN,朋友节点只要接收到LPN的Poll消息,且其携带的FSN域值与上次接收到的值不同,这个时候Friend节点就认为LPN已经从Friend Queue中取出缓存的消息了,同时将上次的消息从队列中移出;
最后,如果朋友队列为空,但是朋友节点此时接收到来自于LPN的Friend Poll消息,这个时候也会产生一个 Friend Update(MD=0) 消息返回给LPN;
该命令由LPN向Friend节点发送,用于通知朋友节点让其帮助缓存目标地址为订阅列表中的地址的消息,该命令的帧格式如下所示:
Field | Size(octets) | Notes |
---|---|---|
TransactionNumber | 1 | The number for identifying a transaction |
AddressList | 2 * N | List of group addresses and virtual addresses where N is the number of group addresses and virtual addresses in this message |
Transaction Number
显然该域用于表示每次传输该消息时的索引号,从0开始;每次有新的该消息,该域值都会加1;相对应的,朋友节点用Friend Subscription List Confirm消息且用相同的Transaction Number应答该消息
AddressList
该域表示增加至朋友订阅列表(Friend Subscription List)中的组地址(Group Address)和虚拟地址(Virtual Address)的列表;需要注意的是当该消息是未分段的控制消息时,该域的值不能超过5个地址
不过对于该消息,仍然有以下几点需要注意:
显然,该消息跟上述的Friend Subscription List Add消息是相反的操作;除此之外,其他的所有内容都是一样的;但是,Transaction Number却是共同使用的;什么意思呢?意思就是说如果上一个Friend Subscription List Add消息发出去的时候,Transaction Number是0x00;那么,下一个Friend Subscription List Remove就是0x01;
该消息是用于应答上述的Friend Subscription List Remove以及Friend Subscription List Add消息,其具体的帧格式如下表所示:
Field | Size(octets) | Notes |
---|---|---|
TransactionNumber | 1 | The number for identifying a transaction |
其中,Transaction Number应该与接收到的Friend Subscription List Remove或者Friend Subscription List Add中的Transaction Number一致;
顾名思其义,该消息用于通知Friend Node,要与其解除友谊关系;其具体的帧格式如下表所示:
Field | Size(octets) | Notes |
---|---|---|
LPNAddress | 2 | The unicast address of the Low Power node being removed |
LPNCounter | 2 | Value of the LPNCounter of new relationship |
LPNAddress
该域表示要解除友谊关系的LPN的单播地址
LPNCounter
该域则表示要解除友谊关系的LPN最后发送的Friend Request消息的LPNCounter
我想此时大部分读者会有这样的一个疑问:“该消息到底是由谁发给Friend Node以及什么时候会发该消息?”
who
when
为了方便阐述上述的内容,仍然是老规矩:上图!!!
由上图可知,一旦LPN与新的Friend节点建立了友谊关系之后,新的Friend节点就会马上向旧的Friend节点发送Friend Clear;这个时候,聪明的读者肯定有这样的疑问:“要是旧的Friend节点短时间内没有收到Friend Clear,或者新的Friend节点没有收到Friend Clear Confirm消息要怎么办?新的朋友节点一直这样子发下去吗?”,显然制定SIG Mesh标准的那些大佬同样也想到了这样的问题,为了有效地解决这个问题,他们又提出了以下两个时间参数:
Friend Clear Repeat Timer
该时间参数表示发送Friend Clear消息的时间间隔,开始值为1秒;如果1秒过后,仍然还没有收到Friend Clear Confirm消息,则下一次发送Friend Clear消息就是2秒之后,这也就是说下一次要发送的Friend Clear消息就是上一次的时间间隔的2倍;如果Friend Clear Confirm消息被收到,那么就停止Friend Clear Repeat Timer计时
Friend Clear Procedure Timer
该时间参数定义了整个Friend Clear进程的时间,也就是说不管有没有收到Friend Clear Confirm消息,这个时间一超时的话,Friend Clear Repeat Timer也将会停止计时,不再发送Friend Clear消息;当然,如果Friend Clear Confirm消息被收到,Friend Clear Procedure Timer也会被停止计时;至于,Friend Clear Procedure Timer的时间参数设置为2倍的Poll TimeOut
注意,该消息使用Master安全凭证加解密,该方面的内容我们会放到Friendship Security中讲解;
该消息显然是用于回复Friend Clear消息,由旧的朋友节点发出来;其帧格式跟Friend Clear消息是一模一样的,也就是说Friend Clear消息的内容是什么,回复的Friend Clear Confirm的消息内容就是什么;如果接收到的Friend Clear消息的TTL域值为0,那么回复的Friend Clear Confirm消息的TTL域值也为0;同样的,该消息也是使用Master安全凭证加解密,该方面的内容我们会放到Friendship Security中讲解;
我们都知道,整个Mesh网络中的数据交互都是通过层层加密的;对于LPN与Friend节点之间的数据也不例外,它们所使用的跟普通的Network PDUs交互不同的密钥,但是它们都是由NetKey派出来的密钥;前者叫Friend Security Material,而后者叫Master Security Material:
Master Security Material
整个Mesh网络中的普通Mesh数据则是由该主安全材料来加解密,其由下述公式计算获得:
NID || EncryptionKey || PrivacyKey = k2(NetKey, 0x00)
Friend Security Material
该安全材料则用于建立友谊之后,LPN与Friend节点的数据交互的加解密,其由下述公式计算获得:
NID || EncryptionKey || PrivacyKey = k2(NetKey, 0x01 || LPNAddress || FriendAddress || LPNCounter || FriendCounter)
LPNAddress
LPN首要元素的单播地址
FriendAddress
Friend节点的首要元素的单播地址
LPNCounter
LPN发送Friend Request时的LPNCounter域值
FriendCounter
朋友节点发送Friend Offer时的FriendCounter域值
不知道读者还对BLE Mesh各层帧包格式详解里的内容有没有印象,其中PrivacyKey用于加解密obfuscated的内容,而EncryptionKey用于加解密DST和Transport PDU的内容;
至于,在整个LPN与Friend节点的友谊关系过程中,哪些消息是用的Master Security Material?哪些是用的Friend Security Material? 仍然是老规矩:上图!!!
由上图我们可以清晰地知道:
Master Security Material
Friend Security Material
至于,为什么Friend Request和Friend Offer它们两个用的是Master Security Material,我们可以从上述的Friend Security Material可知,必须知道了LPNCounter、FriendCounter、LPNAddress、FriendAddress之后,才可以计算得到Friend Security Material;根据上图,小编重点讲解一下InMsg、OutMsg1/2:
InMsg
该消息进来的时候,使用的是Master Security Material,当LPN向Friend节点发送Poll消息时,朋友节点则使用Friend Security Material将InMsg发送给LPN
OutMsg1
该消息由LPN使用Friend Security Material发送出去,这也就意味着只有与其建立了友谊关系的Friend节点才能解析该消息;当Friend节点收到之后并解析,然后使用Master Security Material,将数据发送出去
OutMsg2
由于该消息使用Master Security Material发送,因此LPN射频范围内的其他Relay节点以及其Friend节点均可以接收到该消息,并同样使用使用Master Security Material发送出去;从这一点,我们就可以间接地获取到另外一信息:LPN想要将数据发送到整个Mesh网络中,可以不经过Friend节点中继,可以直接发往Mesh网络中去,但是前提必须使用Master Security Material
最后,总结一下上述所涉及到Friendship消息的操作码(Opcode)
Value | Opcode | Notes |
---|---|---|
0x00 | - | Reserved for lower transport layer |
0x01 | Friend Poll | Sent by a Low Power node to its Friend node to request any messages that it has stored for the Low Power node |
0x02 | Friend Update | Sent by a Friend node to a Low Power node to inform it about security updates |
0x03 | Friend Request | Sent by a Low Power node the all- friends fixed group address to start to find a friend |
0x04 | Friend Offer | Sent by a Friend node to a Low Power node to offer to become its friend |
0x05 | Friend Clear | Sent to a Friend node to inform a previous friend of a Low Power node about the removal of a friendship |
0x06 | Friend Clear Confirm | Sent from a previous friend to Friend node to confirm that a prior friend relationship has been removed |
0x07 | Friend Subscription List Add | Sent to a Friend node to add one or more addresses to the Friend Subscription List |
0x08 | Friend Subscription List Remove | Sent to a Friend node to remove one or more addresses from the Friend Subscription List |
0x09 | Friend Subscription List Confirm | Sent by a Friend node to confirm Friend Subscription List updates |
0x0A | Heartbeat | Sent by a node to let other nodes determine topology of a subnet |
0x0B-0x7F | RFU | Reserved for Future Use |
至此,所有Friend Node与Low Power Node之间的错综复杂的关系就讲解完成了;由于COIVD-19疫情的影响,导致该篇章用了断断续续将近一个月的时间才完结,不管怎么样最终还是美满结束。