医院网站建设的目的网页界面设计
Vector 如何封装以太网报文
在 Vector 的 CAPL 环境中,官方提供了一个叫做 ethernetPacket 的结构体,它对以太网报文的结构做了封装。我们只需要设置好一些关键字段(比如源 MAC、目标 MAC、帧类型和负载长度),然后通过Byte(Index)方法逐字节填充数据即可。
VECTOR封装原理
-
CANoe 内部会根据我们设置的 ethernetPacket 字段自动组装出完整的以太网帧。
-
一般以太网帧,分为三部分:头部+Payload+尾部
-
以太网头部(包括目的 MAC、源 MAC 和以太网类型字段)由 source、
destination
和type
等字段提供。 -
以太网数据负载Payload中,也就是下图中的Payload字段,代表上层协议数据(如 IP 报文、SOME/IP、VLAN等)
-
以太网尾部FCS,帧校验序列,不属于Payload,主要进行CRC校验,检测数据检测错误。
以太网(Ethernet II 帧)报文格式
-
一个标准的Ethernet II 帧由三部分组成:Header ,Payload和FCS。但是,在CANoe工程中,一般只需要关注Header和Payload即可。(注释1)
-
Header(头部)
-
目标 MAC 地址(6 字节):标识接收方的网络接口。
-
源 MAC 地址(6 字节):标识发送方的网络接口。
-
类型/长度字段(2 字节):
-
如果该字段的数值大于或等于 0x0600,则表示 以太网类型,说明 Payload 中承载的是哪种协议(例如 0x0800 表示 IPv4)。
-
如果小于 0x0600,则表示 Payload 的长度。(注释2)
-
-
对于Header,长度总共是 14 字节
-
对于Header中的type,常用协议类型的以太网帧type字段参考:(注释3)
-
- Payload(有效载荷)
-
Payload这部分是实际承载数据的内容。
-
在后文的代码示例中,Payload 包括了 IP 头部 和 ICMP 头部:
-
注:在 ethernetPacket中,只计算 Payload 的字节数,不包括前面的 14 字节以太网头部。
在代码示例中设置 Length 为 84 字节,表示 IP 数据包(包括 IP 头 20 字节、ICMP 头 8 字节和 56 字节数据)的总长度。(即84字节,并不包含以太网头部的14字节)
为什么 IP (头部)和 (ICMP)头部包含在 Payload内?
-
IP头部:
这是网络层协议(IPv4)的首部,包含了版本、总长度、源 IP、目的 IP 等信息。
当以太网帧的类型字段(Type)被设置为 0x0800 时,接收方会知道接下来的数据是一个 IP 数据包。 -
ICMP头部:
IP 数据包中载荷(Payload)的内容可以是多种协议的数据。在后文的代码示例中,我们构造的是一个 ICMP Echo Request(通常用来执行 ping 测试)。
ICMP(Internet Control Message Protocol,互联网控制消息协议)用于在网络设备间传递控制信息和错误报告。
Echo Request(0x08):用来请求对方回复
Echo Reply (0x00):对应的回复消息 -
IP和ICMP的关系,参见(注释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.57const dword broadcastIP = 0xFFFFFFFF; // broadcast IP-->255.255.255.255ethernetPacket txPacket;
}on start
{int i;// 以太网头部:headertxPacket.msgChannel = 1; txPacket.source = EthGetMacAddressAsNumber("11:22:33:44:55:66");//My Mac AddrtxPacket.destination = EthGetMacAddressAsNumber("AA:BB:CC:DD:00:39");//PIU_Mst Mac AddrtxPacket.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/ECNtxPacket.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 = 64txPacket.Byte(9) = 0x01; // Protocol = ICMPtxPacket.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 RequesttxPacket.Byte(21) = 0x00; // CodetxPacket.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 内容。 -
数据包的解析也类似,通过预先定义的字段(如
type
、Length
、source
等)以及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 传输的状态和错误信息。