1. IP介绍
IP是TCP/IP协议族中最为核心的协议。大家,如TCP、UDP、ICMP及IGMP数据,都是在IP数据报格式基础上再封装一层再来传输的(见图1 - 4)。
不可靠(unreliable)的意思是它不能保证 IP数据报能成功地到达目的地。 IP仅提供最好的传输服务。如果发生某种错误时,如某个路由器暂时用完了缓冲区, IP有一个简单的错误处理算法:丢弃该数据报,然后发送 ICMP消息报给信源端。任何要求的可靠性必须由上层来提供(如TCP) 。
无连接(connectionless)这个术语的意思是I P并不维护任何关于后续数据报的状态信息。每个数据报的处理是相互独立的。这也说明, IP数据报可以不按发送顺序接收。如果一信源向相同的信宿发送两个连续的数据报(先是 A,然后是B) ,每个数据报都是独立地进行路由选择,可能选择不同的路线,因此B可能在A到达之前先到达。
2. IP首部
I P数据报的格式如图3 - 1所示。普通的IP首部长为20个字节,除非含有选项字段。
分析图3 - 1中的首部。最高位在左边,记为0 bit;最低位在右边,记为31 bit。4个字节的32 bit值以下面的次序传输:首先是0~7 bit,其次8~15 bit,然后1 6~23 bit,最后是24~31 bit。这种传输次序称作big endian字节序。由于TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序。
目前的协议版本号是4,因此IP有时也称作IPv4。
服务类型(TOS)字段包括一个3 bit的优先权子字段(现在已被忽略) ,4 bit的TO S子字段和1 bit未用位但必须置0。4 bit的TO S分别代表:最小时延、最大吞吐量、最高可靠性和最小费用。
总长度字段是指整个I P数据报的长度,以字节为单位。
标识字段唯一地标识主机发送的每一份数据报。通常每发送一份报文它的值就会加 1。在大多数从伯克利派生出来的系统中,每发送一个I P数据报,I P层都要把一个内核变量的值加1,不管交给IP的数据来自哪一层。内核变量的初始值根据系统引导时的时间来设置。
TTL(time-to-live)生存时间字段设置了数据报可以经过的最多路由器数。TTL的初始值由源主机设置(通常为3 2或6 4) ,一旦经过一个处理它的路由器,它的值就减去1。当该字段的值为0时,数据报就被丢弃,并发送 ICMP报文通知源主机。
协议字段可以识别是哪个协议向I P传送数据。
首部检验和字段是根据IP首部计算的检验和码。它不对首部后面的数据进行计算。 ICMP、IGMP、UDP和TCP在它们各自的首部中均含有同时覆盖首部和数据检验和码。
目前,这些任选项定义如下:
• 安全和处理限制(用于军事领域,详细内容参见 RFC 1108[Kent 1991])
• 记录路径(让每个路由器都记下它的IP地址,见7 . 3节)
• 时间戳(让每个路由器都记下它的IP地址和时间,见7 . 4节)
• 宽松的源站选路(为数据报指定一系列必须经过的 IP地址,见8 . 5节)
• 严格的源站选路(与宽松的源站选路类似,但是要求只能经过指定的这些地址,不能经过其他的地址) 。
------------------------------------------以上内容整理于《TCP/IP协议详解:卷1》--------------------------------------
------------------------------------------以下内容产生于代码及分析--------------------------------------
3. IP宏定义实现
C++ Code
1 | // ******* IP ******* |
4. IP函数实现
以太网的header在IP的header之前,很简单的,介绍先。
配置以太网的头,为14字节:6字节目的mac地址+6字节源mac地址+2字节协议类型
1 | // make a return eth header from a received eth packet |
展开之后如下所示,其在以太网帧中的位置与之前的宏定义是一一对应的。
IP与ARP一样,需要判定是不是发给本机的(eth_type_is_ip_and_my_ip函数),还有与填充make_eth 函数一样需要填充函数(make_ip函数),此外还有填充其他杂七杂八和16位首部校验和函数(fill_ip_hdr_checksum函数)
C++ Code
1 | //判定过程与eth_type_is_arp_and_my_ip类似 |
5. IP校验和实现
校验和函数式如何得出校验和值的呢?看《TCP/IP协议详解:卷1》里面咋说的吧。
”为了计算一份数据报的 IP检验和,首先把检验和字段置为 0。然后,对首部中每个 16 bit进行二进制反码求和(整个首部看成是由一串 16 bit的字组成) ,结果存在检验和字段中。当收到一份I P数据报后,同样对首部中每个16 bit进行二进制反码的求和。由于接收方在计算过程中包含了发送方存在首部中的检验和,因此,如果首部在传输过程中没有发生任何差错,那么接收方计算的结果应该为全 1。如果结果不是全1(即检验和错误) ,那么I P就丢弃收到的数据报。但是不生成差错报文,由上层去发现丢失的数据报并进行重传。
ICMP、IGMP、UDP和TCP都采用相同的检验和算法,尽管TCP和UDP除了本身的首部和数据外,在IP首部中还包含不同的字段。在RFC 1071[Braden, Borman and Patridge 1988]中有关于如何计算Internet检验和的实现技术。由于路由器经常只修改 TTL段(减1) ,因此当路由器转发一份报文时可以增加它的检验和,而不需要对 IP整个首部进行重新计算。 RFC1141[Mallory and Kullberg 1990]为此给出了一个很有效的方法。“
但是本协议栈的实现顺序上与以上说的略有不同,《TCP/IP协议详解:卷1》是先反码再求和,本协议栈里面是先求和再反码,当然都是按照16bit单位的单元来的。那结果一样么?
比如:
11101010 01010100
10000000 11111110
先反码再求和:
取反
00010101 10101011
01111111 00000001
求和
10010100 10101100
先求和再反码:
求和
1 01101011 01010010
将进位加置最后来保持16位(下面的代码如是说)
01101011 01010011
取反
10010100 10101100
没错,不完全验证两种方法的结果是一致的,不是科班出身,感觉上有啥子理论来说明某种顺序的调换在对二进制运算结果方面的影响是无关的。
C++ Code
1 | unsigned int checksum(unsigned char * buf, unsigned int len,unsigned char type) |
------------------------------------------------------------------------------------------------------
6. ICMP简介
注意:ICMP在TCP/IP分层上与IP属于同一层,因此放在与IP一块,但是ICMP是封装在IP数据报里面的。
ICMP:Internet Control Messages Protocol, 网间控制报文协议
ICMP报文的格式如图6 - 2所示。所有报文的前4个字节都是一样的,但是剩下的其他字节则互不相同。下面我们将逐个介绍各种报文格式。类型字段可以有1 5个不同的值,以描述特定类型的 ICMP报文。某些ICMP报文还使用代码字段的值来进一步描述不同的条件。
检验和字段覆盖整个ICMP报文。使用的算法与I P首部检验和算法相同。ICMP的检验和是必需的。
7. ICMP宏定义及函数实现
虽然ICMP具有很多的子协议,但是其中最著名的要数ping程序,即ICMP回显请求和应答报文。通过使用ping命令来判断报文是否可以到达目标地址。ICMP的实现是一个逐步遵守规则的过程,即向固定的字节填充数据,其实本协议栈也就实现了这个ping。
“ping”这个名字源于声纳定位操作。 Ping程序由Mike Muuss编写,目的是为了测试另一台主机是否可达。该程序发送一份 ICMP回显请求报文给主机,并等待返回 ICMP回显应答。
当返回ICMP回显应答时,要打印出序列号和TTL,并计算往返时间(TTL位于 IP首部中的生存时间字段)。
ICMP回显应答需要做好两步,第一步检查IP首部中的协议类型是否为ICMP报文;第二,检查ICMP首部中的ICMP类型是否为ICMP请求,如果是则生成ICMP回显应答并通过以太网驱动芯片发送。为了便于调试,在接收到ICMP回显请求时通过串口输出发起方的IP地址,ping命令发起方的IP地址存在于IP首部中的源IP地址部分。
C++ Code
1 | // ******* ICMP ******* //ICMP_DEBUG插入此处 |
8 ICMP实验调试
C++ Code
1 | void make_echo_reply_from_request(unsigned char * buf,unsigned int len) |
在程序的无线循环中,需要层层进行查询。其实就是各种if语句来判定以太网帧的那些个标记为是不是所要找的类型。
1.查询以太网中是否有数据,若无数据则返回。
2.保存源MAC地址,待返回时使用。
3.查询是否为ARP报文并返回ARP报文
4.保存源IP地址,待返回时使用。
6.查询是否为IP报文,若非IP报文返回。
5.查询是否为ICMP报文并返回ICMP回显应答。
这里可以修改fill_ip_hdr_checksum函数里面的ttl(time to live)值,来确定IP包的生存周期,就是经过几个路由之后被丢弃掉。修改为以下的125。
如果按照注释里面改正之后~~~
上一篇:分析TCP/IP协议栈代码之ARP(STM32平台)
下一篇:分析TCP/IP协议栈代码之TCP(STM32平台)
推荐阅读最新更新时间:2024-03-16 16:00
设计资源 培训 开发板 精华推荐
- 【泰克注册观看有礼】 PCI-SIG 前主席解析:PCI Express5.0测试方案和测量挑战
- 一起哇:基于国产芯、便携烙铁系统IronOS(FreeRTOS)的智能烙铁
- 西门子EDA直播:多板产品互联规划方案,为破局而来!
- 有奖问答:在线寻找英特尔® 视觉加速设计“全知”达人
- 免费试用+优惠购+任务解锁赢好礼!这个夏天pyboardCN V2畅玩走起!
- 【预约有礼】全球测量圈大咖直播:验证5G核心网,确保最佳性能
- 有奖直播|大唐恩智浦半导体 | 电池管理芯片方案设计和注意事项
- 将低功耗设计进行到底——评论、转发赢大礼!
- 有奖直播:AC/DC 在 ATX 及 Server 电源解決方案及应用 报名开始啦!
- 开学季!解锁奇楼去充电,玩转幸运大抽奖~抽不中再抽