MAC层的校验是CRC,而IP层也有其校验机制。
CRC保证数据包的传输正确;
IP头校验和
IP头校验和是一种错误检测机制,用于在互联网协议(IP)中保证IP头的数据完整性。
当一个IP数据包从源主机发送到目的主机时,它经过许多路由器和交换机,校验和可以帮助这些中间设备检查数据包在传输过程中是否出现错误。
IP头校验和的计算方式如下:
- 分割:将IP头部分为16位(2字节)的段。
- 求和:将所有16位的段相加(以二进制求和,也就是每个段直接按位相加)。
- 进位处理:如果求和的结果产生了溢出,则将溢出的部分(即进位)加到求和的结果的最低位上。这可能需要重复进行,直到不再有溢出发生。
- 取反:将求和结果取反(按位取反,1变0,0变1)得到校验和。
这个校验和随后被填充在IP头中专门为校验和预留的字段内。在接收端,同样的计算会被执行在收到的IP头上,包括校验和字段本身。如果数据包在传输过程中没有错误,所有段的总和加上接收到的校验和的结果应该是一个全1的二进制数(因为原始计算中结果取反了)。如果计算结果不是全1,那么就说明数据在传输过程中可能出现了错误。
重要的是,IP头校验和只检查头部的完整性,并不保护整个IP数据包的内容。传输层(如TCP或UDP)有自己的校验和,负责整个数据段(包括数据)的完整性检查。
在实际的网络设备中,这个计算通常是由硬件来执行,以提高数据包处理的效率。当数据包通过每个路由器传输时,因为TTL字段会改变,所以需要重新计算校验和。
FPGA实现:
module emcode_checksum_ip ( input wire sys_clk , input wire sys_rst_n , input wire i_vaild , input wire [7:0] i_data , output wire o_vaild , output wire [7:0] o_data ); reg [15:0] r_i_vaild ; reg [07:0] r1_i_data [15:0] ; reg [07:0] checksum_cnt ; reg [01:0] concat_cnt ; wire [15:0] concat_data ; reg [31:0] r1_sum ; wire [31:0] r1_checksum_value ; wire [15:0] r2_checksum_value ; reg [15:0] r3_checksum_value ; reg [07:0] vaild_cnt ; reg [07:0] r_o_data ; always @(posedge sys_clk) begin r_i_vaild <= {r_i_vaild[14:0],i_vaild}; end reg [7:0] reg_i1; reg [7:0] reg_i2; always @(posedge sys_clk) begin if(sys_rst_n == 1'b0) begin for (reg_i1 = 0; reg_i1 < 'd15; reg_i1 = reg_i1 + 1) begin r1_i_data[reg_i1] <= 'd0; end end else begin for (reg_i2 = 0; reg_i2 < 'd15; reg_i2 = reg_i2 + 1) begin r1_i_data[reg_i2+1] <= r1_i_data[reg_i2]; end r1_i_data[0] <= i_data; end end always @(posedge sys_clk) begin if(sys_rst_n == 1'b0) begin checksum_cnt <= 8'h0; end else if(i_vaild == 1'b0 && r_i_vaild[0] == 1'b1) begin checksum_cnt <= 8'h0; end else if(i_vaild == 1'b1)begin checksum_cnt <= checksum_cnt + 1'b1; end end always @(posedge sys_clk) begin if(sys_rst_n == 1'b0) begin vaild_cnt <= 8'h0; end else if(r_i_vaild[10] == 1'b0 && r_i_vaild[11] == 1'b1) begin vaild_cnt <= 8'h0; end else if(r_i_vaild[10] == 1'b1)begin vaild_cnt <= vaild_cnt + 1'b1; end end always @(posedge sys_clk) begin if(sys_rst_n == 1'b0) begin concat_cnt <= 2'd0; end else if(i_vaild == 1'b0 && r_i_vaild[0] == 1'b1) begin concat_cnt <= 2'd0; end else if(i_vaild == 1'b1 && checksum_cnt >= 'd22 && checksum_cnt <= 41) begin if(concat_cnt == 1'b1) begin concat_cnt <= 2'd0; end else begin concat_cnt <= concat_cnt + 1'b1; end end else begin concat_cnt <= concat_cnt; end end assign concat_data = {r1_i_data[0],i_data}; always @(posedge sys_clk) begin if(sys_rst_n == 1'b0) begin r1_sum <= 32'd0; end else if(i_vaild == 1'b0 && r_i_vaild[0] == 1'b1) begin r1_sum <= 32'd0; end else if(i_vaild == 1'b1 && checksum_cnt >= 'd22 && checksum_cnt <= 'd41 && concat_cnt == 1'b1) begin r1_sum <= r1_sum + concat_data; end else begin r1_sum <= r1_sum; end end assign r1_checksum_value = r1_sum[15:0] + r1_sum[31:16]; assign r2_checksum_value = ~(r1_checksum_value[15:0]); always @(posedge sys_clk) begin if(sys_rst_n == 1'b0) begin r3_checksum_value <= 'd0; end else if(r_i_vaild[10] == 1'b0 && r_i_vaild[11] == 1'b1) begin r3_checksum_value <= 'd0; end else if(i_vaild == 1'b1 && checksum_cnt == 'd42) begin r3_checksum_value <= r2_checksum_value; end end assign o_vaild = r_i_vaild[11]; assign o_data = r_o_data ; always @(posedge sys_clk) begin if(sys_rst_n == 1'b0) begin r_o_data <= 8'd0; end else if(r_i_vaild[10] == 1'b1 && vaild_cnt == 'd32) begin r_o_data <= r3_checksum_value[15:08]; end else if(r_i_vaild[10] == 1'b1 && vaild_cnt == 'd33) begin r_o_data <= r3_checksum_value[07:00]; end else begin r_o_data <= r1_i_data[10]; end end endmodule
UDP校验和
UDP校验和是一种错误检测机制,与IP校验和类似,但它覆盖了更多的数据:UDP校验和不仅检查UDP头部,还检查数据部分。这为UDP数据包提供了一个简单的形式的数据完整性验证。
计算UDP校验和的步骤如下:
-
伪头部:首先,创建一个所谓的“伪头部”,它包括源IP地址、目的IP地址、一个8位全零字段、协议字段(对于UDP,这个值是17,8‘h11)和UDP长度字段。这个伪头部不是UDP数据包的一部分,而是仅用于校验和计算过程。
-
合并:将伪头部、UDP头部和数据部分合并起来。如果数据的总字节长度不是偶数,会在最后添加一个零字节来填充。
-
分割:将合并后的数据分割成16位的段。
-
求和:以二进制求和这些16位的段,包括溢出。
-
进位处理:与IP校验和相同,如果求和的结果产生溢出,将溢出的部分加回到求和结果的最低位。
-
取反:将最终的求和结果取反。
得到的校验和随后放入UDP头部中的校验和字段。在接收端,同样的计算会被执行在整个数据包上(包括伪头部)。如果数据包传输正确,所有的16位段相加(包括校验和字段)应该结果为全1的二进制数(0xFFFF)。如果不是,那么就说明数据包在传输过程中出现了错误。
值得注意的是,UDP校验和是可选的,在IPv4中可以设置为零表示不计算校验和,但在IPv6中,UDP校验和是必需的。这是因为IPv6不包括一个独立的校验和,因此依赖于UDP校验和提供错误检测。
标签:UDP,wire,IP,校验,数据包,reg From: https://www.cnblogs.com/VerweileDoch/p/18123556