软件版本:Anlogic -TD5.9.1-DR1_ES1.1 操作系统:WIN10 64bit 硬件平台:适用安路(Anlogic)FPGA 实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板 3.6 ICMP层该层在程序中为IP层的子层,设计了接收ICMP请求包并回复的功能。 3.6.1 ICMP接收模块该模块首先过滤掉ICMP报文头部,并且对头部数据进行校验,校验方式和IP首部校验相同。 - //ICMP报文的校验和
- always@(posedge I_clk or posedge I_reset) begin
- if(I_reset) begin
- accum1 <= 16'd0;
- accum2 <= 32'd0;
- checksum_state <= 2'd0;
- checksum_correct <= 1'b1;
- end
- else begin
- case(checksum_state)
- 0:begin
- if(I_icmp_pkg_valid) begin
- accum1[15:8] <= I_icmp_pkg_data;
- checksum_state <= 2'd1;
- end
- else begin
- accum1[15:8] <= 8'd0;
- checksum_state <= 2'd0;
- end
- end
- 1:begin
- accum1[7:0] <= I_icmp_pkg_data;
- checksum_state <= 2'd2;
- end
- 2:begin
- if(!I_icmp_pkg_valid) begin
- checksum_state <= 2'd3;
- if((tmp_accum1[15:0] + tmp_accum1[31:16]) != 16'hffff)
- checksum_correct <= 1'b0;
- else
- checksum_correct <= 1'b1;
- end
- else begin
- accum2 <= tmp_accum1;
- accum1[15:8] <= I_icmp_pkg_data;
- checksum_state <= 2'd1;
- end
- end
- 3:begin
- accum1 <= 16'd0;
- accum2 <= 32'd0;
- checksum_state <= 2'd0;
- end
- endcase
- end
- end
复制代码将报文的附加数据存入FIFO中,并向icmp_pkg_tx模块发送ping应答信息,请求发送ping应答包。 - //以下模块完成ICMP报文包echo ping应答的请求,并且先缓存到ip_layer的FIFO中
- always@(posedge I_clk or posedge I_reset) begin
- if(I_reset) begin
- cnt <= 4'd0;
- type1 <= 8'd0;
- code <= 8'd0;
- echo_data_cnt <= 10'd0;
- checksum <= 16'd0;
- O_icmp_req_en <= 1'b0;
- O_icmp_req_id <= 16'd0;
- O_icmp_req_sq_num <= 16'd0;
- O_icmp_ping_echo_data_valid <= 1'b0;
- O_icmp_ping_echo_data <= 8'd0;
- O_icmp_req_checksum <= 16'd0;
- STATE <= RECORD_ICMP_HEADER;
- end
- else begin
- case(STATE)
- RECORD_ICMP_HEADER:begin
- O_icmp_req_en <= 1'b0;
- echo_data_cnt <= 10'd0;
- if(I_icmp_pkg_valid) //ICMP报文有效
- case(cnt)
- 0: begin type1 <= I_icmp_pkg_data; cnt <= cnt + 1'b1;end //ICMP报文首部-类型:8位数表示错误类型的差错报文或者查询类型的报告报文,一般是查询报文(0代表回显应答(ping应答);1代表查
- 1: begin code <= I_icmp_pkg_data; cnt <= cnt + 1'b1;end //ICMP报文首部-类型:代码占用8位数据,根据ICMP差错报文的类型,进一步分析错误的原因
- 2: begin checksum[15:8] <= I_icmp_pkg_data; cnt <= cnt + 1'b1;end //ICMP报文首部-校验和:16位校验和的计算方法与IP首部校验和计算方法一致,该校验和需要对ICMP首部和ICMP数据做校验
- 3: begin checksum[7:0] <= I_icmp_pkg_data; cnt <= cnt + 1'b1;end //ICMP报文首部-校验和:16位校验和的计算方法与IP首部校验和计算方法一致,该校验和需要对ICMP首部和ICMP数据做校验
- 4: begin O_icmp_req_id[15:8] <= I_icmp_pkg_data; cnt <= cnt + 1'b1;end //ICMP报文首部-标识符:16位标识符对每一个发送的数据报进行标识
- 5: begin O_icmp_req_id[7:0] <= I_icmp_pkg_data; cnt <= cnt + 1'b1;end //ICMP报文首部-标识符:16位标识符对每一个发送的数据报进行标识
- 6: begin O_icmp_req_sq_num[15:8] <= I_icmp_pkg_data; cnt <= cnt + 1'b1;end //ICMP报文首部-序列号:16位对发送的每一个数据报文进行编号
- 7: begin O_icmp_req_sq_num[7:0] <= I_icmp_pkg_data; cnt <= cnt + 1'b1;end //ICMP报文首部-序列号:16位对发送的每一个数据报文进行编号
- 8: begin
- if(type1 == PING_REQUEST && code == 8'h00) begin //如果是远端主机发的ping请求包,那么本地主机需要返回一个ping应答包
- O_icmp_ping_echo_data_valid <= 1'b1; //ping应答有效
- O_icmp_ping_echo_data <= I_icmp_pkg_data;
- end
- else begin
- O_icmp_ping_echo_data_valid <= 1'b0;
- O_icmp_ping_echo_data <= 8'd0;
- end
- cnt <= 4'd0;
- STATE <= WAIT_PACKET_END;
- end
- default: STATE <= RECORD_ICMP_HEADER;
- endcase
- else
- STATE <= RECORD_ICMP_HEADER;
- end
- WAIT_PACKET_END:begin
- if(I_icmp_pkg_valid) begin //继续接收ICMP 报文
- if(O_icmp_ping_echo_data_valid) //ping应答有效
- echo_data_cnt <= echo_data_cnt + 1'b1;//ICMP包计数器
- else
- echo_data_cnt <= 10'd0;
- O_icmp_ping_echo_data_valid <= O_icmp_ping_echo_data_valid;
- O_icmp_ping_echo_data <= I_icmp_pkg_data;
- STATE <= WAIT_PACKET_END;
- end
- else begin
- if(O_icmp_ping_echo_data_valid) begin
- O_icmp_req_en <= 1'b1; //通知ip_tx模块接收到ICMP报文包ping请求,并且发送一个echo ping应答
- O_icmp_req_checksum <= checksum_temp; //输出校验和
- end
- else begin
- O_icmp_req_en <= 1'b0;
- O_icmp_req_checksum <= 16'd0;
- end
- echo_data_cnt <= echo_data_cnt;
- O_icmp_ping_echo_data_valid <= 1'b0;
- O_icmp_ping_echo_data <= 8'd0;
- STATE <= RECORD_ICMP_HEADER;
- end
- end
- endcase
- end
- end
复制代码 3.6.2 ICMP发送模块该模块收到icmp_pkg_ctrl模块发送的ping应答包使能信号,寄存接收到的信息包括标识符、序列号、校验和、地址和数据长度,通过计数器添加报文头部,再将附加数据从FIFO中读出,组成ping应答包发送到ip_tx模块。 - always@(posedge I_clk or posedge I_reset) begin
- if(I_reset) begin
- cnt1 <= 4'd0;
- cnt2 <= 10'd0;
- request_id <= 16'd0;
- request_sq_num <= 16'd0;
- request_ip_taddress <= 32'd0;
- checksum <= 16'd0;
- echo_data_length <= 10'd0;
- O_icmp_pkg_req <= 1'b0;
- O_icmp_pkg_valid <= 1'b0;
- O_icmp_pkg_data <= 8'd0;
- O_icmp_ping_echo_ren <= 1'b0;
- STATE <= WAIT_ICMP_PACKET;
- end
- else begin
- case(STATE)
- WAIT_ICMP_PACKET:begin
- if(I_icmp_req_en) begin//当接收到ICMP echo ping包,先保存该包的基本信息到寄存器
- request_id <= I_icmp_req_id; //ICMP包的标识符
- request_sq_num <= I_icmp_req_sq_num; //ICMP包的序列号
- request_ip_taddress <= I_icmp_req_ip_addr; //ICMP包的地址
- checksum <= I_icmp_req_checksum; //ICMP包的校验和
- echo_data_length <= I_icmp_ping_echo_data_len; //ICMP包的长度
- O_icmp_pkg_req <= 1'b1; //请求ip_tx模块发送部分,发送ICMP报文
- STATE <= WAIT_PACKET_SEND; //发送ICMP包状态
- end
- else begin
- request_id <= 16'd0;
- request_sq_num <= 16'd0;
- request_ip_taddress <= 32'd0;
- checksum <= 16'd0;
- echo_data_length <= 10'd0;
- O_icmp_pkg_req <= 1'b0;
- STATE <= WAIT_ICMP_PACKET;
- end
- end
- WAIT_PACKET_SEND:begin
- if(I_icmp_pkg_busy) begin//该信号来自ip_tx模块,当有效代表ip_tx模块已经开始准备发送ICMP包,这里需要对ip_tx代码部分时序逻辑确保数据正确给到ip_tx模块
- O_icmp_pkg_req <= 1'b0;
- O_icmp_pkg_valid <= 1'b1;
- O_icmp_pkg_data <= PING_REPLY_TYPE;//回显应答(ping应答)的类型
- STATE <= SEND_PACKET;
- end
- else begin
- O_icmp_pkg_req <= 1'b1;
- O_icmp_pkg_valid <= 1'b0;
- O_icmp_pkg_data <= 8'd0;
- STATE <= WAIT_PACKET_SEND;
- end
- end
- SEND_PACKET:begin
- case(cnt1)
- 0 :begin O_icmp_pkg_data <= 8'h00; cnt1 <= cnt1 + 1'b1;end//回显应答(ping应答)的代码
- 1 :begin O_icmp_pkg_data <= checksum[15:8]; cnt1 <= cnt1 + 1'b1;end//ICMP报文包校验和,直接获取远程主机发送的Ping包校验和
- 2 :begin O_icmp_pkg_data <= checksum[7:0]; cnt1 <= cnt1 + 1'b1;end//ICMP报文包校验和,直接获取远程主机发送的Ping包校验和
- 3 :begin O_icmp_pkg_data <= request_id[15:8]; cnt1 <= cnt1 + 1'b1;end//ICMP报文标识符,直接获取远程主机发送的Ping包标识符
- 4 :begin O_icmp_pkg_data <= request_id[7:0]; cnt1 <= cnt1 + 1'b1;end//ICMP报文标识符,直接获取远程主机发送的Ping包标识符
- 5 :begin O_icmp_pkg_data <= request_sq_num[15:8]; cnt1 <= cnt1 + 1'b1;end//ICMP报文编码,直接获取远程主机发送的Ping序列号
- 6 :begin //从echo FIFO中读取ICMP echo报文的数据部分
- O_icmp_pkg_data <= request_sq_num[7:0];
- cnt1 <= cnt1 + 1'b1;
- O_icmp_ping_echo_ren <= 1'b1;
- end
- 7 :begin//ICMP报文包的数据有效部分
- O_icmp_pkg_valid <= 1'b1;
- O_icmp_pkg_data <= I_icmp_ping_echo_data;
- if(cnt2 == (echo_data_length - 1)) begin
- cnt2 <= 10'd0;
- O_icmp_ping_echo_ren <= 1'b0;
- cnt1 <= cnt1 + 1'b1;
- end
- else begin
- cnt2 <= cnt2 + 1'b1;
- O_icmp_ping_echo_ren <= 1'b1;
- cnt1 <= cnt1;
- end
- end
- 8 :begin
- cnt1 <= 4'd0;
- O_icmp_pkg_data <= 8'd0;
- O_icmp_pkg_valid <= 1'b0;
- STATE <= WAIT_ICMP_PACKET;
- end
- default:;
- endcase
- end
- endcase
- end
- end
复制代码 |