当前位置:   article > 正文

ip分片代码_UDP/IP硬件协议栈设计(二):分类

撸就完了

ebf77e3f47a38a85c34cdd873b1b04fb.png

上回确定了UDP/IP硬件协议栈的基本目标,历时五天终于把代码撸完了,简单上板测试下问题不大,接下来就是简单把设计过程介绍下。

首先声明:并未参考网上其他代码 ,全部是对照《TCP/IP详解》一书完成的,所以处理机制不合适还望指正!

首先是分类,即问进来的以太网数据“你是什么垃圾?”

d6d03d732427a609da421f4cd689a774.png
你是什么垃圾

对于本弟弟协议栈来说,进入的数据先粗分为“ARP”、“ICMP”、“UDP”和“others”。其中ICMP和UDP是基于IP协议的,而本协议栈的IP协议不支持分片、option、IPv6等,所以在分类时需注意。

在分类前得先清楚以太网帧长什么样子

2e6794edfbfc179d0e161bf0fd8ca59d.png
说到以太网帧就要祭出这张图了

如上图所示[1],以TCP协议为例:

  1. 一条完整的以太网帧包括了14字节的以太网首部、46-1500字节的以太网数据部分和4字节的以太网尾部,而以太网首部中的类型字段会标明其数据部分为何协议,比如0x0800即IPv4协议,就是说以太网数据包含了IP数据报,同时该数据报的长度需要在46-1500字节之间;
  2. 同样,对于IP数据报,也有IP首部和IP数据部分,其中IP首部会标明IP数据报的长度、首部长度以及IP数据部分协议类型,比如0x06即TCP协议;
  3. 同样,对于TCP数据报,也有其TCP首部和TCP数据两部分......

直接使用wireshark抓包来看以太网帧结构会更加方便,如下图所示 :

2c186f98221e5e8a496dfc4635dd412c.png
wireshark抓的数据报

总之,以太网帧就像套娃一样将“用户数据”层层打包进行发送,而接收的时候也是层层拆包把“用户数据”解析出来。

当然,要区分这些协议就需知道这些协议的标识字段。

  • ARP

ARP的请求或应答的帧结构如下图所示[2],有14字节的MAC首部和28字节ARP数据,其中MAC首部中的帧类型字段为0806标明接下来的是ARP帧,而ARP除了标明硬件、协议的类型/地址长度字段外,有个2字节的opcode字段,当为0x0001时为请求,0x0002为应答。

f74b66418da1ac8b6e5be43db50f8f29.png
ARP请求或应答帧结构

似乎看不太明白,直接上wireshark,下图即一次ARP的请求帧。

16163f5fe7e4a8f88e3cf14dc0707f03.png
wireshark抓的ARP请求帧内容

那么获取ARP请求帧就简单了,当MAC首部的Type字段为0x0806,并且ARP数据报中Opcode字段为0x0001,并且请求的Target IP地址为本机的IP地址,这样就能筛选出一条对本机请求的一条ARP帧。

  • IP

前面说了MAC首部中的类型字段若是0x0800的话即表示接下来的协议为IPv4协议,而ICMP和UDP都是基于IP协议的,所以先来看看它的首部的字段。

4bit的版本字段(Version)标明其IP协议的版本,4'b0100即表示为IPv4;

4bit的首部长度字段(Header length)标明IP首部的长度,像是4'b0101即表示首部长度为20字节(若有option则首部长度会更长一点);

1字节的协议字段(Protocol)标明IP数据部分的协议,像是8'h01为ICMP,8'h11为UDP;

当然,其他字段也有用,但对于本文来说只关注其版本、首部长度、协议等字段,可用于分类使用。

762dbe4b5ff222d76321203e59dcb427.png
IP数据报格式及首部中的各字段
  • ICMP

对于ICMP,是基于IP协议的(前面所示),直接看ICMP的报文,此外不同类型/代码的ICMP的报文格式会有些许差别,下图仅为回显请求和应答的报文格式(用于PING)[3],其中的类型字段,0x08标明请求,0x00标明应答。

1f64da0934618bec657bcf27dff7541c.png
ICMP回显请求和回显应答报文格式

直接看wireshark抓包,如下图所示

b944b8f4df31cc80e9f6ffa973dd2c2d.png

那么,要获取ICMP帧(ping请求)则需要,MAC首部的类型字段为0x0800(仅考虑IPv4),IP首部协议字段为0x01,ICMP报文的类型字段为0x08(请求)。

  • UDP

UDP帧是本协议栈的重点,直接看wireshark抓包,如下图

9a8c29d12d4829326dd6a3ce70cad659.png
wireshark抓的UDP帧

UDP也是采用IP协议,所以可以通过IP首部的protocol类型来判断,0x11即标明为UDP。而UDP作为本协议栈的主要传输的数据,所以对于其首部的端口等信息直接传给应用层,不再加以分类处理了。

总结就是,要获取UDP帧,MAC首部的类型字段为0x0800(仅考虑IPv4),IP首部协议字段为0x11(即UDP)

  • OTHERS

对本协议栈来说,非上述协议的以太网帧即其他帧,可以选择直接丢弃。

那开始分类吧

由于以太网帧传输采用大端模式,所以对接收的数据提取关键信息时需注意,此外整个流程为流水处理,所以直接对接收的字节进行移位寄存获取相应字段的信息,从而完成提取和分类。

  • MAC首部
always 

以上即获取MAC首部,只有当目的mac地址与本机的mac地址一样或者为广播地址时才认为有效,同时在MAC首部中可以简单分为IP协议和ARP协议,其余的进行舍弃。

  • IP首部

IP首部获取同样采用移位寄存方式,获取20字节的IP首部信息(暂不支持IPv6和option等),从协议类型字段中可获取IP数据部分的协议,总长度字段需小于等于1500字节(MTU),至于帧长大于MTU的巨型帧采取丢弃处理,此外目的IP地址需要与本机的一致,其他的予以舍弃。

assign 
  • ICMP首部
always 

只有当icmp_type为0x08时才认为有效,其他予以舍弃。

  • UDP首部
always 

UDP首部同理,解析后的首部信息{源端口、目的端口、UDP帧长、UDP首部checksum}需交予其他逻辑处理,在分类中暂不说明。

  • 数据部分

对于ARP而言,数据部分只对ARP处理模块输出完整的28字节的ARP数据(padding不输出),至于是否应答均交由后续逻辑判断,本文不加以说明;

对于ICMP而言,输出完整的ICMP数据(8字节头和数量不等的padding),交由后续逻辑处理;

对于UDP而言,输出完整的UDP纯数据(UDP首部以后的数据),交由后续逻辑处理。

  • 解析的状态

包括:源/目的MAC地址,源/目的IP地址,源/目的端口,数据帧长等,这个状态信息随着每帧的数据进行输出,供后续模块处理使用。

  • 最后分类结果

7b3816c2b35021ad12e08e1bbe0f6aef.png
分类处理后的结果

当然,仅仅完成协议解析分类还是不够的,如果需要检验checksum或者FCS进行过滤的话,还需要再次对解析的数据进行校验计算,为降低延迟,需要在收到数据的同时进行校验的计算,不过,这也就是下篇该完成的事情了。

若有不足之处还望请批评指教~


十二点过九分:UDP/IP硬件协议栈设计(三):校验​zhuanlan.zhihu.com
6f07ad6ff394c4b98a1e2fbf4a5102a6.png

参考

  1. ^《TCP/IP详解 卷一:协议》第7页
  2. ^《TCP/IP详解 卷一:协议》第40页
  3. ^《TCP/IP详解 卷一:协议》第61页
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/187172
推荐阅读
相关标签
  

闽ICP备14008679号