[X]关闭

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

文档创建者:FPGA课程
浏览次数:207
最后更新:2024-08-09
文档课程分类-安路-DR1
安路-DR1: FPSOC-DR1-FPGA部分 » 2_FPGA实验篇(仅旗舰) » 4-FPGA UDP通信
软件版本: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
复制代码
copycode.gif
copycode.gif
copycode.gif
copycode.gif
copycode.gif
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则