第3章 Mesh协议栈初探:分层结构与PDU格式

各位同学,今天我们来聊聊蓝牙Mesh的协议栈。说实话,我第一次接触Mesh协议栈时,也被那一堆层吓到了——Bearer、Network、Lower/Upper Transport、Access、Model……感觉像在爬一栋五层楼。但后来我发现,只要理解了每一层“管什么事”,这栋楼其实很好爬。

我个人习惯把协议栈比作一个快递系统。你想想看,Model层是“我要寄什么”,Access层是“写快递单”,Transport层是“打包分箱”,Network层是“贴路由标签”,Bearer层是“交给哪个快递员”。每一层只关心自己的事,不越界。这就是分层设计的精髓。

3.1 协议栈全景:五层架构

蓝牙Mesh协议栈从下到上分别是:

  • Bearer层:负责物理传输,比如通过BLE广播或GATT连接收发数据。
  • Network层:负责消息的路由、中继、加密和重放保护。
  • Lower Transport层:负责将大消息分片成小段,或把小段重组回大消息。
  • Upper Transport层:负责应用层加密、传输确认和心跳。
  • Access层:负责应用数据的格式化和操作码解析。
  • Model层:定义具体的行为,比如开关灯、传感器读数。

嗯,这里要注意:Model层其实不算严格意义上的“协议层”,它更像是一套标准行为模板。但为了方便理解,我们通常把它放在最上面。

核心观点:每一层只处理自己的PDU(协议数据单元),下层对上层的数据是“透明”的。你在Wireshark里看到的每一层头部,都是这一层自己加的。

蓝牙Mesh协议栈分层架构 蓝牙Mesh协议栈分层架构 Model层 Access层 Upper Transport层 Lower Transport层 Network层 Bearer层 说明: 每一层只处理自己的PDU,下层对上层数据“透明”。 Wireshark中看到的每一层头部,都是该层自己添加的。

3.2 Bearer层:数据怎么出门

Bearer层是协议栈的最底层,它决定了数据通过什么物理通道发送。蓝牙Mesh支持两种Bearer:

  • Advertising Bearer(PB-ADV):通过BLE广播信道发送,是Mesh的主要承载方式。节点之间不需要建立连接,直接广播。
  • GATT Bearer(PB-GATT):通过BLE GATT连接发送,主要用于手机App与Mesh节点通信,或者不支持广播的设备。

我在项目中遇到过一个问题:有些设备只支持GATT Bearer,但Mesh网络里大部分节点都用广播。这时候就需要一个“代理节点”来做协议转换。说白了,就是让一个节点同时支持两种Bearer,帮GATT设备转发消息到广播网络里。

实战技巧:抓包时,如果你看到的是广播包(ADV),那大概率是PB-ADV;如果你看到的是ATT Write/Notify,那就是PB-GATT。Wireshark里可以直接过滤 btmesh 协议,它会自动解析。

3.3 Network层:路由与安全的第一道门

Network层是Mesh协议栈的“交通警察”。它负责三件事:

  1. 消息中继:判断是否需要转发给邻居节点。
  2. 路由:根据TTL(生存时间)和源/目标地址决定消息走向。
  3. 网络层加密:使用Network Key对PDU进行加密和认证。

Network层PDU的格式是这样的:

Network PDU = IVI (1bit) + NID (7bit) + CTL (1bit) + TTL (7bit) + SEQ (24bit) + SRC (16bit) + DST (16bit) + Transport PDU (可变) + NetMIC (32bit或64bit)

嗯,这里要注意:IVI是IV Index的最低有效位,用于防止重放攻击。NID是Network ID,用来标识使用的是哪个Network Key。CTL位表示后面跟的是控制消息还是访问消息。

我曾经调试过一个奇怪的问题:某个节点总是收不到中继消息。抓包一看,TTL=0。原来配置工具把TTL设成了0,导致消息发不出去。你想想看,TTL=0意味着“别转发”,那中继节点当然不会理它。

避坑指南:我曾经在抓包时发现,有些设备发送的Network PDU里,SEQ号是乱序的。后来排查发现,是设备固件里的序列号计数器没做持久化,每次重启都从0开始。这会导致重放攻击防护失效。所以,SEQ号必须保存在非易失性存储里。

3.4 Lower Transport层:大消息的分片与重组

Lower Transport层解决一个实际问题:Network层一次最多只能传15字节的Payload(因为BLE广播包的限制)。如果你的应用数据超过15字节,怎么办?

答案就是分片。Lower Transport层把大消息切成多个Segment,每个Segment单独发送。接收端再把这些Segment重组回原始消息。

分片消息的格式如下:

Segmented Message:
  SEG (1bit) = 1 表示这是分片消息
  AKF (1bit) = 应用密钥标志
  AID (6bit) = 应用密钥ID
  SeqZero (13bit) = 序列号零,用于标识属于同一消息的所有分片
  SegO (5bit) = 当前分片编号
  SegN (5bit) = 总分片数减1
  SegmentData (可变)

非分片消息就简单多了:

Unsegmented Message:
  SEG (1bit) = 0
  AKF (1bit)
  AID (6bit)
  Upper Transport PDU (可变)

我记得有一次,客户反映某个灯控指令有时灵有时不灵。抓包后发现,指令被分成了3个Segment,但第2个Segment丢了。接收端等不到所有分片,超时后直接丢弃了。这就是典型的“分片丢失”问题。解决方案是降低分片数量,或者启用传输层确认。

3.5 Upper Transport层:应用层加密与传输控制

Upper Transport层是“应用数据的保险柜”。它负责:

  • 使用Application Key对Access Payload进行加密和认证。
  • 处理传输层确认(如果消息需要可靠传输)。
  • 处理心跳消息(Heartbeat)。

Upper Transport PDU的格式:

Upper Transport PDU = TransMIC (32bit) + Access PDU (可变)

这里要注意:TransMIC是传输层消息完整性校验码,用于验证数据是否被篡改。它和Network层的NetMIC不同,NetMIC保护的是整个Network PDU,而TransMIC只保护Access PDU。

关键点:Upper Transport层使用的密钥是Application Key,而Network层使用的是Network Key。这两把钥匙不一样。Network Key保护的是“谁在说话”,Application Key保护的是“说了什么”。

3.6 Access层:应用数据的格式化

Access层是协议栈的“翻译官”。它把上层Model发来的数据,格式化成标准的Access PDU,然后交给Transport层。

Access PDU的格式:

Access PDU = Opcode (1-3字节) + Parameters (可变)

Opcode分为两种:

  • 单字节Opcode:0x00-0x7F,用于标准Mesh模型。
  • 双字节Opcode:0x8000-0xBFFF,用于厂商自定义模型。
  • 三字节Opcode:0xC00000-0xFFFFFF,用于特殊用途。

举个例子,开关灯的命令:

Opcode: 0x8201 (Generic OnOff Set)
Parameters: 0x01 (表示开灯)

我在Wireshark里经常看到新手把Opcode和Parameters搞混。记住:Opcode告诉设备“你要干什么”,Parameters告诉设备“具体怎么干”。

3.7 Model层:行为定义

Model层是协议栈的“顶层应用”。它定义了设备的行为,比如:

  • Generic OnOff Server:开关灯。
  • Generic Level Server:调亮度。
  • Sensor Server:上报传感器数据。

Model层本身不产生PDU,它只是调用Access层的接口。说白了,Model层就是一套API规范,告诉开发者“你的设备应该支持哪些功能”。

实战建议:在Wireshark里分析Mesh流量时,我建议你从下往上逐层看。先看Bearer层确认物理通道,再看Network层确认路由和加密,最后看Access层确认具体操作。这样不容易漏掉关键信息。

3.8 各层PDU格式对比

为了方便你记忆,我把各层PDU的核心字段整理成了一张表:

协议层 核心字段 长度 作用
Network IVI, NID, CTL, TTL, SEQ, SRC, DST 9字节 + 可变 路由、中继、网络层加密
Lower Transport SEG, AKF, AID, SeqZero, SegO, SegN 2-3字节 + 可变 分片与重组
Upper Transport TransMIC 4字节 + 可变 应用层加密、传输确认
Access Opcode, Parameters 1-3字节 + 可变 应用数据格式化

嗯,这张表你最好收藏一下。每次抓包分析时,对照着看,能快速定位问题出在哪一层。

3.9 小结

这一章我们走了一遍Mesh协议栈的五层结构。从Bearer层的物理传输,到Network层的路由加密,再到Transport层的分片和加密,最后到Access和Model层的应用处理。每一层都有自己的PDU格式,每一层都只关心自己的事。