目的
- 此文档的目的在于引导读者思考蓝牙mesh行为,并非一篇完善的mesh行为描述文档。
什么是蓝牙mesh的行为
- 蓝牙mesh的行为就是指,一个设备在处于某些特定的角色,并开启特定特性时,他是如何组网,并如何进行加解密的,如何进行数据流的传递的,等等,在mesh规范中,常常标有behavior的字样,但规范最大的缺陷是,采用分散描述,并无对某完整的过程进行串行描述,这使得从整体上把握mesh的行为显得比较困难。
举例说明什么是蓝牙mesh的行为
背景描述
- 假设有一个手机和一个灯,手机可以作为蓝牙主设备与灯进行GATT连接,灯可进行GATT连接的同时又能进行广播数据的发送,灯将relay和proxy特性打开,手机可以作为一个provisioner对灯进行组网操作,那么请描述手机对灯进行GATT连接后的组网过程,配置过程,控制过程等过程的具体行为。
一种行为描述
- 首先,灯是一个未组网设备,会进行广播,广播分为两种,一种为可连接的未组网广播,另一种为不可连接的未组网网络信标广播,这两者交替进行;
- 另外,灯设备也会加载provisioning service,并在可连接广播中暴露其服务类型;
- 手机APP端,会扫描周围灯的可连接的未组网广播,根据广播的AD Type可找到它,最后显示到手机app列表;
- 手机APP通过BLE连接灯设备,连接后进行service discovery过程,并获取设备的provisioning service,之后使能notify;
- 然后APP就可以通过发送代理协议数据给灯设备,且灯设备也可以通过代理协议返回应答数据了;
- 首先说组网过程,其中手机充当provisioner角色,此时其代理协议数据类型MessageType为 Provisioning PDU (0x03):
- 手机发送 Provisioning invite
- 灯返回 Provisioning capabilities
- 手机发送 Provisioning start
- 手机发送 Provisioning Public Key
- 灯返回 Provisioning Public Key
- 手机发送 Provisioning Confirmation
- 灯返回 Provisioning Confirmation
- 手机发送 Provisioning Random
- 灯返回 Provisioning Random
- 手机发送 Provisioning Data (包含会话密钥)
- 灯返回 Provisioning Complete
- 手机主动断开连接。
- 灯组网完成。
- 特别说明:以上过程,每个发送或者返回都可能要分段,数据包长度大于BLE的MTU就要分段,分段采用的策略为代理分段策略,主要控制字段为SAR和Message Type。这与Lower transport layer的分段策略没有任何关系。
- 通过以上过程,灯就变为一个节点了,已经具备了设备密钥,网络密钥,但还没有应用密钥。
- 因为灯节点已经是已组网状态,所以灯节点将provisioning service更改为proxy service
- 同时灯节点变更广播内容,将广播内容改为可连接的node identity广播和不可连接的secure network beacon广播(即安全网络信标)
- 手机APP重新扫描node id广播,并与之建立GATT连接,之后发现proxy service,然后使能notify
- 接下来,手机就要对灯节点进行组网后的配置过程了,其中手机充当proxy client,而灯节点则充当proxy server角色。
- 接下来通过收发以下消息设置地址过滤器 ,此时其代理协议数据类型MessageType为 Proxy Configuration (0x02):
- 手机发送 Set Filter Type message
- 灯返回 Filter Status message
- 手机发送 Add Addresses to Filter message
- 灯返回 Filter Status message
- 地址过滤器设置好后,则可通过以下消息获取灯节点的组成数据, 此时其代理协议数据类型MessageType为 Network PDU (0x00):
- 手机发送 Config Composition Data Get
- 灯节点返回 Config Composition Data Status
- 手机发送 Seg Ack Msg(For Config Composition Data Status) :因为我把双方MTU都设置为23了,所以灯节点返回组成数据时在Lower transport layer层分段了,所以手机需要返回该分段应答消息来确认,即告诉灯节点,我收到了你发过来的所有段。(说明:如果只收到了部分段的话,手机也会返回该指令,但后续流程就不一样了,后续灯设备需要补发缺失的段,直到手机发送的ACK中提示自己收到所有的段为止。这是network PDU分段发送专有的应答机制,这种通信增加了传输的可靠性。只要代理协议数据类型MessageType为 Network PDU (0x00)的数据包,如果发生分段,都需要应答确认,后续不再赘述)
- 通过以上composition data的获取过程,手机APP了解了灯节点支持哪些feature(例如relay和proxy等),也知道了灯节点由哪些模型(比如general on off service等)组成,同时也知道灯节点的CID、PID、VID、RPL(中继保护列表)数量等等;
- 接下来,就可以给灯节点下发应用密钥了, 此时其代理协议数据类型MessageType为 Network PDU (0x00),相关指令如下:
- 手机发送 Config AppKey Add
- 灯节点返回 Config AppKey Status
- 接下来,就可以给灯节点模型绑定应用密钥了,此时其代理协议数据类型MessageType为 Network PDU (0x00),相关指令如下:
- 手机发送 Config Model App Bind
- 灯节点返回 Config Model App Status message
- 。。。。。
- 一般上面发送的指令是成对儿出现的,一次只能给一个模型绑定一个应用密钥,如果有多个模型需要绑定应用密钥,就要发送多次上面的组合,我共绑定了七个模型到上面下发的那个密钥上。
- 密钥绑定完毕,则配置过程就完毕了,此时手机端和灯节点,均有网络密钥和应用密钥了(当然也有设备密钥--组网生成),且所有模型也都绑定了应用密钥。后续就可以通过手机发送指令控制灯的亮灭了。
- 控制灯节点亮灭的指令,我没有详细研究,但也是Network PDU的数据,流程与composition data 、appKey下发、appKey绑定等过程相同,后面研究后添加上。
- 上面就是一个关于mesh行为描述的举例,虽然描述的并不十分完整,但也比直接看规范更能将整个mesh的通讯行为串起来了,更容易弄明白了,我觉得我们需要更多这样的行为描述。
其它行为疑问
- 对于Network PDU,GATT Client发送的数据是如何通过由代理协议转化为网络层数据的?网络层数据又是如何转化为lower传输层的?lower传输层又是如何传递给upper传输层的?upper传输层又是如何传递给access层的?access层又是如何传输给model层的?模型层处理完数据,应答数据回传的逆向过程又是怎样进行的?等等。
- 上面提到了灯节点开启了relay和proxy的特性,且手机通过GATT实施代理协议给灯节点发送的provisioning数据、配置过滤器数据、获取composition数据、下发应用密钥数据、下发绑定应用密钥数据、下发灯控命令数据等等,那这其中的哪些数据需要通过ADV BEARER(广播承载)发送出去呢?哪些不需要呢?如果只打开relay特性,关闭proxy特性,又应该怎样呢?如果只打开proxy特性,关闭relay特性,又应该怎样呢?如果两个特性都关闭,又该怎样呢?