<!--

前言

继前面章节的Proxy和Relay节点之后,该篇将讲深入讲解朋友节点的作用及其工作的流程。其在整个BLE Mesh网络中是极其重要的一个特性,甚至可以认为如果没有朋友这个特性的话,BLE Mesh是不完整的或者说是有缺陷的;因为IoT领域充斥着大量的由电池供电的低功耗设备,这也导致需要一个特别的设备来临时缓存这些低功耗设备的信息,在BLE Mesh中我们称这个特殊的设备为朋友节点,而其他的Mesh网络则称之为父节点;反之,低功耗设备就称为低功耗节点;但是,它们本质的功能都是相同的。

由上图可以看出,朋友节点与低功耗设备的关系是树状通讯模型。

FriendShip

在整个BLE Mesh网络中朋友节点的作用就是帮周边的低功耗节点缓存消息;为了保持这种纯洁的友谊,Spec专门定义了以下相关的时间参数来维护它们之间的关系。

基本上整个朋友节点与低功耗节点的数据交互 (这里指的是友谊关系建立之后的情况),均是建立在上述Spec规定的时间参数上。

Establishment of a friendship

如果Friend节点要帮忙缓存周边低功耗设备的消息,低功耗设备就必须跟Friend节点建立关系,然后一直维持这段关系;否则,这种友谊关系就会断了;老规矩先直接上图:

由上面的两幅图,我们可以大概了解到友谊是如何建立的;这其实跟我们平时相亲的过程是极度类似的,先亮家底然后挑选一个喜欢的妹纸或者男子耍朋友;但是如果以后没精力去维护这段感情的话,那么就很容易导致分手或者离婚。接下来,由小编带领读者看看它们是如何耍朋友的:

Friend Request

当LPN需要朋友节点帮其缓存信息的时候,它会向其周边的所有朋友节点发送Friend Request消息 (这意味着该消息的目标地址为0xFFFD),该消息的帧格式如下所示:

Field NameSize(octets)Notes
Criteria1The criteria that a Friend node should support in order to participate in friendship negotiation
ReceiveDelay1Receive delay requested by the Low Power node
PollTimeout3The initial value of the PollTimeout timer set by the Low Power node
PreviousAddress2Unicast address of the primary element of the previous friend
NumElements1Number of elements in the Low Power node
LPNCounter2Number of Friend Request messages that the Low Power node has sent

至此,Friend Request的全部内容都讲完了,这也是交朋友的第一步;但是,小编觉得还有如下几点是需要注意的:

Friend Offer

当朋友节点接收到Friend Request之后,如果Friend Node符合其提及的Criteria内容,那么就响应该请求,其具体的内容如下表所示:

FieldSize(octets)Notes
ReceiveWindow1Receive Window value supported by the Friend node
QueueSize1Queue Size available on the Friend node
SubscriptionListSize1Size of the Subscription List that can be supported by a Friend node for a Low Power node
RSSI1RSSI measured by the Friend node
FriendCounter2Number of Friend Offer messages that the Friend node has sent

至于,朋友节点接收到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的间隔时长,其中该计算公式的各个参数来自于不同的消息:

上述的公式再配合前面提及到的实际的友谊建立过程,我相信读者此时对Local Delay已经相对了解了吧。但是,Local Delay还有一点需要读者们注意:

如果计算出来的Local Delay的值大于100,那么实际的友谊建立过程中的Delay值,也就是Friend Offer Delay就等于Local Delay毫秒;否则,Delay值直接等于100ms

为了加深大家的理解,这里小编用实际捉包的示程向大家展示Local DelayFriend RequestFriend Offer之间的关系:

由上图我们可以得知:

Local Delay = ReceiveWindowFactor * ReceiveWindow - RSSIFactor * RSSI = 1* 5 - 2* 225 = -445 < 100

所以,Local Delay = 100ms。同样的,如下两点是需要注意的:

Friend Poll

LPN节点根据众多的朋友节点返回的Friend Offer中,选择最符合自己要求的一个Friend Node,然后向其发送Friend Poll消息;至于,LPN是如何选择最符合的Friend节点?

一般最先接收到Friend Offer消息的那个朋友节点就是最适合的,因为离LPN最近且LPN要求的Criteria的条件也满足;当然,用户可以继续监听其他的Friend节点,再根据Criteria的条件选择想要的Friend节点;

如果Friend Node接收该消息的话,就会返回Friend Update;除了该功能之外,该消息还用于建立友谊之后,获取朋友节点为LPN缓存的消息;该消息的帧格式如下表所示:

FieldSize(bits)Notes
Padding70b0000000. All other values are Prohibited
FSN1Friend Sequence Number, used to acknowledge receipt of previous messages from the Friend node to the Low Power node

其中,FSN域主要的作用如下:

同样的,该消息有如下几点需要注意:

Friend Update

接着上述的LPN发送的Friend Poll消息,那么此时朋友节点就会回复该消息给LPN;到了这个阶段,朋友节点这一端就认为其与LPN的友谊的关系已经建立了;如果LPN相对应也接收到Friend Update消息,那么LPN此时也认为其与朋友节点的友谊关系建立完成;同时,该消息还有如下的作用:

具体的帧格式如下所示:

FieldSize(octets)Notes
Flags1Contains the IV Update Flag and the Key Refresh Flag
IV Index4The current IV Index value known by the Friend node
MD1Indicates if the Friend Queue is empty or not

同样的,该消息有如下几点需要注意:

至此,所有的友谊建立过程就已经介绍完成了;然而,上述的内容都相对比较离散,那么整个友谊建立流程是怎么样的呢?如下图所示:

Friendship Established

当友谊关系建立之后,接下来的日常工作就是LPN隔一段时间就会向Friend节点发送Poll消息,而朋友节点就response消息给LPN,这也就是说此时它们两者之间的交互就仅剩Friend PollFriend Update以及缓存在Friend Queue的消息了;但是,除了上述的三个消息之外,可能还会存在如下几个消息的交互:

那这些消息在建立友谊关系之后,又是如何发挥它们的作用的呢?接下来,小编将一一给大家徐徐道来。

Friend Poll After establishment

Friend Poll消息在整个友谊关系的生命周期中,占据了很大的数据流量,它没有什么其他的作用,LPN发这个消息就是向朋友节点索取暂存在Friend Queue中的消息。LPN之所以能省电也是得益于此该消息,如上述的Friendship Established中所说,LPN会隔一段时间向朋友节点发送Poll消息,从而得到Mesh网络中其他节点发送给LPN的消息。那么,LPN具体又是如何来运作的呢?小编这里先抛出两个参数:

Friend Update After establishment

由上述的Friend Update可知,在建立友谊的过程中,朋友节点给LPN发送过一次Update消息,用于让LPN确定其与Friend节点的友谊建立完成;那么,友谊关系建立之后有如下两种情况,仍然会给LPN发送Update消息:

Friend Queue

顾名思义,朋友队列用于缓存发送给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;

Friend Subscription List Add

该命令由LPN向Friend节点发送,用于通知朋友节点让其帮助缓存目标地址为订阅列表中的地址的消息,该命令的帧格式如下所示:

FieldSize(octets)Notes
TransactionNumber1The number for identifying a transaction
AddressList2 * NList of group addresses and virtual addresses where N is the number of group addresses and virtual addresses in this message

不过对于该消息,仍然有以下几点需要注意:

Friend Subscription List Remove

显然,该消息跟上述的Friend Subscription List Add消息是相反的操作;除此之外,其他的所有内容都是一样的;但是,Transaction Number却是共同使用的;什么意思呢?意思就是说如果上一个Friend Subscription List Add消息发出去的时候,Transaction Number是0x00;那么,下一个Friend Subscription List Remove就是0x01

Friend Subscription List Confirm

该消息是用于应答上述的Friend Subscription List Remove以及Friend Subscription List Add消息,其具体的帧格式如下表所示:

FieldSize(octets)Notes
TransactionNumber1The number for identifying a transaction

其中,Transaction Number应该与接收到的Friend Subscription List Remove或者Friend Subscription List Add中的Transaction Number一致;

Friend Clear

顾名思其义,该消息用于通知Friend Node,要与其解除友谊关系;其具体的帧格式如下表所示:

FieldSize(octets)Notes
LPNAddress2The unicast address of the Low Power node being removed
LPNCounter2Value of the LPNCounter of new relationship

我想此时大部分读者会有这样的一个疑问:“该消息到底是由谁发给Friend Node以及什么时候会发该消息?”

为了方便阐述上述的内容,仍然是老规矩:上图!!!

由上图可知,一旦LPN与新的Friend节点建立了友谊关系之后,新的Friend节点就会马上向旧的Friend节点发送Friend Clear;这个时候,聪明的读者肯定有这样的疑问:“要是旧的Friend节点短时间内没有收到Friend Clear,或者新的Friend节点没有收到Friend Clear Confirm消息要怎么办?新的朋友节点一直这样子发下去吗?”,显然制定SIG Mesh标准的那些大佬同样也想到了这样的问题,为了有效地解决这个问题,他们又提出了以下两个时间参数:

注意,该消息使用Master安全凭证加解密,该方面的内容我们会放到Friendship Security中讲解;

Friend Clear Confirm

该消息显然是用于回复Friend Clear消息,由旧的朋友节点发出来;其帧格式跟Friend Clear消息是一模一样的,也就是说Friend Clear消息的内容是什么,回复的Friend Clear Confirm的消息内容就是什么;如果接收到的Friend Clear消息的TTL域值为0,那么回复的Friend Clear Confirm消息的TTL域值也为0;同样的,该消息也是使用Master安全凭证加解密,该方面的内容我们会放到Friendship Security中讲解;

Friendship Security

我们都知道,整个Mesh网络中的数据交互都是通过层层加密的;对于LPN与Friend节点之间的数据也不例外,它们所使用的跟普通的Network PDUs交互不同的密钥,但是它们都是由NetKey派出来的密钥;前者叫Friend Security Material,而后者叫Master Security Material:

不知道读者还对BLE Mesh各层帧包格式详解里的内容有没有印象,其中PrivacyKey用于加解密obfuscated的内容,而EncryptionKey用于加解密DST和Transport PDU的内容;

至于,在整个LPN与Friend节点的友谊关系过程中,哪些消息是用的Master Security Material?哪些是用的Friend Security Material? 仍然是老规矩:上图!!!

由上图我们可以清晰地知道:

至于,为什么Friend RequestFriend Offer它们两个用的是Master Security Material,我们可以从上述的Friend Security Material可知,必须知道了LPNCounterFriendCounterLPNAddressFriendAddress之后,才可以计算得到Friend Security Material;根据上图,小编重点讲解一下InMsgOutMsg1/2

最后,总结一下上述所涉及到Friendship消息的操作码(Opcode)

ValueOpcodeNotes
0x00-Reserved for lower transport layer
0x01Friend PollSent by a Low Power node to its Friend node to request any messages that it has stored for the Low Power node
0x02Friend UpdateSent by a Friend node to a Low Power node to inform it about security updates
0x03Friend RequestSent by a Low Power node the all- friends fixed group address to start to find a friend
0x04Friend OfferSent by a Friend node to a Low Power node to offer to become its friend
0x05Friend ClearSent to a Friend node to inform a previous friend of a Low Power node about the removal of a friendship
0x06Friend Clear ConfirmSent from a previous friend to Friend node to confirm that a prior friend relationship has been removed
0x07Friend Subscription List AddSent to a Friend node to add one or more addresses to the Friend Subscription List
0x08Friend Subscription List RemoveSent to a Friend node to remove one or more addresses from the Friend Subscription List
0x09Friend Subscription List ConfirmSent by a Friend node to confirm Friend Subscription List updates
0x0AHeartbeatSent by a node to let other nodes determine topology of a subnet
0x0B-0x7FRFUReserved for Future Use

至此,所有Friend Node与Low Power Node之间的错综复杂的关系就讲解完成了;由于COIVD-19疫情的影响,导致该篇章用了断断续续将近一个月的时间才完结,不管怎么样最终还是美满结束。