概述
前面耽搁了几天搞了个大东西(又离毕业远了一步),似乎前面已经完成了ARP的应答和ARP表的设计,终于可以使用IP协议进行通信了。
接下来是根据协议栈设计(二)分类中得到的ICMP数据进行处理,不过本文只针对回显请求(ping功能)进行处理,即“我叫你一声,你敢答应吗?”。
前文说过ICMP实现在IP系统间传递差错和管理报文,但是就目前的设计需要而言,只想完成“你叫上千声,我就答应你千声!”,所以只处理其回显请求,你敢ping我,我就敢答应。
- 看看ping都干了些什么
我们时常在同一局域网的不同主机之间的通信中会遇到数据无法传输的问题,总会习惯性的调出CMD,熟练的敲上“ping 192.168.xxx.xxx”,然后惊叹一句“竟然ping不通!”,当然也会发出“为什么ping通了,还是连不上?”
为了探清楚这一过程,进行这一操作如下图所示, 一共ping两次,一次默认,另一次设padding长度为500字节,如果能ping通,则会受到来自对方地址的回复。
同时再打开wireshark去捕获上述的过程如下图所示:
从上两张图中可以看到:
- 在本主机的CMD中输入"ping 192.168.208.1"指令后,将会发出四条回显请求(Echo request)的ICMP帧;
- 对方主机每次收到回显请求的ICMP帧后,会回复一条回显应答(Echo reply)的ICMP帧;
- 本主机每收到一条来自对方主机的回显应答帧后,解析其内容(padding字节长度、TTL等信息),并在CMD栏中显示出来;
- 如果ping的时候,将padding字节长度设为500字节,则收到对方的应答帧的padding长度也将是500字节;
- ICMP报文结构分析
对ping的过程有所了解后,再来看看其报文结构,也就是前文分类中处理得到的ICMP数据报文,如下图所示:
可见其字段分别为:
- 类型(Type):1字节,8'h00表示reply,8'h08表示request;
- 代码(Code):1字节,在回显请求和应答中填8'h00;
- 校验和(Checksum):2字节,校验一文中说过,这里不再多说;
- 标识符(Identifier):2字节,用于标识,reply帧需与对应的request帧一致;
- 序号(Sequence):2字节,在request中,每请求一次,该字段加一,reply帧需与对应的request帧一致;
- 数据(Data):至少32字节,即ICMP报文中需填充的数据,reply帧需与对应的request帧一致;
- 回显请求的处理
前面介绍了回显请求应答的过程和报文结构,可以发现,如果要处理一条ICMP Echo request帧,需要:
- 解析其类型字段,仅当为8'h08时,才进行应答,其他时予以舍弃处理;
- 当可以应答时,将应答帧(reply)的类型字段置为8'h00;
- 当可以应答时,保证应答帧(reply)的标识符、序号、数据字段的数据与请求帧(request)一致;
- 当可以应答时,校验和字段需重新按照前文所说的方式计算;
以上的处理过程用verilog可表示为:
对前文分类中解析得到的ICMP数据进行移位寄存处理
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
icmp_data_valid_shift <= 16'h0;
icmp_data_shift <= 80'h0;
end
else begin
icmp_data_valid_shift <= {icmp_data_valid_shift[14:0],icmp_data_valid};
icmp_data_shift <= {icmp_data_shift[71:0],icmp_data};
end
end
当ICMP的type为request才进行应答
assign icmp_reply_valid = (icmp_type == 8'h08); //当type为08时才应答
对于应答帧中的Checksum计算,因为需要首部和数据均参与计算,而本协议栈在分类解析时就对接收的ICMP帧进行过计算了,为降低延迟,可在解析过程中单独对其数据部分进行累加,累加结果可随着ICMP报文传递至该处理模块中,这样,在计算应答帧的Checksum时可直接加上数据部分的累加值,如此一来,Checksum的计算可在短时间内完成:
assign icmp_checksum_clac_en = (icmp_data_valid_shift[5] && (!icmp_data_valid_shift[6])) ||
(icmp_data_valid_shift[7] && (!icmp_data_valid_shift[8]));
assign icmp_data_shift2 = icmp_data_shift[15:0];
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
icmp_checksum_clac_32 <= 32'h0;
end
else if (icmp_type_en) begin
icmp_checksum_clac_32 <= current_frame_data_checksum; //数据部分的累加值由前级传递而来
end
else if (icmp_checksum_clac_en) begin
icmp_checksum_clac_32 <= icmp_checksum_clac_32 + icmp_data_shift2;
end
end
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
icmp_checksum_clac_temp <= 32'h0;
icmp_checksum <= 16'h0;
end
else begin
icmp_checksum_clac_temp <= icmp_checksum_clac_32[31:16] + icmp_checksum_clac_32[15:0];
icmp_checksum <= ~{{15'h0,icmp_checksum_clac_temp[16]} + icmp_checksum_clac_temp[15:0]};
end
end
其他就是按照报文结构依次组成ICMP的Echo reply帧(仅包括ICMP报文部分),存入FIFO中,待发送模块进行发送处理:
//reply type and code
assign reply_type_code_valid = icmp_reply_valid && (icmp_data_valid_shift[8] && (!icmp_data_valid_shift[8+2]));
assign reply_type_code = 9'h0;
//reply icmp checksum
assign reply_checksum_valid = icmp_reply_valid && (icmp_data_valid_shift[10] && (!icmp_data_valid_shift[10+2]));
assign reply_checksum_h = (icmp_reply_valid && (icmp_data_valid_shift[10] && (!icmp_data_valid_shift[11])))?{1'b0,icmp_checksum[15:8]}:9'h0;
assign reply_checksum_l = (icmp_reply_valid && (icmp_data_valid_shift[11] && (!icmp_data_valid_shift[12])))?{1'b0,icmp_checksum[7:0]}:9'h0;
//reply identifier/sequence num/data
assign reply_id_seqnum_data_valid = icmp_reply_valid && icmp_data_valid_shift[8] & icmp_data_valid_shift[10+2];
assign reply_id_seqnum_data_last = icmp_reply_valid && (~icmp_data_valid_shift[7]) & icmp_data_valid_shift[8];
assign reply_id_seqnum_data = reply_id_seqnum_data_valid?{reply_id_seqnum_data_last,icmp_data_shift[71:64]}:9'h0;
//reply data
assign icmp_reply_data_valid = reply_type_code_valid | reply_checksum_valid | reply_id_seqnum_data_valid;
assign icmp_reply_data = reply_type_code | reply_checksum_h | reply_checksum_l | reply_id_seqnum_data;
最后的仿真结果如下图所示:
以上即ICMP中回显请求的处理过程,针对ICMP中的其他功能由于暂时使用不到,故不作处理,这样一来,协议栈完成了地址的解析、网络通达的检测,之后就可以传数据了,且听下回分解。
若有错误还望批评指正!
十二点过九分:UDP/IP硬件协议栈设计(七):UDPzhuanlan.zhihu.com
最后
以上就是糟糕豌豆为你收集整理的icmp协议_UDP/IP硬件协议栈设计(六):ICMP的全部内容,希望文章能够帮你解决icmp协议_UDP/IP硬件协议栈设计(六):ICMP所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复