[米联客-安路飞龙DR1-FPSOC] UDP通信篇连载-07 ICMP层程序设计

软件版本:Anlogic -TD5.9.1-DR1_ES1.1

操作系统:WIN10 64bit

硬件平台:适用安路(Anlogic)FPGA

实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板

板卡获取平台:https://milianke.tmall.com/

登录"米联客"FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!

3.6 ICMP

该层在程序中为IP层的子层,设计了接收ICMP请求包并回复的功能。

3.6.1 ICMP接收模块

该模块首先过滤掉ICMP报文头部,并且对头部数据进行校验,校验方式和IP首部校验相同。

 1 //ICMP报文的校验和
 2 always@(posedge I_clk or posedge I_reset) begin
 3     if(I_reset) begin
 4         accum1              <=  16'd0;
 5         accum2              <=  32'd0;
 6         checksum_state      <=  2'd0;
 7         checksum_correct    <=  1'b1;
 8     end
 9     else begin
10         case(checksum_state)
11             0:begin
12                 if(I_icmp_pkg_valid) begin
13                     accum1[15:8]    <=  I_icmp_pkg_data;
14                     checksum_state  <=  2'd1;
15                 end
16                 else begin
17                     accum1[15:8]    <=  8'd0;
18                     checksum_state  <=  2'd0;
19                 end
20             end
21             1:begin
22                 accum1[7:0]     <=  I_icmp_pkg_data;
23                 checksum_state  <=  2'd2;
24             end
25             2:begin
26                 if(!I_icmp_pkg_valid) begin
27                     checksum_state      <=  2'd3;
28                     if((tmp_accum1[15:0] + tmp_accum1[31:16]) != 16'hffff)
29                         checksum_correct    <=  1'b0;
30                     else
31                         checksum_correct    <=  1'b1;
32                 end
33                 else begin
34                     accum2          <=  tmp_accum1;
35                     accum1[15:8]    <=  I_icmp_pkg_data;
36                     checksum_state  <=  2'd1;
37                 end
38             end
39             3:begin
40                 accum1          <=  16'd0;
41                 accum2          <=  32'd0;
42                 checksum_state  <=  2'd0;
43             end
44         endcase
45     end
46 end

将报文的附加数据存入FIFO中,并向icmp_pkg_tx模块发送ping应答信息,请求发送ping应答包。 

 1 //以下模块完成ICMP报文包echo ping应答的请求,并且先缓存到ip_layer的FIFO中
 2 always@(posedge I_clk or posedge I_reset) begin
 3     if(I_reset) begin
 4         cnt                         <=  4'd0;
 5         type1                       <=  8'd0;
 6         code                        <=  8'd0;
 7         echo_data_cnt               <=  10'd0;
 8         checksum                    <=  16'd0;
 9         O_icmp_req_en               <=  1'b0;
10         O_icmp_req_id               <=  16'd0;
11         O_icmp_req_sq_num           <=  16'd0;
12         O_icmp_ping_echo_data_valid <=  1'b0;
13         O_icmp_ping_echo_data       <=  8'd0;
14         O_icmp_req_checksum         <=  16'd0;
15         STATE                       <=  RECORD_ICMP_HEADER;
16     end
17     else begin
18         case(STATE)
19             RECORD_ICMP_HEADER:begin
20                 O_icmp_req_en       <=  1'b0;
21                 echo_data_cnt       <=  10'd0;
22                 if(I_icmp_pkg_valid)        //ICMP报文有效
23                     case(cnt)
24                         0:  begin   type1                   <=  I_icmp_pkg_data;    cnt <=  cnt + 1'b1;end  //ICMP报文首部-类型:8位数表示错误类型的差错报文或者查询类型的报告报文,一般是查询报文(0代表回显应答(ping应答);1代表查
25                         1:  begin   code                    <=  I_icmp_pkg_data;    cnt <=  cnt + 1'b1;end  //ICMP报文首部-类型:代码占用8位数据,根据ICMP差错报文的类型,进一步分析错误的原因
26                         2:  begin   checksum[15:8]          <=  I_icmp_pkg_data;    cnt <=  cnt + 1'b1;end  //ICMP报文首部-校验和:16位校验和的计算方法与IP首部校验和计算方法一致,该校验和需要对ICMP首部和ICMP数据做校验
27                         3:  begin   checksum[7:0]           <=  I_icmp_pkg_data;    cnt <=  cnt + 1'b1;end  //ICMP报文首部-校验和:16位校验和的计算方法与IP首部校验和计算方法一致,该校验和需要对ICMP首部和ICMP数据做校验
28                         4:  begin   O_icmp_req_id[15:8]     <=  I_icmp_pkg_data;    cnt <=  cnt + 1'b1;end  //ICMP报文首部-标识符:16位标识符对每一个发送的数据报进行标识
29                         5:  begin   O_icmp_req_id[7:0]      <=  I_icmp_pkg_data;    cnt <=  cnt + 1'b1;end  //ICMP报文首部-标识符:16位标识符对每一个发送的数据报进行标识
30                         6:  begin   O_icmp_req_sq_num[15:8] <=  I_icmp_pkg_data;    cnt <=  cnt + 1'b1;end  //ICMP报文首部-序列号:16位对发送的每一个数据报文进行编号
31                         7:  begin   O_icmp_req_sq_num[7:0]  <=  I_icmp_pkg_data;    cnt <=  cnt + 1'b1;end  //ICMP报文首部-序列号:16位对发送的每一个数据报文进行编号
32                         8:  begin
33                             if(type1 == PING_REQUEST && code == 8'h00) begin        //如果是远端主机发的ping请求包,那么本地主机需要返回一个ping应答包      
34                                 O_icmp_ping_echo_data_valid <=  1'b1;               //ping应答有效
35                                 O_icmp_ping_echo_data       <=  I_icmp_pkg_data;
36                             end
37                             else begin
38                                 O_icmp_ping_echo_data_valid <=  1'b0;
39                                 O_icmp_ping_echo_data       <=  8'd0;
40                             end
41                             cnt     <=  4'd0;
42                             STATE   <=  WAIT_PACKET_END;
43                         end
44                         default:    STATE   <=  RECORD_ICMP_HEADER;
45                     endcase
46                 else
47                     STATE   <=  RECORD_ICMP_HEADER;
48             end
49             WAIT_PACKET_END:begin
50                 if(I_icmp_pkg_valid) begin          //继续接收ICMP 报文
51                     if(O_icmp_ping_echo_data_valid) //ping应答有效
52                         echo_data_cnt   <=  echo_data_cnt + 1'b1;//ICMP包计数器
53                     else
54                         echo_data_cnt   <=  10'd0;
55                     O_icmp_ping_echo_data_valid <=  O_icmp_ping_echo_data_valid;
56                     O_icmp_ping_echo_data       <=  I_icmp_pkg_data;
57                     STATE               <=  WAIT_PACKET_END;
58                 end
59                 else begin
60                     if(O_icmp_ping_echo_data_valid) begin
61                         O_icmp_req_en       <=  1'b1;           //通知ip_tx模块接收到ICMP报文包ping请求,并且发送一个echo ping应答
62                         O_icmp_req_checksum <=  checksum_temp;  //输出校验和
63                     end
64                     else begin
65                         O_icmp_req_en       <=  1'b0;
66                         O_icmp_req_checksum <=  16'd0;                      
67                     end
68                     echo_data_cnt               <=  echo_data_cnt;
69                     O_icmp_ping_echo_data_valid <=  1'b0;
70                     O_icmp_ping_echo_data       <=  8'd0;
71                     STATE                       <=  RECORD_ICMP_HEADER;
72                 end
73             end
74         endcase
75     end
76 end

3.6.2 ICMP发送模块

该模块收到icmp_pkg_ctrl模块发送的ping应答包使能信号,寄存接收到的信息包括标识符、序列号、校验和、地址和数据长度,通过计数器添加报文头部,再将附加数据从FIFO中读出,组成ping应答包发送到ip_tx模块。

 1 always@(posedge I_clk or posedge I_reset) begin
 2     if(I_reset) begin
 3         cnt1                    <=  4'd0;
 4         cnt2                    <=  10'd0;
 5         request_id              <=  16'd0;
 6         request_sq_num          <=  16'd0;
 7         request_ip_taddress     <=  32'd0;
 8         checksum                <=  16'd0;
 9         echo_data_length        <=  10'd0;
10         O_icmp_pkg_req          <=  1'b0;
11         O_icmp_pkg_valid        <=  1'b0;
12         O_icmp_pkg_data         <=  8'd0;
13         O_icmp_ping_echo_ren    <=  1'b0;
14         STATE                   <=  WAIT_ICMP_PACKET;
15     end
16     else begin
17         case(STATE)
18             WAIT_ICMP_PACKET:begin
19                 if(I_icmp_req_en) begin//当接收到ICMP echo ping包,先保存该包的基本信息到寄存器
20                     request_id              <=  I_icmp_req_id;              //ICMP包的标识符
21                     request_sq_num          <=  I_icmp_req_sq_num;          //ICMP包的序列号
22                     request_ip_taddress     <=  I_icmp_req_ip_addr;         //ICMP包的地址
23                     checksum                <=  I_icmp_req_checksum;        //ICMP包的校验和 
24                     echo_data_length        <=  I_icmp_ping_echo_data_len;  //ICMP包的长度      
25                     O_icmp_pkg_req          <=  1'b1;                       //请求ip_tx模块发送部分,发送ICMP报文
26                     STATE                   <=  WAIT_PACKET_SEND;           //发送ICMP包状态
27                 end
28                 else begin
29                     request_id              <=  16'd0;
30                     request_sq_num          <=  16'd0;
31                     request_ip_taddress     <=  32'd0;
32                     checksum                <=  16'd0;
33                     echo_data_length        <=  10'd0;
34                     O_icmp_pkg_req          <=  1'b0;
35                     STATE                   <=  WAIT_ICMP_PACKET;                   
36                 end
37             end
38             WAIT_PACKET_SEND:begin
39                 if(I_icmp_pkg_busy) begin//该信号来自ip_tx模块,当有效代表ip_tx模块已经开始准备发送ICMP包,这里需要对ip_tx代码部分时序逻辑确保数据正确给到ip_tx模块
40                     O_icmp_pkg_req          <=  1'b0;
41                     O_icmp_pkg_valid        <=  1'b1;
42                     O_icmp_pkg_data         <=  PING_REPLY_TYPE;//回显应答(ping应答)的类型
43                     STATE                   <=  SEND_PACKET;
44                 end
45                 else begin
46                     O_icmp_pkg_req          <=  1'b1;
47                     O_icmp_pkg_valid        <=  1'b0;
48                     O_icmp_pkg_data         <=  8'd0;
49                     STATE                   <=  WAIT_PACKET_SEND;
50                 end
51             end
52             SEND_PACKET:begin
53                 case(cnt1)
54                     0   :begin  O_icmp_pkg_data <=  8'h00;                  cnt1    <=  cnt1 + 1'b1;end//回显应答(ping应答)的代码
55                     1   :begin  O_icmp_pkg_data <=  checksum[15:8];         cnt1    <=  cnt1 + 1'b1;end//ICMP报文包校验和,直接获取远程主机发送的Ping包校验和
56                     2   :begin  O_icmp_pkg_data <=  checksum[7:0];          cnt1    <=  cnt1 + 1'b1;end//ICMP报文包校验和,直接获取远程主机发送的Ping包校验和
57                     3   :begin  O_icmp_pkg_data <=  request_id[15:8];       cnt1    <=  cnt1 + 1'b1;end//ICMP报文标识符,直接获取远程主机发送的Ping包标识符
58                     4   :begin  O_icmp_pkg_data <=  request_id[7:0];        cnt1    <=  cnt1 + 1'b1;end//ICMP报文标识符,直接获取远程主机发送的Ping包标识符
59                     5   :begin  O_icmp_pkg_data <=  request_sq_num[15:8];   cnt1    <=  cnt1 + 1'b1;end//ICMP报文编码,直接获取远程主机发送的Ping序列号
60                     6   :begin  //从echo FIFO中读取ICMP echo报文的数据部分
61                         O_icmp_pkg_data         <=  request_sq_num[7:0];    
62                         cnt1                    <=  cnt1 + 1'b1;
63                         O_icmp_ping_echo_ren    <=  1'b1;
64                     end
65                     7   :begin//ICMP报文包的数据有效部分
66                         O_icmp_pkg_valid        <=  1'b1;
67                         O_icmp_pkg_data         <=  I_icmp_ping_echo_data;
68                         if(cnt2 == (echo_data_length - 1)) begin
69                             cnt2                    <=  10'd0;
70                             O_icmp_ping_echo_ren    <=  1'b0;
71                             cnt1                    <=  cnt1 + 1'b1;
72                         end
73                         else begin
74                             cnt2                    <=  cnt2 + 1'b1;
75                             O_icmp_ping_echo_ren    <=  1'b1;
76                             cnt1                    <=  cnt1;                           
77                         end
78                     end
79                     8   :begin
80                         cnt1                    <=  4'd0;
81                         O_icmp_pkg_data         <=  8'd0;
82                         O_icmp_pkg_valid        <=  1'b0;
83                         STATE                   <=  WAIT_ICMP_PACKET;
84                     end
85                     default:;
86                 endcase
87             end
88         endcase
89     end
90 end

 

posted @ 2024-08-09 18:59  米联客(milianke)  阅读(14)  评论(0编辑  收藏  举报