一、IP,TCP,UDP,ICMP校验和的区别和计算
1、IP首部校验和
IP数据报的校验和只检验IP数据报的首部。
当发送IP包时,需要计算IP报头的校验和:
- 把校验和字段置为0;
- 对IP头部中的每16bit进行二进制求和;
- 如果和的高16bit不为0,则将和的高16bit和低16bit反复相加,直到和的高16bit为0,从而获得一个16bit的值;
- 将该16bit的值取反,存入校验和字段。
//计算checksum
always @(posedge i_clk or posedge i_rst)begin
if(i_rst)
r_checksum <= 'd0;
else if(r_recv_cnt == 1)
r_checksum <= 16'h4500 + r_pkt_byte_len +
w_upper_ID + {w_upper_flags,w_upper_offset} +
{8'd128,w_upper_type} + 16'd0 +
r_dynamic_src_ip[31:16] + r_dynamic_src_ip[15:0] +
r_dynamic_dst_ip[31:16] + r_dynamic_dst_ip[15:0];
else if(r_recv_cnt == 2)
r_checksum <= r_checksum[15:0] + r_checksum[31:16];
else
r_checksum <= r_checksum;
end
2、TCP、UDP校验和
UDP数据报计算校验和的方法和IP数据报校验和的方法相似,但是UDP的校验和是将首部和数据部分一起都校验。
需要注意的是,由于UDP首部中不包含源地址与目标地址等信息,为了保证UDP校验的有效性,在进行UDP校验和的计算时,需要增加一个UDP伪首部的校验和。
伪首部共有12字节,包含如下信息:
- 源IP地址
- 目的IP地址
- 保留字节(置0,为了字节对齐)]
- 传输层协议号(TCP是6)
- UDP报文长度(报头+数据)。
TCP 的校验和计算方法同UDP一样,同样要加上一个伪头部,区别是伪头部的协议码是0x06,长度是整个TCP报文的长度(包含TCP头部)。
伪首部是为了增加TCP校验和的检错能力:如检查TCP报文是否收错了(目的IP地址)、传输层协议是否选对了(传输层协议号)等。
3、ICMP校验和
ICMP校验和的计算方法一样,只不过只是对ICMP包整个进行校验和,没有伪头部,也不包括IP包头部。
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_hd_checksum <= 'd0;
else if(i_trigger)
r_hd_checksum <= 16'h0000 + 16'h0000 + i_Identifier + i_Sequence
+ 16'h6162 + 16'h6364 + 16'h6566 + 16'h6768
+ 16'h696a + 16'h6b6c + 16'h6d6e + 16'h6f70
+ 16'h7172 + 16'h7374 + 16'h7576 + 16'h7761
+ 16'h6263 + 16'h6465 + 16'h6667 + 16'h6869;
else if(ri_trigger)
r_hd_checksum <= r_hd_checksum[31:16] + r_hd_checksum[15:0];
else
r_hd_checksum <= r_hd_checksum;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
rm_axis_ip_data <= 'd0;
else case(r_cnt)
0 :rm_axis_ip_data <= {16'h0000,(~r_hd_checksum[15:0]),ri_Identifier,ri_Sequence};
1 :rm_axis_ip_data <= {64'h6162636465666768};
2 :rm_axis_ip_data <= {64'h696a6b6c6d6e6f70};
3 :rm_axis_ip_data <= {64'h7172737475767761};
4 :rm_axis_ip_data <= {64'h6263646566676869};
default :rm_axis_ip_data <= 64'd0;
endcase
end
总结
IP、TCP、UDP、ICMP校验和的区别:
- IP校验和 = IP头部的计算
- TCP,UP校验和 = 伪首部+TCP/UDP报头+数据
- ICMP校验和 = ICMP报头+数据