当前位置:首页 > 汽车电子 > 汽车电子
[导读]DoIP不是新诊断协议,只是把UDS从CAN搬到以太网:UDS服务原样不动,外层套DoIP头走UDP/TCP。 诊断仪侧用C写Socket,重点在“车辆发现→TCP建连→路由激活→0x8001封装UDS→Alive Check保活”五步,网关按逻辑地址转发到目标ECU。


DoIP不是新诊断协议,只是把UDS从CAN搬到以太网:UDS服务原样不动,外层套DoIP头走UDP/TCP。 诊断仪侧用C写Socket,重点在“车辆发现→TCP建连→路由激活→0x8001封装UDS→Alive Check保活”五步,网关按逻辑地址转发到目标ECU。

一、端口与协议分工

UDP 13400:车辆发现(Vehicle Identification Request 0x0001 / Response 0x0004)

TCP 13400:路由激活、诊断报文传输(未加密)

TLS场景用3496

DoIP通用头固定8字节:协议版本(0x02) + 反码(0xFD) + Payload Type(2B) + Payload Length(4B)。

二、建TCP连接

int doip_connect(const char*ip){

   int fd=socket(AF_INET,SOCK_STREAM,0);

   struct sockaddr_in a={0};

   a.sin_family=AF_INET; a.sin_port=htons(13400);

   inet_pton(AF_INET,ip,&a.sin_addr);

   if(connect(fd,(sa*)&a,sizeof(a))<0){close(fd);return -1;}

   return fd;

}

连上不等于能发诊断,必须过路由激活。

三、组DoIP头

void doip_hdr(uint8_t*buf,uint16_t ptype,uint32_t plen){

   buf[0]=0x02; buf[1]=0xFD;

   buf[2]=(ptype>>8)&0xFF; buf[3]=ptype&0xFF;

   buf[4]=(plen>>24)&0xFF; buf[5]=(plen>>16)&0xFF;

   buf[6]=(plen>>8)&0xFF;  buf[7]=plen&0xFF;

}

长度字段必须和实际Payload字节数一致,多写少写网关直接静默丢弃,不回NACK。

四、路由激活(0x0005)

Payload:源逻辑地址(2B) + 激活类型(1B,默认0x00) + 保留(1B)。

void send_routing_activation(int fd,uint16_t tester_addr){

   uint8_t f[8+4];

   doip_hdr(f,0x0005,4);

   f[8]=tester_addr>>8; f[9]=tester_addr&0xFF;

   f[10]=0x00;          // Default activation

   f[11]=0x00;

   send(fd,f,sizeof(f),0);

}

响应是0x0006,响应码0x00=成功、0x10=成功但需确认、0x02=源地址已被占用、0x01=连接数满。 激活失败别急着发UDS,先查tester逻辑地址白名单。

五、封装UDS诊断报文(0x8001)

诊断消息Payload结构:源地址(2B) + 目标地址(2B) + UDS原始数据。

void doip_send_uds(int fd,uint16_t src,uint16_t dst,

                  uint8_t*uds,uint8_t ulen){

   uint8_t buf[8+4+8];

   doip_hdr(buf,0x8001,4+ulen);

   buf[8]=src>>8; buf[9]=src&0xFF;

   buf[10]=dst>>8; buf[11]=dst&0xFF;

   memcpy(&buf[12],uds,ulen);

   send(fd,buf,8+4+ulen,0);

}

例:读VIN → doip_send_uds(fd,0x0E00,0x1000,(uint8_t[]){0x22,0xF1,0x90},3)

网关按dst逻辑地址路由:目标在CAN域就转CAN TP,在以太网域就直接投。

六、接收与解析

接收侧先读8字节头,按Payload Length收完整Payload,再分流:

int doip_recv(int fd,uint8_t*out){

   uint8_t h[8]; recv_exact(fd,h,8);

   uint16_t pt=(h[2]<<8)|h[3];

   uint32_t len=(h[4]<<24)|(h[5]<<16)|(h[6]<<8)|h[7];

   recv_exact(fd,out,len);

   return pt;     // 0x0006 / 0x8001 / 0x8003 ...

}

0x0006 → 查响应码

0x8001 → 剥掉前4字节逻辑地址,剩下交UDS层处理

0x8003 → 诊断消息否定应答(目标地址错/路由失败)

注意:0x8002/0x8003是网关给的“是否路由成功”,不是ECU的UDS响应。

七、Alive Check与保活

TCP连上不代表一直在线,网关会周期性发0x0007,诊断仪回0x0008;超时无响应就断socket释放资源。 长时间刷写/读DTC时:

周期发UDS 0x3E 00保活诊断会话

同时响应网关Alive Check,别只保UDS不管DoIP层

超时建议DoIP层5s、UDS层2s

八、工程落坑

逻辑地址错:dst填成网关地址而非目标ECU地址,报文被静默丢弃

路由激活忘做:TCP能连上但发UDS无任何响应

长度字段手滑:Payload Length算错直接被丢弃,Wireshark看都不进UDS层

多诊断仪抢地址:同一tester地址已注册会回0x02,换0x0E00~0x0FFF区间

激活类型乱填:量产默认0x00,Central Security要看OEM规范

防火墙/网卡:PC多网卡时UDP广播可能走错接口,绑定到车端网段

安全:产线/售后建议走TLS 3496或路由激活白名单,裸TCP 13400易被非法诊断仪接入

按“UDP发现→TCP 13400→0x0005激活→0x8001封UDS→逻辑地址路由→Alive Check”写,诊断仪侧代码并不复杂;复杂点在逻辑地址表、激活拒绝码处理、超时重连。UDS业务层和CAN完全复用,只换传输适配层即可。



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭