3、DoIP网络层核心概念:DoIP报文结构、DoIP头部字段详解
好,咱们今天来聊聊DoIP报文到底长什么样。说实话,我刚接触DoIP那会儿,看着那一串十六进制数据,脑子里全是问号。后来摸清了门道,发现其实结构很清晰,说白了就是「固定头部 + 负载」这么个套路。
3.1 DoIP报文整体结构
一个完整的DoIP报文,由两部分组成:
- DoIP头部:固定长度,8个字节
- DoIP负载:长度可变,最大支持到2^32 - 1字节
你想想看,这设计其实挺聪明的。头部固定8字节,解析起来特别快。我在项目中遇到过一个问题,就是有人把负载长度算错了,结果ECU直接不理你。嗯,这里要注意,负载长度是不包括头部的。
核心公式:
DoIP报文总长度 = 8字节(头部) + Payload Length(负载长度)
3.2 DoIP头部字段详解
头部这8个字节,每个字段都有它的使命。我习惯按顺序一个一个来拆解:
| 偏移量 | 字段名 | 长度 | 说明 |
|---|---|---|---|
| 0 | 协议版本号 | 1字节 | 当前标准值为0x02 |
| 1 | 反向协议版本号 | 1字节 | 取反,用于校验 |
| 2 | 负载类型码 | 2字节 | 标识报文用途 |
| 4 | 负载长度 | 4字节 | 大端序,单位字节 |
3.3 协议版本号(0x02)
这个字段就一个字节,目前ISO 13400-2定义的版本是0x02。为什么是0x02?因为0x01是早期草案,基本没人用了。我记得有一次调试,对方发了个0x01的版本号,我这边ECU直接回了NACK。所以啊,版本号不匹配,连握手都过不去。
我的小技巧:抓包时先看第一个字节。如果不是0x02,大概率是设备固件太老,或者有人在搞恶作剧。
3.4 反向协议版本号
这个字段是版本号的按位取反。比如版本号是0x02,那反向版本号就是0xFD。为什么要搞这么一出?说白了就是为了快速校验。接收方只要把这两个字节加起来,结果应该是0xFF。我曾经见过一个山寨工具,反向版本号算错了,结果ECU死活不认。嗯,这种低级错误,调试起来特别坑。
3.5 负载类型码(重中之重)
这是DoIP报文里最核心的字段,2个字节,定义了报文的具体用途。我把它分成几大类:
- 0x0000 - 0x00FF:通用DoIP报文,比如路由激活、诊断请求等
- 0x0100 - 0x01FF:车辆信息报文,比如VIN读取
- 0x0200 - 0x02FF:诊断相关报文,比如UDS on DoIP
- 0x8000 - 0xFFFF:厂家自定义,别乱用
你想想看,没有这个类型码,接收方根本不知道你发的是啥。是来激活路由的?还是来读故障码的?全凭这个字段说话。
避坑指南:我曾经在项目中遇到一个情况,测试人员把类型码写成了0x0200,但实际应该用0x8001。结果ECU直接丢弃报文,连个NACK都不给。所以,类型码一定要查ISO 13400-2的表,别想当然。
3.6 负载长度
4个字节,大端序,表示后面跟着的负载有多少字节。最大值是0xFFFFFFFF,也就是4GB。当然,实际场景中没人会发这么大的包,以太网MTU才1500字节呢。
这里有个细节:负载长度不包括头部。如果负载长度为0,那就是一个纯粹的DoIP控制报文,比如路由激活请求。我刚开始学的时候,老是把总长度算进去,结果解析出来的数据全是乱的。后来养成了习惯,抓包时先看这个字段,再决定读多少字节。
3.7 抓包实例:一个完整的DoIP报文
咱们来看一个真实的抓包数据,我随便挑一个:
02 FD 80 01 00 00 00 08 // DoIP头部
01 02 03 04 05 06 07 08 // 负载(8字节)
我来逐字节拆解:
- 02:协议版本号,标准值
- FD:反向版本号,0x02取反得0xFD
- 80 01:类型码,0x8001,这是诊断报文
- 00 00 00 08:负载长度,8字节
- 01 02 ... 08:负载内容,这里是UDS诊断请求
你看,是不是很简单?我当年第一次手动解析时,花了半小时才搞明白。现在闭着眼睛都能写出来。
3.8 常见错误与调试技巧
最后,我分享几个实战中容易踩的坑:
- 字节序搞反:DoIP头部全是网络字节序(大端)。如果你用小端去解析,负载长度会变成天文数字。
- 版本号不匹配:有些老设备用0x01,新设备用0x02。互连前先确认。
- 类型码乱填:我见过有人把0x0001写成0x0100,结果ECU直接不理。
我的调试习惯:先用Wireshark抓包,过滤条件设成doip。然后看头部的前两个字节,如果加起来不是0xFF,那报文肯定有问题。别问我怎么知道的,都是血泪教训。
好了,DoIP报文结构就讲到这里。下一章咱们聊聊路由激活的具体流程,那个更有意思。