2. DoIP车辆识别请求响应

任务目标

实现一个DoIP(Diagnostic over IP)车辆识别请求的响应处理逻辑。当客户端发送0x0004(车辆识别请求)时,服务端应返回包含VIN码和逻辑地址的0x0005(车辆识别响应)报文。

协议背景

DoIP协议中,车辆识别请求(Payload Type = 0x0004)用于发现网络中的车辆ECU。请求报文无负载数据,响应报文(Payload Type = 0x0005)需携带VIN码(17字节ASCII)和逻辑地址(2字节)。本案例聚焦于服务端对该请求的解析与响应构造,不涉及TCP连接管理或路由激活等前置流程。

核心实现


#include <stdint.h>
#include <string.h>
#include <arpa/inet.h>

#define DOIP_HEADER_LEN   8
#define VIN_LEN           17
#define LOGICAL_ADDR_LEN  2

/* DoIP通用报文头 */
typedef struct {
    uint8_t  version;
    uint8_t  inverse_version;
    uint16_t payload_type;
    uint32_t payload_len;
} doip_header_t;

/* 车辆识别响应负载 */
typedef struct {
    char     vin[VIN_LEN];        /* 17字节ASCII码 */
    uint16_t logical_addr;        /* 网络字节序 */
} vehicle_id_resp_t;

/**
 * @brief 处理车辆识别请求,生成响应报文
 * @param vin          车辆VIN码(17字节,不足补空格)
 * @param logical_addr ECU逻辑地址(主机字节序)
 * @param out_buf      输出缓冲区(需≥8+17+2=27字节)
 * @return 响应报文总长度,失败返回-1
 */
int handle_vehicle_id_request(const char *vin, uint16_t logical_addr,
                              uint8_t *out_buf)
{
    if (!vin || !out_buf) {
        return -1;
    }

    doip_header_t *hdr = (doip_header_t *)out_buf;
    vehicle_id_resp_t *resp = (vehicle_id_resp_t *)(out_buf + DOIP_HEADER_LEN);

    /* 填充报文头 */
    hdr->version          = 0x02;  /* DoIP ISO 13400-2:2012 */
    hdr->inverse_version  = 0xFD;  /* 0x02取反 */
    hdr->payload_type     = htons(0x0005);
    hdr->payload_len      = htonl(VIN_LEN + LOGICAL_ADDR_LEN);

    /* 填充VIN(不足17字节补空格) */
    memset(resp->vin, ' ', VIN_LEN);
    memcpy(resp->vin, vin, strnlen(vin, VIN_LEN));

    /* 填充逻辑地址(网络字节序) */
    resp->logical_addr = htons(logical_addr);

    return DOIP_HEADER_LEN + VIN_LEN + LOGICAL_ADDR_LEN;
}

调用示例


#include <stdio.h>

int main(void)
{
    uint8_t buf[27];
    const char *vin = "LVGBE42K9RG123456";  /* 17位VIN */
    uint16_t ecu_addr = 0x0E80;             /* 典型ECU逻辑地址 */

    int len = handle_vehicle_id_request(vin, ecu_addr, buf);
    if (len < 0) {
        printf("构造响应失败\n");
        return 1;
    }

    /* 打印响应报文(十六进制) */
    for (int i = 0; i < len; i++) {
        printf("%02X ", buf[i]);
        if ((i + 1) % 8 == 0) printf("\n");
    }
    printf("\n");
    return 0;
}

编译与运行


gcc -o doip_vin doip_vin.c
./doip_vin

验证方法

编译运行后,观察输出报文:

  • 前2字节应为 02 FD(版本及反码)
  • 第3-4字节应为 00 05(Payload Type = 0x0005)
  • 第5-8字节应为 00 00 00 13(负载长度 = 19字节)
  • 第9-25字节为VIN码ASCII值,第26-27字节为逻辑地址 0E 80

预期输出首行:02 FD 00 05 00 00 00 13,后续行包含VIN的十六进制ASCII码及结尾的 0E 80。若报文头字段与上述一致,且VIN和逻辑地址正确填入,则判定实现通过。

关键说明

  • VIN码必须为17字节,不足时以空格填充(0x20),超过则截断
  • 逻辑地址使用htons()转换为网络字节序,与DoIP协议要求一致
  • 本实现仅覆盖车辆识别请求的响应构造,实际应用中需在TCP连接上接收0x0004请求后调用此函数,并将返回的报文发送回客户端