Friend直接流程建立都是通过上层传输曾的控制PDU进行交互。控制消息大部分都为不分段消息,所以这一章我们以下层传输层的为分段消息作为PDU格式的总体示意图。
1. Friendship相关Control PDU
1.1. Friend Poll
由LPN发起,请求Friend发送LPN睡眠期间为LPN存储的消息。
Opcode=0x01,对应的Parameters如下所示:
Field | Size(bits) | Notes |
---|---|---|
Padding | 7 | 0b0000000,固定值 |
FSN | 1 | Friend Sequence Number |
TTL域设置为0。
消息使用friendship security credentials加密。
1.2. Friend Update
Friend通知LPN安全参数已经改变,或者当前消息队列为空。
Opcode=0x02,对应的Parameters如下所示:
Field | Size(octets) | Notes |
---|---|---|
Flags | 1 | 第0个bit表示当前的Key Refresh阶段 第1个bit表示当前的IV Update状态 第2-7位RFU |
IV Index | 4 | Friend节点当前的IV Index |
MD | 1 | MD=0:表明Friend Queue为空 MD=1:表明Friend Queue非空 |
Field | Notes |
---|---|
Key Refresh Flag | 0:未处于阶段2 1:处于阶段2 |
IV Update Flag | 0:未处于IV更新状态 1:处于IV更新状态中 |
TTL域设置为0。
消息使用friendship security credentials加密。
1.3. Friend Request
LPN发起,向所有Friend节点广播,希望与一个Friend建立Friendship。
Opcode=0x03,对应的Parameters如下所示:
Field | Size(octets) | Notes |
---|---|---|
Criteria | 1 | 表明要与本LPN建立Friendship,Friend应该具有的最低要求 |
ReceiveDelay | 1 | LPN端要求的ReceiveDelay 0x00-0x09:Prohibited 0x0A-0xFF:Receive Delay,单位1ms |
PollTimeout | 3 | LPN端设置的初始PollTimeout Timer值 0x000000-0x000009:Prohibited 0x00000A-0x34BBFF:PollTimerout,单位100ms 0x34BC00-0xFFFFFF:Prohibited |
PreviousAddress | 2 | 友尽前的前朋友地址 |
NumElement | 1 | 当前LPN节点的元素数量,通过该值和首元素地址可以计算出该LPN的非首元素的地址,从而保证能够缓存非首元素模型的消息。 0x00:Prohibited 0x01-0xFF:元素个数 |
LPNCounter | 2 | Request命令发送次数的计数 |
Field | Size(bits) | Notes |
---|---|---|
RFU | 1 | Reserved for Future Use |
RSSIFactor | 2 | RSSI计算精度 0b00:1 0b01:1.5 0b10:2 0b11:2.5 |
ReceiveWindowFactor | 2 | ReceiveWindow计算精度 0b00:1 0b01:1.5 0b10:2 0b11:2.5 |
MinQueueSizeLog | 3 | Friend队列能存储消息数量的最小值 0b000:Prohibited 0b001:2 0b010:4 0b011:8 0b100:16 0b101:32 0b110:64 0b111:128 |
TTL域设置为0。
消息使用master security credentials加密。
1.4. Friend Offer
Friend收到LPN发起的Request,觉得自己条件满足要求的,向LPN发起Offer,导师转身了。
Opcode=0x04,对应的Parameters如下所示:
Field | Size(octets) | Notes |
---|---|---|
ReceiveWindow | 1 | 本Friend支持的ReceiveWindow 0x00:Prohibited 0x01-0xFF:Receive Window,单位1ms |
QueueSize | 1 | Friend端提供的队列大小 |
SubscriptionListSize | 1 | Friend提供给该LPN的订阅表大小,Friend通过此表来判断该消息是否属于该LPN |
RSSI | 1 | 计算出来的我Friend与你LPN之间的RSSI值,表征两者之间的信号强度 |
FriendCounter | 2 | Offer命令发送次数的计数 |
TTL域设置为0。
消息使用master security credentials加密。
1.5. Friend Clear
新Friend与LPN建立了Friendship后,发送该消息通知LPN的前Friend,告诉他被抛弃了,需要自己把之前留给LPN的资源给回收了。
Opcode=0x05,对应的Parameters如下所示:
Field | Size(octets) | Notes |
---|---|---|
LPNAddress | 2 | 需要移除的LPN的单播地址 |
LPNCounter | 2 | 新的Friendship的LPNCounter值 |
新Friend发送此消息期待老Friend响应,若没有收到响应,则需要重发,每次重发的时间间隔为上一次的2倍,初始间隔时间为1s。
TTL域设置为0。(会不会导致Old Friend收不到New Friend的Clear消息??协议P85)
消息使用master security credentials加密。
1.6. Friend Clear Confirm
LPN的老Friend收到新Friend的Friend Clear消息后,向新Friend响应Confirm消息,表示这边知道了,你们放心耍。
Opcode=0x06,对应的Parameters如下所示:
Field | Size(octets) | Notes |
---|---|---|
LPNAddress | 2 | 需要移除的LPN的单播地址 |
LPNCounter | 2 | 收到的Friend Clear中的LPNCounter值 |
TTL域设置为0。(疑问同上??协议P85)
消息使用master security credentials加密。
1.7. Friend Subscription List Add
LPN发送此命令给Friend,告诉Friend需要添加订阅地址。
Opcode=0x07,对应的Parameters如下所示:
Field | Size(octets) | Notes |
---|---|---|
TransactionNumber | 1 | 交互的标记号,用于区分每个独立的消息 |
AddressList | 2*N | 需要添加的订阅地址(群组地址、虚拟地址) |
TTL域设置为0。
消息使用friendship security credentials加密。
当N>5时,会产生分段。
1.8. Friend Subscription List Remove
LPN发送此命令给Friend,告诉Friend需要删除订阅地址。
Opcode=0x08,对应的Parameters如下所示:
Field | Size(octets) | Notes |
---|---|---|
TransactionNumber | 1 | 交互的标记号,用于区分每个独立的消息 |
AddressList | 2*N | 需要删除的订阅地址(群组地址、虚拟地址) |
TTL域设置为0。
消息使用friendship security credentials加密。
当N>5时,会产生分段。
1.9. Friend Subscription List Confirm
Friend收到Subscription List Add/Remove后,需要响应Confirm,告诉LPN我这边已经收到了。
Opcode=0x09,对应的Parameters如下所示:
Field | Size(octets) | Notes |
---|---|---|
TransactionNumber | 1 | 交互的标记号,用于区分每个独立的消息 |
TTL域设置为0。
消息使用friendship security credentials加密。
2. Friendship建立流程
2.1. ReceiveDelay/ReceiveWindow/PollTimeout
LPN月Friend之间的通信LPN每一条消息都有Friend的响应。
ReceiveDelay:LPN发送一条消息后,开始监听Friend的响应之间的时间。(给Friend准备响应的时间??)
ReceiveWindow:LPN监听Friend的响应的窗口。收到Friend的响应后,关闭窗口,发送下一个请求;若窗口时间到仍未收到响应,需要重发上次消息。达到重发次数上限(一般是3次),就认为对端不在消息处理范围内,可能是没开机或者出故障了,所以LPN需要结束Friendship,再次向周围Friend发起建立Friendship的请求。
PollTimeout:两次连续的Friend Poll之间的最大时间间隔,即LPN单次的最大睡眠时间,Friend收到Friend Poll后,重置此timer。若PollTimeout时间到期,Friendship结束。在1.3可以知道,PollTimeout的取值范围为0x0A-0x34BBFF,单位是100ms,换算过来为1s-96h之间,为啥最大值是96h呢?因为IV更新流程的最大持续时长为96小时,这样保证了LPN不会错过IV的安全更新。
2.2. Friendship建立
建立流程如下:
① LPN向周围所有Friend发送Friend Request,表示他需要一个Friend为他保存数据。这里的Request消息TTL为0,保证只有直接收到消息的Friend才能收到Request。
② Friends收到Request后经过Friend Offer Delay的延迟后,向LPN发起Friend Offer,Friend发送Offer后期待1s内,LPN响应,若没有响应,则表示LPN未选择他 。
③ LPN在等待期间(发送Request后等待100ms,然后开启1s的等待窗口)收到的所有Offer中选择最满意的一个。给那个指定的Friend发送Friend Poll消息。若没有收到Offer,则再次发送Request,两次连续的Request之间的间隔至少为1.1s。
④ Friend收到Poll后,表示LPN选择了他,然后响应Friend Update消息,并向LPN的上一任Friend发送Friend Clear消息。
⑤ LPN收到Friend Update消息后,表明Friendship建立成功。
Friend Offer Delay体现当前LPN对信号强度和信号窗口期的重视度,通过不同的Delay,响应Offer,一是可以避免大量的Offer同时响应,导致信号拥堵,再者可以通过Factor的设置,优先过滤出想要的Friend。Friend Offer Delay的计算公式如下:
当Friend收到已于他建立了friendship的LPN的Friend Request请求,说明LPN认为friendship已断,或者LPN想换一个Friend,此时Friend应该结束LPN,并释放相关的资源。
3. Friend/LPN通信
在进行通信之前,需要对friendship进行配置。
3.1. Friendship配置
配置流程如下:
① LPN收到Friend的Update后,表示友谊建立成功。发送Friend Subscription List Add消息,将自己订阅表的地址发送给Friend。
② Friend收到Subscription List Add后,响应Friend Subscription List Confirm消息,表示地址添加成功。
配置时Add和Remove消息与对应的Confirm消息应有相同的TransactionNumber值。
配置完成后,就可以进行通信了。
3.1. Friendship通信
通信流程如下:
① 所有发给LPN的消息,Friend会根据LPN的PrimAddress和元素个数和订阅表判断是否属于LPN,然后把此消息存在Friend Queue中。(Friend节点为每个建立Friendship的LPN都维护了一个Friend Queue)
② LPN醒来后,向Friend发送Friend Poll,Friend收到Poll后,向LPN响应队列的第一条消息。
③ LPN收到消息后,再次向Friend发送Friend Poll,Friend依次把队列的消息响应给LPN,若此时队列为空,则响应MD=0的Friend Update消息。
④ LPN收到MD=0的Friend Update消息,表明Friend缓存的消息都收到了。LPN再次进入睡眠,等待下一次唤醒。
当Friend Queue满了的时候,收到新的消息不是Friend Update时,则抛弃最老的非Update消息,Update消息包含了网络安全KeyRefresh和IVUpdate,因此不能被普通消息替换掉。
若Friend Queue中有多个分段确认消息,其中仅仅只有IV和Seq不同,则抛弃过期的确认消息。
LPN发起Friend Poll时,所带参数的最后1bit为FSN,当收到Friend发送的存储消息后,下一次的Poll消息中的FSN会翻转,表示这条消息LPN收到了,若Friend收到的Poll消息中FSN未翻转,说明LPN未收到上一次的消息,这事Friend需要将上一次的消息再发一次。
4. Friendship安全
在建立Friendship期间,交换的数据中包含LPNAddress/FriendAddress/LPNCounter/FriendCounter以及NetKey共同生成friendship security material,只由NetKey生成的为master security material。在非LPN/Friend的条件下,均使用master加密。在LPN/Friend建连期间的控制命令使用master security material,配置和通信期间的控制命令使用friendship security material。
所以Friend Request/Offer/Clear/Clear Confirm使用master security material。
Friend Poll/Update/Subscription List Add/Remove/Confirm使用friendship security material。
Friend Queue存储的消息通过Publish Friendship Credentials Flag字段来选择friendship还是master加密,这个字段是由配置客户端配置节点Publication参数时配置的。
若LPN向外发的消息使用的friendship security material,则只有Friend能解析,Friend收到后,转化为master加密然后再中继出去。
5. LPN分段消息的收发
发给LPN的分段消息,Friend代替LPN接收,分段确认消息也由Friend发送给源节点。Friend重组完这个分段消息后才会放入Friend Queue中,等待LPN睡醒后来拿。
LPN主动向外发送分段消息,首先分段消息应该使用master加密,只有Friend才能解析friendship加密的消息。LPN发送所有分段后,向Friend发送Poll消息,期望收到Friend存储的Segmented Ack消息,根据收到的Ack消息再次重发对端未收到的分段,其余流程同普通分段消息发送。
在分段发送期间,LPN不会睡眠,因此不会存在timer超时的情况。
来源:CSDN
作者:蓬某某
链接:https://blog.csdn.net/wang_yunpeng/article/details/103805491