3、DoIP消息格式:通用DoIP消息头结构、Payload类型与编码、消息类型分类
好,咱们进入DoIP协议最核心的部分——消息格式。说实话,我刚接触DoIP那会儿,看着那一串十六进制字节,脑袋也是嗡嗡的。但后来我发现,只要把消息头结构吃透了,后面Payload怎么编解码、消息怎么分类,其实都是顺理成章的事。
这一节,我会带着大家把DoIP消息的「骨架」拆开来看。你想想看,一辆车和诊断仪之间要说话,总得有个统一的信封吧?这个信封就是通用消息头。咱们先看信封长什么样,再聊里面装了什么内容。
3.1 通用DoIP消息头结构
DoIP消息头是固定的8字节。嗯,这里要注意,不管后面Payload有多长,这8个字节雷打不动。我个人习惯把这8个字节分成四个字段来记:
| 字节偏移 | 字段名称 | 长度 | 说明 |
|---|---|---|---|
| 0 | 协议版本 | 1字节 | 当前固定为0x02(ISO 13400-2:2012) |
| 1 | 反向协议版本 | 1字节 | 取协议版本的按位取反,即0xFD |
| 2-3 | Payload类型 | 2字节 | 标识消息的具体用途 |
| 4-7 | Payload长度 | 4字节 | 后续Payload的字节数(大端序) |
关键点:反向协议版本字段是用来做快速校验的。接收方收到消息后,把协议版本和反向协议版本相加,如果结果不是0xFF,说明消息头损坏了,直接丢弃。我在项目中遇到过好几次因为网络干扰导致版本字段出错的情况,这个机制确实能快速过滤掉垃圾数据。
举个例子,一个完整的DoIP消息头在抓包工具里看起来是这样的:
02 FD 00 01 00 00 00 04
拆开来看:
02— 协议版本,ISO 13400-2:2012FD— 反向协议版本,0x02取反得0xFD00 01— Payload类型,0x0001代表车辆识别请求00 00 00 04— Payload长度,4字节
说白了,这8个字节就是DoIP通信的「身份证」。任何不符合这个结构的报文,接收方都会直接无视。
3.2 Payload类型与编码
消息头之后跟着的就是Payload。Payload怎么编码?这得看Payload类型字段的值。ISO 13400-2标准里定义了一大堆类型,我挑几个最常用的给大家讲讲。
Payload的编码方式其实不复杂,主要分两类:
- 固定长度Payload:比如车辆识别请求(0x0001),Payload就是4字节的逻辑地址。编码时直接按大端序填进去就行。
- 可变长度Payload:比如诊断消息(0x8001),Payload里包含目标地址、源地址和实际的UDS诊断数据。这种就需要在Payload内部再嵌套一个子结构。
我记得有一次调试,发现诊断仪发出去的DoIP消息,ECU就是不响应。抓包一看,Payload长度字段填错了,多填了2个字节。ECU等着收完数据,结果一直收不到,直接超时了。所以啊,Payload长度这个字段,一定要算准。
小技巧:写代码的时候,我习惯在填充Payload长度之前,先把整个消息组装好,然后回头再填长度。这样不容易算错。你想想看,如果先填了长度再拼Payload,万一中间改了数据,长度还得重新算,多麻烦。
咱们看一个诊断消息的Payload编码示例:
// 诊断消息Payload结构(类型0x8001)
// 字节0-1: 目标逻辑地址 (2字节)
// 字节2-3: 源逻辑地址 (2字节)
// 字节4-n: UDS诊断数据
// 示例:发送诊断请求 10 03(诊断会话控制-扩展会话)
// 目标地址: 0x0E00 (ECU逻辑地址)
// 源地址: 0x0E80 (诊断仪逻辑地址)
// UDS数据: 10 03
Payload (共8字节):
0E 00 0E 80 10 03
3.3 消息类型分类
DoIP的消息类型,按功能可以分成四大类。我习惯用「查、连、控、诊」四个字来记:
| 分类 | Payload类型范围 | 典型消息 | 用途 |
|---|---|---|---|
| 车辆发现 | 0x0001 - 0x0004 | 车辆识别请求/响应 | 诊断仪发现网络中的车辆 |
| 连接管理 | 0x0005 - 0x0008 | 路由激活请求/响应 | 建立诊断会话连接 |
| 数据控制 | 0x8001 - 0x8004 | 诊断消息、诊断ACK | 传输实际的UDS诊断数据 |
| 事件通知 | 0x4001 - 0x4003 | 车辆状态变化通知 | ECU主动上报状态变化 |
这里我要特别强调一下「连接管理」类中的路由激活消息。为什么?因为这是DoIP安全机制的入口。我曾经在项目里见过有人把路由激活的Payload类型填错了,结果ECU一直不响应,折腾了两天才发现是类型字段写成了0x0006而不是0x0005。
避坑指南:路由激活请求(0x0005)的Payload里包含一个「激活类型」字段。常见的激活类型有0x01(默认激活)和0x02(安全激活)。如果你用的是安全激活,记得在Payload里带上认证数据,否则ECU会直接拒绝。我曾经因为忘了带认证数据,被ECU连续拒绝了5次,触发了ECU的防攻击机制,锁了10分钟……
再说说「事件通知」类。这类消息比较特殊,它不是诊断仪发起的,而是ECU主动上报的。比如车辆熄火、网络断开等场景,ECU会发一个0x4003(车辆状态变化通知)给诊断仪。嗯,这里要注意,诊断仪收到这类消息后,通常需要回复一个确认,否则ECU会认为诊断仪没收到,继续重发。
最后总结一下:
- 消息头8字节,固定结构,反向协议版本用来做快速校验
- Payload编码分固定长度和可变长度两种,长度字段一定要算准
- 消息类型分四大类,路由激活是安全机制的关键入口
下一节我们会深入路由激活的具体流程,以及如何通过DoIP实现安全认证。到时候我会分享一个我在实际项目中遇到的「路由激活失败」的经典案例,保证让你印象深刻。