[米联客-安路飞龙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
本文来米联客(milianke),作者:米联客(milianke),转载请注明原文链接:https://www.cnblogs.com/milianke/p/18351347