当前位置: 首页 > news >正文

以太网报文结构 via ethernetPacket in CAPL

Vector 如何封装以太网报文

在 Vector 的 CAPL 环境中,官方提供了一个叫做 ethernetPacket 的结构体,它对以太网报文的结构做了封装。我们只需要设置好一些关键字段(比如源 MAC、目标 MAC、帧类型和负载长度),然后通过Byte(Index)方法逐字节填充数据即可。


VECTOR封装原理

  1. CANoe 内部会根据我们设置的 ethernetPacket 字段自动组装出完整的以太网帧。

  2. 一般以太网帧,分为三部分:头部+Payload+尾部

  3. 以太网头部(包括目的 MAC、源 MAC 和以太网类型字段)由 sourcedestination和 type 等字段提供。

  4. 以太网数据负载Payload中,也就是下图中的Payload字段,代表上层协议数据(如 IP 报文、SOME/IP、VLAN等)

  5. 以太网尾部FCS,帧校验序列,不属于Payload,主要进行CRC校验,检测数据检测错误。


 以太网(Ethernet II 帧)报文格式

  1. 一个标准的Ethernet II 帧由三部分组成:Header ,Payload和FCS。但是,在CANoe工程中,一般只需要关注Header和Payload即可。(注释1)

  2. Header(头部)

    1. 目标 MAC 地址(6 字节):标识接收方的网络接口。

    2. 源 MAC 地址(6 字节):标识发送方的网络接口。

    3. 类型/长度字段(2 字节):

      1. 如果该字段的数值大于或等于 0x0600,则表示 以太网类型,说明 Payload 中承载的是哪种协议(例如 0x0800 表示 IPv4)。

      2. 如果小于 0x0600,则表示 Payload 的长度。(注释2)

    4. 对于Header,长度总共是 14 字节

    5. 对于Header中的type,常用协议类型的以太网帧type字段参考:(注释3)

  3. Payload(有效载荷)

    1. Payload这部分是实际承载数据的内容。

    2. 在后文的代码示例中,Payload 包括了 IP 头部 和 ICMP 头部:

注:在 ethernetPacket中,只计算 Payload 的字节数,不包括前面的 14 字节以太网头部。

在代码示例中设置 Length 为 84 字节,表示 IP 数据包(包括 IP 头 20 字节、ICMP 头 8 字节和 56 字节数据)的总长度。(即84字节,并不包含以太网头部的14字节)


为什么 IP (头部)和 (ICMP)头部包含在 Payload内?

  1. IP头部:
    这是网络层协议(IPv4)的首部,包含了版本、总长度、源 IP、目的 IP 等信息。
    当以太网帧的类型字段(Type)被设置为 0x0800 时,接收方会知道接下来的数据是一个 IP 数据包。

  2. ICMP头部:
    IP 数据包中载荷(Payload)的内容可以是多种协议的数据。在后文的代码示例中,我们构造的是一个 ICMP Echo Request(通常用来执行 ping 测试)。
    ICMP(Internet Control Message Protocol,互联网控制消息协议)用于在网络设备间传递控制信息和错误报告。

    Echo Request(0x08):用来请求对方回复
    Echo Reply    (0x00):对应的回复消息

  3. IP和ICMP的关系,参见(注释4)

  4. 此处需要厘清:
    有三个“Header”(头部)
    分别为:
    1)以太网帧的头部
    2)以太网Payload中IP的头部
    3)以太网Payload中ICMP的头部

    以太网帧的头部header不包含于Payload内,以太网header中包含了目标Mac、源Mac、以及以太网类型;
    而IP头部和ICMP头部,包含在Payload内;

CAPL源代码

代码主要功能:在 CANoe 中通过 Ethernet 总线发送 ICMPv4 Echo Request(即 Ping 请求),然后监听 IUT(被测设备)是否回复 ICMP Echo Reply(即 Ping 响应)。


/*@!Encoding:65001*/
variables
{ 
  const dword iutIP = 0xC0A8B239; //IUT-->192.168.178.57
  const dword broadcastIP = 0xFFFFFFFF;   // broadcast IP-->255.255.255.255
  ethernetPacket txPacket;
}


on start
{
  int i;

  // 以太网头部:header
  txPacket.msgChannel   = 1;  
  txPacket.source       = EthGetMacAddressAsNumber("11:22:33:44:55:66");//My Mac Addr
  txPacket.destination  = EthGetMacAddressAsNumber("AA:BB:CC:DD:00:39");//PIU_Mst Mac Addr
  txPacket.type         = 0x0800;  // IPv4
  // payload:84 byte(Not contain header)
  txPacket.Length       = 84;     



  //以太网Payload
  // --- 构造 IP 头部 (20 字节) ---
  txPacket.Byte(0)  = 0x45;    // Version=4, IHL=5 (20字节)
  txPacket.Byte(1)  = 0x00;    // DSCP/ECN
  txPacket.Byte(2)  = 0x00;    // Total Length 高位 (0x0054 = 84)
  txPacket.Byte(3)  = 0x54;    // Total Length 低位
  txPacket.Byte(4)  = 0x00;    // Identification 高位
  txPacket.Byte(5)  = 0x00;    // Identification 低位
  txPacket.Byte(6)  = 0x40;    // Flags (0x40 = Don't Fragment) + Fragment Offset 高位
  txPacket.Byte(7)  = 0x00;    // Fragment Offset 低位
  txPacket.Byte(8)  = 0x40;    // TTL = 64
  txPacket.Byte(9)  = 0x01;    // Protocol = ICMP
  txPacket.Byte(10) = 0x00;    // Header Checksum(此处置 0,如有需要可计算)
  txPacket.Byte(11) = 0x00;
  // 源 IP 地址设为广播地址 (用于测试)
  txPacket.Byte(12) = (broadcastIP >> 24) & 0xFF;
  txPacket.Byte(13) = (broadcastIP >> 16) & 0xFF;
  txPacket.Byte(14) = (broadcastIP >> 8)  & 0xFF;
  txPacket.Byte(15) = broadcastIP & 0xFF;
  // 目标 IP 地址:IUT 的 IP 地址
  txPacket.Byte(16) = (iutIP >> 24) & 0xFF;
  txPacket.Byte(17) = (iutIP >> 16) & 0xFF;
  txPacket.Byte(18) = (iutIP >> 8)  & 0xFF;
  txPacket.Byte(19) = iutIP & 0xFF;

  // --- 构造 ICMP 头部 (8 字节) ---
  txPacket.Byte(20) = 0x08;    // ICMP Type: Echo Request
  txPacket.Byte(21) = 0x00;    // Code
  txPacket.Byte(22) = 0x00;    // Checksum 高位(可选计算)
  txPacket.Byte(23) = 0x00;    // Checksum 低位
  txPacket.Byte(24) = 0x12;    // Identifier 高位
  txPacket.Byte(25) = 0x34;    // Identifier 低位
  txPacket.Byte(26) = 0x00;    // Sequence Number 高位
  txPacket.Byte(27) = 0x01;    // Sequence Number 低位

  // --- 填充附加数据 (56 字节) ---
  for(i = 28; i < 84; i++){
      txPacket.Byte(i) = i & 0xFF;
  }

  // 发送构造好的以太网数据包
  output(txPacket);
  write("Sent ICMPv4 Echo Request to IUT on Ethernet1.");
}

// 监听来自 Ethernet1 的所有报文,并检测 IUT 是否发送了 ICMPv4 Echo Reply
on ethernetPacket msgChannel1.*
{
  // 判断数据包是否为 IPv4 类型
  if(this.type == 0x0800 && this.Length >= 28)
  {
    // 检查 IP 头部中 Protocol 字段是否为 ICMP (0x01)
    if(this.Byte(9) == 0x01)
    {
      // 判断 ICMP 头部中 Type 字段是否为 Echo Reply (0x00)
      if(this.Byte(20) == 0x00)
      {
        // 判断报文的源 MAC 是否与 IUT 的 MAC 匹配
        if(this.source == EthGetMacAddressAsNumber("AA:BB:CC:DD:00:39"))
        {
          write("ERROR: IUT sent ICMPv4 Echo Reply, which is NOT expected!");
        }
      }
    }
  }
}

代码分析

1. 使用的结构类型:

on ethernetPacket()

  • 这是 CAPL 中用来表示以太网数据包的结构,VECTOR 官方在 CAPL 示例中已经做了封装。

  • 结构体内部主要包含头部字段(如源 MAC、目的 MAC、帧类型)和一个用于保存上层协议数据的字节数组(payload)。

2. 主要字段说明

  • msgChannel

    • 用于指定数据包所属的通道号。

    • 在我们的例子中设为 1,但实际项目中需要根据 CANoe 工程中 Ethernet 通道的配置来调整。

  • source

    • 表示发送该报文的以太网接口的 MAC 地址。

    • 代码中使用 EthGetMacAddressAsNumber() 将字符串形式的 MAC 地址转换为数值格式赋值给 source。

  • destination

    • 表示目标接收方的 MAC 地址。

    • 这里同样用 EthGetMacAddressAsNumber() 转换 IUT 的 MAC 地址字符串。

  • type

    • 表示以太网帧的类型字段,例如 0x0800 表示 IPv4 数据包。

    • 该字段在数据链路层用于告知上层协议如何解析 payload。

  • txPacket.Length

    • 表示 payload 部分的总字节数(不包括以太网帧头部)。

    • 在我们的例子中设为 84 字节,这里包含了 IP 头部(20 字节)、ICMP 头部(8 字节)和附加数据(56 字节)。

  • payload 字节数组(通过 Byte(index) 访问)

    • IP 头部:

      从 Byte(0) 到 Byte(19),包括版本、头长、总长度、标识符、TTL、协议、源 IP 和目标 IP 等字段。

    • ICMP 头部:

      从 Byte(20) 到 Byte(27),设置了 ICMP 类型(Echo Request 为 0x08)、代码、校验和、标识符、序列号。

    • 附加数据:

      从 Byte(28) 到 Byte(83),这里简单填充为序号数据(可以根据需要自定义)。

         使用 txPacket.Byte(i) 访问并设置报文的每个字节。

3. 数据包构造与发送

  • 构造过程

    • 前 20 字节:IP 头部

    • 接下来 8 字节:ICMP 头部

    • 剩余部分:附加数据负载

    • 在 on start 事件中,先配置好 txPacket 的各个头部字段(msgChannel、source、destination、type、Length)。

    • 然后依次用 txPacket.Byte(index) 填充各个字段:

  • 发送

    • 构造完成后调用 output(txPacket) 将数据包发送出去。

    • 发送后数据包会经过 CANoe 的 Ethernet 驱动,在指定的通道(Ethernet1,对应 msgChannel1 通道)上进行发送。

4. 接收处理

  • 接收事件:

        使用 on ethernetPacket msgChannel1.* 事件监听所有来自指定通道的数据包。

  • 解析过程:

    • 通过 this.type 判断数据包类型(0x0800 表示 IPv4)。

    • 通过 this.Length 判断报文长度是否满足基本要求(例如至少 28 字节以上)。

    • 通过 this.Byte(9) 读取 IP 头部的 Protocol 字段,判断是否为 ICMP(0x01)。

    • 通过 this.Byte(20) 判断 ICMP 类型是否为 Echo Reply(0x00)。

    • 通过 this.source 与 EthGetMacAddressAsNumber(iutMACStr) 对比判断报文是否由 IUT 发出。


总结

该 CAPL 以太网报文结构利用了 VECTOR 官方提供的 ethernetPacket 封装函数,使得构造、发送、接收以太网数据包变得直观易用。

  • 只需要设置好各个字段(MAC、类型、长度),然后使用 Byte() 方法填充 payload 内容。

  • 数据包的解析也类似,通过预先定义的字段(如 typeLengthsource 等)以及 Byte() 方法按偏移访问具体内容。


注释1:

以太网Mac层负责在帧发送前,自动计算FCS并附加到帧尾,接收端也会自动验证FCS

CANoe的CAPL主要操作的是数据链路层以上,它模拟或者处理以太网的Header和Payload,不需要手动计算或附加FCS

如果手动封装FCS,可能会导致错误,因为MAC硬件会再次计算和附加,最终FCS可能不匹配,最终被丢弃

总结:CAPL发送以太网帧的时候只关注头部和负载。

注释2:

以太网头部中的类型(Type)字段的作用,在以太网帧头部,以太网类型(Type) 是一个 2 字节(16 位) 的字段,主要用于区分上层协议类型(如IPV4)。但在 IEEE 802.3 标准早期,该字段也可以表示帧的负载长度(Payload Length),这就是为什么它可能会填充 0x0600(1536)以下的值。

注释3:

对于Header中的type,常用协议类型的以太网帧type字段  (这些值告诉接收端如何解析Payload部分的数据内容):

注释4:

ICMP 是 IP 协议的一部分,专门用于发送控制消息和错误报告;

总结为-->IP 负责传输,ICMP 负责反馈 IP 传输的状态和错误信息。

http://www.dtcms.com/a/106354.html

相关文章:

  • 三轴云台之相机技术篇
  • JavaWeb开发基础知识-Servlet终极入门指南(曼波萌新版)
  • KingbaseES物理备份还原之物理备份
  • 单框架鸿蒙开发
  • 解决报错curl: (35) OpenSSL SSL_connect: 连接被对方重设 in connection to download.docker.com:443
  • JavaScript闭包
  • Python设计模式:责任链模式
  • JAVASE(十三)常用类(二)包装类、工具类Arrays类
  • 【案例分享】江苏某汽车制造厂水冷式制冷站AI节能优化方案
  • LVS-----DR模式
  • JAVA中JVM一次 GC的 流程
  • 电脑屏幕亮度随心控,在Windows上自由调整屏幕亮度的方法
  • 分布式数据一致性场景与方案处理分析|得物技术
  • 谷粒商城:Redisson
  • TiDB 可观测性解读(二)丨算子执行信息性能诊断案例分享
  • Linux网络编程socket服务器端模拟实现
  • JSP 指令
  • Python数据类型-dict
  • 第八届 蓝桥杯 嵌入式 省赛
  • 【ESP32-IDF 笔记】02-LED PWM 配置
  • 运维面试题(ORACLE数据库)--20250401
  • Cesium学习(未完继续)
  • 题解:AT_arc050_c [ARC050C] LCM 111
  • Android的安全问题 - 在 Android 源码的 system/sepolicy 目录中,区分 public、private 和 vendor的目的
  • Kotlin 作用域函数:apply、let、run、with、also
  • 掩码图像建模 (MIM) 中的对数似然与交叉熵
  • 品铂科技与宇都通讯UWB技术核心区别对比(2025年)
  • C++:位图和布隆过滤器
  • spring-ai-alibaba第三章ollama集成Tool
  • 【redis】缓存 更新策略(定期、实时生存),缓存预热、穿透、雪崩、击穿详解