分析TCP/IP协议栈代码之IP & ICMP(STM32平台)

发布者:以泉换泉最新更新时间:2018-04-28 来源: eefocus关键字:TCP  IP协议栈  IP  ICMP  STM32平台 手机看文章 扫描二维码
随时随地手机看文章

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30


// ******* IP *******
//IP首部长度
#define IP_HEADER_LEN   20

//IP版本号位置 以太网首部2+6+6,与下面那个在用的时候上区别下
#define IP_HEADER_LEN_VER_P 0xe

//IP版本号位置 以太网首部2+6+6
#define IP_P 0xe
//IP 16位标志位置
#define IP_FLAGS_P 0x14
//IP 生存时间位置
#define IP_TTL_P 0x16
//IP协议类型位置,如ICMP,TCP,UDP 1个字节
#define IP_PROTO_P 0x17
//首部校验和
#define IP_CHECKSUM_P 0x18
// IP源地址位置 14+12
#define IP_SRC_P 0x1a
// IP目标地址位置 14+12+4
#define IP_DST_P 0x1e

//IP总长度
#define IP_TOTLEN_H_P 0x10
#define IP_TOTLEN_L_P 0x11

//协议类型
#define IP_PROTO_ICMP_V 0x01
#define IP_PROTO_TCP_V 0x06
#define IP_PROTO_UDP_V 0x11


4. IP函数实现

以太网的header在IP的header之前,很简单的,介绍先。

 配置以太网的头,为14字节:6字节目的mac地址+6字节源mac地址+2字节协议类型

1
2
3
4
5
6
7
8
9
10
11
12
13


// make a return eth header from a received eth packet
void make_eth(unsigned char *buf)
{
    unsigned char  i = 0;

    //copy the destination mac from the source and fill my mac into src
    while(i < sizeof(mac_addr))
    {
        buf[ETH_DST_MAC + i] = buf[ETH_SRC_MAC + i];
        buf[ETH_SRC_MAC + i] = macaddr[i];
        i++;
    }
}


展开之后如下所示,其在以太网帧中的位置与之前的宏定义是一一对应的。


IP与ARP一样,需要判定是不是发给本机的(eth_type_is_ip_and_my_ip函数),还有与填充make_eth  函数一样需要填充函数(make_ip函数),此外还有填充其他杂七杂八和16位首部校验和函数(fill_ip_hdr_checksum函数)

 C++ Code 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66


//判定过程与eth_type_is_arp_and_my_ip类似
unsigned char  eth_type_is_ip_and_my_ip(unsigned char *buf, unsigned  int len)
{
    unsigned char  i = 0;

    //eth+ip+udp header is 42
    if(len < MIN_FRAMELEN)
    {
        return(0);
    }

    if(buf[ETH_TYPE_H_P] != ETHTYPE_IP_H_V || buf[ETH_TYPE_L_P] != ETHTYPE_IP_L_V)
    {
        return(0);
    }

    if(buf[IP_HEADER_LEN_VER_P] != 0x45)
    {
        // must be IP V4 and 20 byte header
        return(0);
    }

    while(i < sizeof(ipv4_addr))
    {
        if(buf[IP_DST_P + i] != ipaddr[i])
        {
            return(0);
        }

        i++;
    }

    return(1);
}
//下面那个ip填充函数调用它,主要是补充填充和校验和
void fill_ip_hdr_checksum(unsigned char *buf)
{
    unsigned  int ck;
    // clear the 2 byte checksum
    buf[IP_CHECKSUM_P] = 0;
    buf[IP_CHECKSUM_P + 1] = 0;
    buf[IP_FLAGS_P] = 0x40; // don't fragment
    buf[IP_FLAGS_P + 1] = 0; // fragement offset
    buf[IP_TTL_P] = 64; // ttl
    // calculate the checksum:
    //校验和计算,在下下面那个函数里面,输入参数的含义下面看就晓得了
    ck = checksum(&buf[IP_P], IP_HEADER_LEN, 0);
    buf[IP_CHECKSUM_P] = ck >> 8;
    buf[IP_CHECKSUM_P + 1] = ck & 0xff;
}

// make a return ip header from a received ip packet
//与以太网填充函数类似,填充ip地址
void make_ip(unsigned char *buf)
{
    unsigned char  i = 0;

    while(i < sizeof(ipv4_addr))
    {
        buf[IP_DST_P + i] = buf[IP_SRC_P + i];
        buf[IP_SRC_P + i] = ipaddr[i];
        i++;
    }

    fill_ip_hdr_checksum(buf);
}

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45


unsigned  int checksum(unsigned char * buf, unsigned  int len,unsigned char  type)
{
    // type 0=ip 
    //      1=udp
    //      2=tcp
    unsigned long sum = 0;
    
    //if(type==0){
    //        // do not add anything
    //}
    if(type==1)
    {
        sum+=IP_PROTO_UDP_V; // protocol udp
        // the length here is the length of udp (data+header len)
        // =length given to this function - (IP.scr+IP.dst length)
        sum+=len-8; // = real tcp len
    }
    if(type==2)
    {
        sum+=IP_PROTO_TCP_V; 
        // the length here is the length of tcp (data+header len)
        // =length given to this function - (IP.scr+IP.dst length)
        sum+=len-8; // = real tcp len
    }
    // build the sum of 16bit words
    while(len >1)
    {
        sum += 0xFFFF & (*buf<<8|*(buf+1));
        buf+=2;
        len-=2;
    }
    // if there is a byte left then add it (padded with zero)
    if (len)
    {
        sum += (0xFF & *buf)<<8;
    }
    // now calculate the sum over the bytes in the sum
    // until the result is only 16bit long
    while (sum>>16)
    {
        sum = (sum & 0xFFFF)+(sum >> 16);
    }
    // build 1's complement:
    return( (unsigned  int) sum ^ 0xFFFF);
}

------------------------------------------------------------------------------------------------------

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25


// ******* ICMP *******
//回显应答
#define ICMP_TYPE_ECHOREPLY_V 0
//回显请求
#define ICMP_TYPE_ECHOREQUEST_V 8
//ICMP类型
#define ICMP_TYPE_P 0x22
//ICMP首部校验和
#define ICMP_CHECKSUM_P 0x24

void make_echo_reply_from_request(unsigned char * buf,unsigned  int len)
{
    make_eth(buf);
    make_ip(buf);

     //ICMP_DEBUG插入此处
    buf[ICMP_TYPE_P]=ICMP_TYPE_ECHOREPLY_V;   //回显应答
    // we changed only the icmp.type field from request(=8) to reply(=0).
    // we can therefore easily correct the checksum:
    if (buf[ICMP_CHECKSUM_P] > (0xff-0x08))
    {
        buf[ICMP_CHECKSUM_P+1]++;
    }
    buf[ICMP_CHECKSUM_P]+=0x08;
    //
    enc28j60PacketSend(len,buf);
}

8 ICMP实验调试

 C++ Code 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30


void make_echo_reply_from_request(unsigned char * buf,unsigned  int len)
{
        int i=0;
    make_eth(buf);
    make_ip(buf);
        #ifdef ICMP_DEBUG
        printf("ping命令发起者的IP地址 : \r\n");
      while(i    {
            //注意这里是IP_SRC_P,不是ARP包了,因为包的类型变了
            printf("%d",buf[IP_SRC_P+i]);/*这里错了,应该是IP_DST_P,why?看函数名,好了,看了串口的输出才看出来的*/
            if(i!=sizeof(ipv4_addr)-1)
                printf(".");
            else
                printf("\r\n");
            i++;
        }
        i=0;
        #endif
    buf[ICMP_TYPE_P]=ICMP_TYPE_ECHOREPLY_V;   //回送应答
    // we changed only the icmp.type field from request(=8) to reply(=0).
    // we can therefore easily correct the checksum:
    if (buf[ICMP_CHECKSUM_P] > (0xff-0x08))
    {
        buf[ICMP_CHECKSUM_P+1]++;
    }
    buf[ICMP_CHECKSUM_P]+=0x08;
    //
    enc28j60PacketSend(len,buf);
}

在程序的无线循环中,需要层层进行查询。其实就是各种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协议栈  IP  ICMP  STM32平台 引用地址:分析TCP/IP协议栈代码之IP & ICMP(STM32平台)

上一篇:分析TCP/IP协议栈代码之ARP(STM32平台)
下一篇:分析TCP/IP协议栈代码之TCP(STM32平台)

推荐阅读最新更新时间:2024-03-16 16:00

JPEG编码器IP核性能优化解决方案
6月19日,半导体IP供应商CAST公司宣布对其提供的JPEG编码器IP核进行功能及性能优化。   系统设计师现在有两个速率控制选项可以选择,用于调试JPEG压缩功能的特定应用程序:   ·有限缓冲,基于模块的速率控制可为缓冲和传输带宽最小化片上内存,产生高质量图像。   ·Motion JPEG面向视频速率控制可为Motion JPEG数据流最大化视频的质量,同时更有效地使用硬件资源。   “图像压缩对外行来说简单意味着“JPEG”,但这远非一个’万全之策’的技术 ”。CAST公司行销部副总裁Nikos Zervas说道:“特定的压缩算法及其内部的处理选项的选择可对质量,带宽,内存需求,性能和能量损耗产生巨大的差异。我们
[模拟电子]
欧胜选择SiliconGate为其提供电源管理IP
专用集成电路(ASIC)/系统级芯片(SoC)的电源管理知识产权(IP)专业供应商SILICONGATE LDA今日宣布:高性能混合信号半导体解决方案供应商欧胜微电子有限公司,已经选择SiliconGate为其提供高性能电源管理IP,双方签订了四年的合约。 经过对多家IP供应商以及他们现有的多种解决方案进行广泛评估之后,欧胜选择了SiliconGate的IP作为其自身高性能IP系列的补充,以在实现超高的性能的同时兼顾紧凑的芯片面积。 “我们选择SiliconGate是因其在高性能电源管理IP方面具有世界一流的知识和专长。”欧胜微电子电源管理IP总监Holger Haiplik表示: 欧胜身先力行,为消费电子市
[电源管理]
如何用FPGA构建IP监视摄像机的参考设计
目前的视频监视市场在发展过程中遇到了很多要解决的难题,包括从模拟到数字摄像机的过渡、转换到高清(HD)视频、应用宽动态范围(WDR)传感器,以及实现进行数据传输和控制的互联网协议(IP)链接等。针对这些问题,本文介绍了如何采用FPGA构建IP监视摄像机的参考设计,展示了怎样采用低成本AlteraCycloneIIIFPGA构建完整的系统。 引言 在视频监视市场领域,对更高质量视频、高分辨率以及灵活性和功能的需求促进了从模拟到数字摄像机的过渡。在定义上,高清(HD)视频必须是数字的,因此,采用HD标准也就意味着过渡到数字传感器。HD视频标准支持更高的帧速率和分辨率,需要H.264等新压缩方法,促使摄像机具有更强的
[安防电子]
Imagination发布首款以新的Furian GPU架构为基础的PowerVR Series8XT IP
2017年5月11日 ─Imagina TI on Technologies 发布第一款以其最新的PowerVR Furian架构为基础的GPU IP内核 ─ Series8XT GT8525。Furian专为推动新一代的消费性设备所设计,能以移动功耗的预算提供长时间的高解析度、沉浸式图形内容以及数据运算功能。双集簇(two-cluster)GT8525可提供同类领先的性能、功耗与面积,以及独特的特性,以协助客户设计出适用于高端智能手机与平板电脑、中端专用型VR与AR设备、以及中级到高级的车用信息娱乐与ADAS系统等产品的SoC。 Imagina TI on公司PowerVR产品及技术营销高级总监Chris Longstaff
[安防电子]
OPPO新IP 沈义人:与用户直接对话,变与不变中进化
这是4月10日OPPO Reno 系列手机发布会后,在媒体群访环节,面对笔者连续发问后,OPPO 副总裁沈义人快速给出的答案。 这次云集了国内主流科技、财经媒体的群访,本该是一场针对这位OPPO“少帅”有关战略、市场、品牌等严肃话题的采访。硬生生的被笔者一连串的问题变成了“娱乐八卦”专场。 笔者提问确实与现场的气氛格格不入,甚至有媒体人私下问我是不是要转娱乐记者了? 事实上,并不是笔者转向娱乐圈了。而是上述答案也是过去2个月网友对沈义人热议较多的 话题。更深层次背后折射出了OPPO 在新一轮历史转折时期,与外界沟通交流方式正在悄然发生变化。 数码达人沈义人,已成为OPPO新IP 沈义人火了!这一点连他自己都承
[手机便携]
OPPO新<font color='red'>IP</font> 沈义人:与用户直接对话,变与不变中进化
安捷伦公司推出业界第一款用于UMTS版本6、HSUPA和IP架构UMTS无线接入网的网络分析工具
此工具提供独特故障诊断和专家分析能力,支持UMTS版本6网络的快速部署和优化 (2007年6月1日,北京)―― 安捷伦科技公司(NYSE:A)日前推出业界第一款用于UMTS版本6网络的实时专家分析工具,使研发工程师、系统测试工程师和操作工程师能够为UMTS发展技术快速地诊断、部署和优化移动网络。 目前的3G UMTS网络正在不断发展,以提供增强的能力、可靠性和数据性能。移动网络运营商关注的焦点已不再是不断增加的下行链路数据速率,他们面临着新的挑战――在不影响现有服务质量的情况下,部署UMTS高速上行链路分组接入(HSUPA)和其他版本6的特性。 移动运营商还面临着更大的挑战:调整传输层,以满足不断发展的无线接入网日益增加的
[新品]
智原第三季度业绩扎心,IP收入却创新高
ASIC设计服务暨硅智财(IP)研发销售厂智原(3035)昨(2)日举办法人说明会,第三季每股净利为0.5元,较第二季衰退18%,惟硅智财(IP)收入写下10年来新高,毛利率也上升至52.5%,创下3年来新高。 智原第三季合并营收为12.69亿元,季减少16%,毛利率达到52.5%,较第二季增加5个百分点,税后净利(归属予母公司)为1.24 亿元,税后每股净利为0.50元,相较第二季的0.61元,衰退18%。 智原表示,第三季公司产品组合持续改善,硅智财(IP)收入达2.25亿,不仅较第二季大幅成长7%,更创下十年来新高,委托设计(NRE)方面,延续第二季往高值化产品发展的趋势,智原第三季认列的应用包括航空、5G网通、工控、 多媒
[半导体设计/制造]
IP高清狙击者:同轴高清闪亮登场
    就目前的整个全球安防监控市场而言,视频监控的高清化之路势不可挡,这也直接导致网络摄像机在不断地吞噬着原本属于模拟摄像机的市场份额,但截至目前为止,模拟摄像机在全球安防市场中依然占据着半数市场份额,笔者手头上的一份权威报告显示,在整个2013年,网络摄像机与模拟摄像机在销售数量上的比为2:8,说明模拟摄像机依然占据市场的主流应用。都说网络摄像机浩浩荡荡的发展会对模拟摄像机形成灭顶之灾,实际的情况绝非如此简单,那么是什么原因让模拟摄像机如今依然占据着安防视频监控的主流应用呢?   首当其冲的一个原因便是价格因素,同样来自该权威报告的数据显示,在2013年网络摄像机与模拟摄像机的平均单价比较中,二者的价格之比为8:3,此外模
[安防电子]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved