跳转至

MAVLink 2帧、消息、签名与路由

微型飞行器链路协议(MAVLink,Micro Air Vehicle Link)是面向资源受限飞行系统的消息封装与定义体系。它可以运行在串口、UDP、TCP、无线数传和进程间连接上,但不规定这些承载本身的可靠性。

MAVLink 2帧结构

线上顺序为:

顺序 字段 长度 含义
1 Magic 1字节 MAVLink 2为0xFD
2 Payload length 1字节 线上载荷长度,最大255
3 Incompatibility flags 1字节 未理解的置位项要求丢弃帧
4 Compatibility flags 1字节 未理解的置位项可忽略
5 Sequence 1字节 发送端链路序号
6 System ID 1字节 发送系统标识
7 Component ID 1字节 发送组件标识
8 Message ID 3字节 24位消息标识,低字节先传
9 Payload 0至255字节 按消息定义序列化
10 Checksum 2字节 CRC-16/MCRF4XX并加入消息CRC_EXTRA
11 Signature 可选13字节 仅签名标志置位时存在

不含Magic时,MAVLink 2固定头为9字节;线上从Magic到Message ID共10字节。讨论“头长度”时必须说明是否包含Magic。

未签名帧总长度为12 + payload length,签名帧为25 + payload length;255字节载荷的签名帧最大280字节。

载荷序列化

消息定义来自方言XML并由代码生成器生成。基本字段按以下原则序列化:

  • 非扩展字段会按类型大小重新排序,以减少对齐空洞;
  • 同尺寸字段保持声明顺序;
  • 多字节基本类型采用小端;
  • 数组元素连续排列;
  • 扩展字段位于基础字段之后;
  • MAVLink 2可以截去载荷尾部连续的零字节,但不能截去载荷中间的零;全零载荷仍至少保留第一个载荷字节。

因此,不能只按XML文本顺序手工拼接全部字段。发送和接收应使用与固定方言匹配的生成库。

载荷长度短于当前定义的完整长度时,缺失尾部按零解释;超过接收端已知定义的扩展可能由生成库按兼容规则处理。基础字段发生不兼容修改时,必须使用新消息ID或其他明确版本策略。

校验

MAVLink使用CRC-16/MCRF4XX累加:

  • Payload length开始;
  • 覆盖不含Magic的头字段和实际线上载荷;
  • 再累加该消息定义对应的CRC_EXTRA
  • 接收的两个CRC字节不参与自身计算。

CRC_EXTRA由消息名称和基础字段的类型、名称、数组长度及线上顺序生成,并作为额外一个字节参与运行时CRC计算,不作为独立字段传输。MAVLink 2扩展字段不参与旧消息的CRC_EXTRA,因此在尾部追加扩展不会改变旧定义的校验种子。它用于降低消息ID相同但定义不同被误解码的风险,不是密码学认证:

  • 不隐藏载荷;
  • 不证明发送者身份;
  • 攻击者知道消息定义即可重新计算;
  • 不能阻止重放。

只检查帧CRC不能代替命令授权。

序号和丢包

Sequence是每条发送链路上的8位递增序号,会回绕。接收端可用它估算丢帧,但要考虑:

  • 发送端重启;
  • 路由器合并多个来源;
  • 多条独立链路;
  • 过滤掉不关心的消息;
  • 乱序承载;
  • 序号回绕。

不能把任意一次跳号都等同于无线丢包,也不能把系统ID相同的不同物理来源合并统计。

System ID和Component ID

系统ID和组件ID用于寻址与路由,不是经过认证的身份。任意能够注入链路的节点都可能伪造这些字段,除非系统另有认证和访问控制。

常见路由规则会参考:

  • 目标系统和目标组件字段;
  • 消息是否广播;
  • 最近从哪个接口看到某系统或组件;
  • 避免把帧原路回送;
  • 链路过滤和转发策略。

路由器必须防止环路、重复放大和未知高流量消息耗尽带宽。

心跳的边界

HEARTBEAT可用于发现系统、组件类型和基本状态,但一个心跳存在不能证明:

  • 姿态、位置或电池消息持续更新;
  • 命令通道可用;
  • 参数协议兼容;
  • 飞控已通过健康检查;
  • 链路经过认证;
  • 地面站显示值是新鲜数据。

应用应对所需消息分别设置更新时间和质量门禁。

命令与确认

MAVLink命令常通过COMMAND_LONGCOMMAND_INT发送,并由COMMAND_ACK报告结果。实现要区分:

  • 已收到并接受;
  • 暂时处理中;
  • 完成;
  • 拒绝;
  • 不支持;
  • 参数错误;
  • 超时且最终状态未知。

重试前检查命令语义是否幂等。重启、存储、任务开始和执行器类动作可能不能安全重复。

目标系统/组件只是寻址。解锁、模式切换、任务写入、参数修改、FTP和远程命令仍需要飞控状态门禁、链路策略和权限控制。

参数和任务是会话协议

参数读取、任务上传和文件传输不是互不相关的单帧:

  • 有请求和响应;
  • 可能分页、分片或按序号传送;
  • 需要超时和重试;
  • 可能与其他客户端并发;
  • 重连后需要重新确认状态;
  • 工具和飞控可能支持不同子协议版本。

例如,任务上传中超时不能直接从头覆盖正在使用的任务。实现要确定当前事务所有者、预期序号和最终提交点。

签名帧把不兼容标志中的签名位设为1,并在CRC之后增加13字节:

字段 长度 含义
Link ID 1字节 本地链路标识
Timestamp 6字节 48位小端签名时间戳
Signature 6字节 SHA-256结果的前6字节

签名计算输入包括32字节秘密密钥、从Magic开始的完整数据包直到CRC、Link ID和Timestamp。摘要截取为6字节。

签名提供什么

在密钥保密、接收策略和时间状态正确时,签名可以:

  • 检测签名覆盖字段被修改;
  • 证明发送方持有共享密钥;
  • 配合时间戳和接收状态拒绝旧签名帧。

签名不加密载荷,旁路观察者仍能读取位置、状态和命令内容。

防重放

时间戳是从2015年1月1日00:00:00 UTC起、以10微秒为单位的48位无符号数。接收方需要按System ID + Component ID + Link ID维护最近接受的签名时间戳,而不是只按物理串口维护。

固定C库要求已建立状态的逻辑流严格递增,相同或更旧的时间戳会被拒绝。首次见到某逻辑流时,对过度落后于本地签名时钟的报文应用接受窗口;规范和固定实现没有给出“时间戳超前一分钟就拒绝”的对称规则。测试时应以所用库版本的精确比较和边界为准,不能凭直觉实现时间窗口。

48位时间戳在约2104年达到上限,规范没有定义可直接循环复用的普通序号语义。长期系统应在设计阶段处理寿命和迁移边界。

以下情况需要专项测试:

  • 发送端重启;
  • 接收端重启;
  • 后备电源或持久化状态丢失;
  • 两条链路误用相同Link ID;
  • 时间戳回退;
  • 合法帧延迟后到达;
  • 密钥轮换;
  • 签名与未签名链路混用。

如果接收策略仍允许高风险未签名命令,启用发送签名不代表系统已经建立强制认证。

签名策略矩阵

来源 帧状态 只读遥测 高风险命令
受信链路 签名有效且新鲜 可按策略接受 继续执行权限和飞行状态检查
受信链路 未签名 按明确策略处理 默认拒绝,除非有经评审的替代控制
任意链路 签名错误 丢弃并计数 丢弃并计数
任意链路 签名有效但重放 丢弃并计数 丢弃并告警
未知链路 签名有效但密钥域未知 不应因格式正确自动信任 拒绝

这是安全设计模板,不是所有平台的默认行为。必须读取固定版本实际配置和源码。

密钥配置消息

SETUP_SIGNING的完整解码载荷为42字节,字段顺序为:

偏移 字段 长度 处理
0 initial_timestamp 8字节 64位小端初始签名时间戳
8 target_system 1字节 目标系统
9 target_component 1字节 目标组件
10 secret_key 32字节 二进制秘密密钥

initial_timestamp用于建立后续签名时钟的起点,必须与10微秒签名时间基准和设备持久化状态一致,不能回退到已接受时间之前。全零密钥加零初始时间戳可触发禁用签名,属于高风险配置变更。

MAVLink 2仍会裁掉载荷末尾连续的零字节。因此,当32字节密钥末尾包含零,尤其发送全零密钥禁用签名时,线上Payload length可以小于42。接收生成库会把缺失的尾部扩展为零。测试应同时验证完整42字节逻辑布局和合法尾零裁剪,不能强制每个线上帧都携带42个载荷字节。

该消息只能在已经确认安全的直连链路上使用:

  • 使用明确目标系统和目标组件逐台发送;
  • 不得广播;
  • 接收方和网关不得自动转发到其他MAVLink接口;
  • 不得从无线、不受信局域网或共享遥测链路下发;
  • 发送前确认当前接口不会被路由器复制;
  • 发送后验证密钥已经保存,但不得回读或显示密钥值。

日志必须完全省略SETUP_SIGNING,或者把其中32字节秘密替换为固定脱敏值。共享调试日志、遥测日志、参数、崩溃转储和截图都不得泄露密钥。

线上签名帧写入普通遥测日志时,官方建议清除签名不兼容标志并移除签名块。由此产生的tlog不再是证明线上签名状态的原始证据;安全核验仍需受控访问的线上捕获和独立计数。

承载边界

串口

需要计算8N1位开销、双向消息、突发和队列。串口本身不重传。

UDP

可能丢包、重复、乱序和源地址伪造。一个UDP数据报可以包含一个或多个MAVLink帧,接收器仍需按字节流或数据报边界正确解析。

TCP

提供有序字节流,但没有MAVLink帧边界;仍可能半帧读取。阻塞和断线恢复也会增加时延。

路由器

路由器可能转发、过滤或合并多个接口。安全策略应位于所有可达路径,而不是只配置地面站一端。

固定版本核验

对Betaflight、INAV、ArduPilot和PX4分别保存:

  • 固件版本和提交;
  • 使用的MAVLink库或生成消息定义;
  • 方言名称及提交;
  • MAVLink 1/2输出设置;
  • 系统ID和组件ID;
  • 串口或网络承载;
  • 消息率配置;
  • 路由路径;
  • 签名支持、密钥域和未签名接收策略;
  • 关键命令的状态门禁。

平台支持“MAVLink 2”不能推导其支持全部方言消息、签名或同一参数微服务。

验证方法

执行错误签名、重放、路由或命令注入前,必须先完成协议审查与测试卡第0节,并按抓包、解码、一致性与版本迁移建立线上原始证据。前置不满足时只使用离线样本。

  1. 在隔离SITL网络中保存线上原始数据;
  2. 用两个独立解码器核对帧头、消息ID、载荷长度和CRC;
  3. 对照固定方言解释字段、单位和扩展;
  4. 检查序号、消息更新时间和链路统计;
  5. 分别测试未知兼容标志和未知不兼容标志;
  6. 测试载荷截断、最大载荷和错误CRC_EXTRA
  7. 对签名链路测试正确签名、错误签名、旧时间戳和重启;
  8. 验证SETUP_SIGNING不能广播、不能经网关自动转发,且不会把秘密写入日志;
  9. 验证高风险命令即使格式和签名正确,仍会在错误飞行状态被拒绝;
  10. 恢复配置并删除测试密钥。

签名失败、伪造和重放测试禁止使用生产密钥或开放无线环境。

常见误判

  • 0xFD后的固定头长度写成包含Magic的相同数字;
  • 忽略24位消息ID按低字节先传;
  • 按XML声明顺序手工序列化字段;
  • 认为CRC通过就代表发送者可信;
  • 把系统ID当作认证身份;
  • 认为签名会加密遥测;
  • 只启用发送签名,不检查接收端未签名策略;
  • 用地面站tlog替代线上原始帧证明签名块;
  • 把心跳存在写成整条链路健康。

检查理解

  1. MAVLink 2的Magic字节是什么?
  2. 未知兼容标志和未知不兼容标志分别怎样处理?
  3. CRC_EXTRA解决什么问题,为什么仍不是认证?
  4. MAVLink 2签名为什么不能保护机密性?
  5. 系统ID为什么不能作为权限依据?

主要参考