搜索
bottom↓
回复: 32

AVRNET 学习笔记 IP ICMP部分

[复制链接]

出0入0汤圆

发表于 2013-2-13 22:51:26 | 显示全部楼层 |阅读模式
本帖最后由 xukai871105 于 2013-2-13 22:53 编辑

1.前言
嵌入式以太网开发是一个很有挑战性的工作。通过几个月的学习,我个人觉得大致有两条途径。第一条途径,先通过高级语言熟悉socket编程,例如C#或C++,对bind,listen,connect,accept等函数熟悉之后,应用 lwIP。第二种途径,通过分析嵌入式以太网代码,结合TCPIP协议栈规范逐步实践代码。第一种途径效率高,开发周期短,编写出来的代码性能稳定,第二种途径花的时间长,开发出来的代码功能不完善,但是由于紧紧结合TCPIP规范,可以了解的内容较多,适合学习。本文通过分析和修改AVRNET源码,逐步实现TCPIP协议栈的各个子部分,包括ETHERNET部分,ARP部分,IP部分,ICMP部分,UDP部分,TCP部分和HTTP部分。
        本文将实现IP部分和ICMP部分。
1.2 相关资料
ENC28J60学习笔记链接
http://www.amobbs.com/thread-5519381-1-1.html
AVRNET学习笔记 ETHERNET和ARP部分链接
http://www.amobbs.com/thread-5519452-1-1.html
AVRNET项目(国外)
http://www.avrportal.com/?page=avrnet
AVR webserver项目(国外)
http://www.tuxgraphics.org/electronics/200611/article06111.shtml#0lfindex0
2.IP部分实现
        IP层是TCP和UDP实现的基础。IP首部紧跟以太网首部,长度为20字节。IP首部具有最基本的两个任务,第一,定义IP包的具体协议类型,例如ICMP,TCP或UDP等;第二,定义IP报文从哪个IP地址来和到哪个IP地址去。但是需要强调,在同一个子网中即同一个物理网络中,IP报文中的目标IP地址和以太网首部中的目标MAC地址是对应的,若不在同一个物理网路中,目标IP地址和目标MAC地址不同,目标MAC地址被路由器的MAC地址替代,意味着通过路由器转发报文。在IP首部中还包括很多其他内容,需要注意的是IP标识符,该标识符主要用于区分IP报文,最简单的算法即每发送一个IP报文后IP标识符累加。具体通过以下代码实现IP首部的填充。
2.1 IP首部填充
  1. // IP首部总长度
  2. #define IP_HEADER_LEN       20
  3. // 协议类型
  4. // ICMP协议
  5. #define IP_PROTO_ICMP_V     0x01
  6. // TCP协议
  7. #define IP_PROTO_TCP_V      0x06
  8. // UDP协议
  9. #define IP_PROTO_UDP_V      0x11
  10. // IPV4版本
  11. #define IP_V4_V             0x40
  12. #define IP_HEADER_LENGTH_V  0x05

  13. // IP版本号位置 以太网首部2+6+6
  14. #define IP_P                0x0E
  15. // 首部长度
  16. #define IP_HEADER_VER_LEN_P 0x0E
  17. // 服务类型
  18. #define IP_TOS_P            0x0F
  19. // IP总长度
  20. #define IP_TOTLEN_H_P       0x10
  21. #define IP_TOTLEN_L_P       0x11
  22. // IP标识
  23. #define IP_ID_H_P           0x12
  24. #define IP_ID_L_P           0x13
  25. //
  26. #define IP_FLAGS_H_P        0x14
  27. #define IP_FLAGS_L_P        0x15
  28. // TTL生存时间
  29. #define IP_TTL_P            0x16
  30. // IP协议类型 例如ICMP TCP UDP
  31. #define IP_PROTO_P          0x17
  32. // 首部校验和
  33. #define IP_CHECKSUM_H_P     0x18
  34. #define IP_CHECKSUM_L_P     0x19
  35. // 源IP地址
  36. #define IP_SRC_IP_P         0x1A
  37. // 目标IP地址
  38. #define IP_DST_IP_P         0x1E
  39. void ip_generate_header ( BYTE *rxtx_buffer, WORD_BYTES total_length, BYTE protocol, BYTE *dest_ip )
  40. {
  41.   BYTE i;
  42.   // 校验结果
  43.   WORD_BYTES ck;
  44.   
  45.   // 版本号和首都长度
  46.   rxtx_buffer[ IP_P ] = IP_V4_V | IP_HEADER_LENGTH_V;

  47.   // 服务类型
  48.   rxtx_buffer[ IP_TOS_P ] = 0x00;

  49.   // 总长度
  50.   rxtx_buffer [ IP_TOTLEN_H_P ] = total_length.byte.high;
  51.   rxtx_buffer [ IP_TOTLEN_L_P ] = total_length.byte.low;
  52.   
  53.   // IP标识
  54.   rxtx_buffer [ IP_ID_H_P ] = ip_identfier >> 8;
  55.   rxtx_buffer [ IP_ID_H_P ] = ip_identfier & 0x00ff;
  56.   // 累加
  57.   ip_identfier++;
  58.   
  59.   // 标志和分片偏移
  60.   rxtx_buffer [ IP_FLAGS_H_P ] = 0x00;
  61.   rxtx_buffer [ IP_FLAGS_L_P ] = 0x00;
  62.   
  63.   // 生存时间
  64.   rxtx_buffer [ IP_TTL_P ] = 128;
  65.   
  66.   // set ip packettype to tcp/udp/icmp...
  67.   rxtx_buffer [ IP_PROTO_P ] = protocol;
  68.   
  69.   // 设定目标地址和源地址
  70.   for ( i = 0; i < 4; i++ )
  71.   {
  72.     rxtx_buffer[ IP_DST_IP_P + i ] = dest_ip;
  73.     rxtx_buffer[ IP_SRC_IP_P + i ] = avr_ip.byte[ i ];
  74.   }
  75.   
  76.   // 校验结果
  77.   rxtx_buffer[ IP_CHECKSUM_H_P ] = 0;
  78.   rxtx_buffer[ IP_CHECKSUM_L_P ] = 0;
  79.   ck.word = software_checksum ( &rxtx_buffer[ IP_P ], sizeof(IP_HEADER), 0 );
  80.   rxtx_buffer[ IP_CHECKSUM_H_P ] = ck.byte.high;
  81.   rxtx_buffer[ IP_CHECKSUM_L_P ] = ck.byte.low;
  82. }
复制代码
2.2 IP报文查询
IP报文查询功能对应于ARP报文查询功能,通过以太网首部中的最后2个字节判断该报文是否为IP报文;如果是IP报文则继续和本机IP地址相比较。如果两步检查均通过则认为是合法的IP报文,当然这其中舍弃了IP版本号和首部校验和的检查,虽然存在某些隐患但并不妨碍实现基本功能。
  1. BYTE ip_packet_is_ip ( BYTE *rxtx_buffer )
  2. {
  3.   unsigned char i;
  4.   
  5.   // 检查该报文是否为IP报文
  6.   if ( rxtx_buffer[ ETH_TYPE_H_P ] != ETH_TYPE_IP_H_V || rxtx_buffer[ ETH_TYPE_L_P ] != ETH_TYPE_IP_L_V)
  7.     return 0;
  8.   
  9.   // 检查该报文的IP地址是否为本机IP地址,逐个检查
  10.   for ( i=0; i<sizeof(IP_ADDR); i++ )
  11.   {
  12.     if ( rxtx_buffer[ IP_DST_IP_P + i ] != avr_ip.byte )
  13.       return 0;
  14.   }
  15.   
  16.   // 若该报文为IP报文,且目标IP地址为本机地址,返回1
  17.   return 1;
  18. }
复制代码
3.ICMP部分实现
        虽然ICMP具有很多的子协议,但是其中最著名的要数ping程序,即ICMP回显请求和应答报文。通过使用ping命令来判断报文是否可以到达目标地址。ICMP的实现是一个逐步遵守规则的过程,即向固定的字节填充数据。
  1. // 回显应答
  2. #define ICMP_TYPE_ECHOREPLY_V   0
  3. // 回显请求
  4. #define ICMP_TYPE_ECHOREQUEST_V 8
  5. // ICMP首部长度
  6. #define ICMP_PACKET_LEN         40

  7. // ICMP类型
  8. #define ICMP_TYPE_P             0x22
  9. // ICMP代码
  10. #define ICMP_CODE_P             0x23
  11. // ICMP首部校验和
  12. #define ICMP_CHECKSUM_H_P       0x24
  13. #define ICMP_CHECKSUM_L_P       0x25
  14. // ICMP标识符
  15. #define ICMP_IDENTIFIER_H_P     0x26
  16. #define ICMP_IDENTIFIER_L_P     0x27
  17. // ICMP序号
  18. #define ICMP_SEQUENCE_H_P       0x28
  19. #define ICMP_SEQUENCE_L_P       0x29
  20. #define ICMP_DATA_P             0x2A
复制代码
3.1 ICMP首部填充
ICMP首部填充需要根据协议类型填充不同的内容,对于回显请求而言只需在ICMP协议类型部分填充0即可,当然ICMP部分也包括ICMP首部校验和。
  1. void icmp_generate_packet ( BYTE *rxtx_buffer ,BYTE type)
  2. {
  3.   BYTE i;
  4.   WORD_BYTES ck;
  5.   
  6.   // ICMP回显请求
  7.   if( type == ICMP_TYPE_ECHOREQUEST_V )
  8.   {
  9.     rxtx_buffer[ ICMP_TYPE_P ] == ICMP_TYPE_ECHOREQUEST_V;
  10.     rxtx_buffer[ ICMP_CODE_P ] = 0;
  11.     rxtx_buffer[ ICMP_IDENTIFIER_H_P ] = icmp_id;
  12.     rxtx_buffer[ ICMP_IDENTIFIER_L_P ] = 0;
  13.     rxtx_buffer[ ICMP_SEQUENCE_H_P ] = icmp_seq;
  14.     rxtx_buffer[ ICMP_SEQUENCE_L_P ] = 0;
  15.     icmp_id++;
  16.     icmp_seq++;
  17.     for ( i=0; i<ICMP_MAX_DATA; i++ )
  18.     {
  19.       rxtx_buffer[ ICMP_DATA_P + i ] = 'A' + i;
  20.     }
  21.   }
  22.   // ICMP回显
  23.   if(type == ICMP_TYPE_ECHOREPLY_V)
  24.   {
  25.     rxtx_buffer[ ICMP_TYPE_P ] = ICMP_TYPE_ECHOREPLY_V;
  26.   }
  27.   
  28.   // ICMP首部校验和
  29.   rxtx_buffer[ ICMP_CHECKSUM_H_P ] = 0;
  30.   rxtx_buffer[ ICMP_CHECKSUM_L_P ] = 0;
  31.   ck.word = software_checksum ( &rxtx_buffer[ ICMP_TYPE_P ], sizeof(ICMP_PACKET), 0 );
  32.   rxtx_buffer[ ICMP_CHECKSUM_H_P ] = ck.byte.high;
  33.   rxtx_buffer[ ICMP_CHECKSUM_L_P ] = ck.byte.low;
  34. }
复制代码
3.2 ICMP回显应答
        ICMP回显应答需要做好两步,第一步检查IP首部中的协议类型是否为ICMP报文;第二,检查ICMP首部中的ICMP类型是否为ICMP请求,如果是则生成ICMP回显应答并通过以太网驱动芯片发送。为了便于调试,在接收到ICMP回显请求时通过串口输出发起方的IP地址,ping命令发起方的IP地址存在于IP首部中的源IP地址部分。
  1. BYTE icmp_send_reply ( BYTE *rxtx_buffer, BYTE *dest_mac, BYTE *dest_ip )
  2. {
  3.   
  4.   // IP首部中为ICMP协议类型
  5.   if ( rxtx_buffer [ IP_PROTO_P ] != IP_PROTO_ICMP_V )
  6.     return 0;
  7.   
  8.   // 是否为ICMP回显请求
  9.   if ( rxtx_buffer [ ICMP_TYPE_P ] != ICMP_TYPE_ECHOREQUEST_V )
  10. return 0;

  11. #ifdef ICMP_DEBUG
  12.   printf("ICMP Request!\n");
  13.   printf("Ping from:%d.%d.%d.%d\n",\
  14.             rxtx_buffer[IP_SRC_IP_P+0],rxtx_buffer[IP_SRC_IP_P+1],\
  15.             rxtx_buffer[IP_SRC_IP_P+2],rxtx_buffer[IP_SRC_IP_P+3]);

  16. #endif
  17.   // 生成以太网首部
  18.   eth_generate_header ( rxtx_buffer, (WORD_BYTES){ETH_TYPE_IP_V}, dest_mac );
  19.   
  20.   // 生成IP首部
  21.   ip_generate_header ( rxtx_buffer, (WORD_BYTES){(rxtx_buffer[IP_TOTLEN_H_P]<<8)|rxtx_buffer[IP_TOTLEN_L_P]}, IP_PROTO_ICMP_V, dest_ip );

  22.   // 生成ICMP首部
  23.   icmp_generate_packet ( rxtx_buffer ,(BYTE)ICMP_TYPE_ECHOREPLY_V);

  24.   // 发送报文
  25.   enc28j60_packet_send ( rxtx_buffer, sizeof(ETH_HEADER) + sizeof(IP_HEADER) + sizeof(ICMP_PACKET) );
  26.   return 1;
  27. }
复制代码
4.实例
        通过ping命令可以测试报文是否可以到达目标主机。例如发送ping 192.168.1.105。
在程序的无线循环中,需要层层进行查询。
1.查询以太网中是否有数据,若无数据则返回。
2.保存源MAC地址,待返回时使用。
3.查询是否为ARP报文并返回ARP报文
4.保存源IP地址,待返回时使用。
6.查询是否为IP报文,若非IP报文返回。
5.查询是否为ICMP报文并返回ICMP回显应答。
  1. /* 获得新的IP报文 */
  2.   plen = enc28j60_packet_receive( (BYTE*)&rxtx_buffer, MAX_RXTX_BUFFER );
  3.   if(plen==0) return;

  4.   /* 保存客服端的MAC地址 */
  5.   memcpy ( (BYTE*)&client_mac, &rxtx_buffer[ ETH_SRC_MAC_P ], sizeof(MAC_ADDR) );
  6.   /* 检查该报文是不是ARP报文 */
  7.   if ( arp_packet_is_arp( rxtx_buffer, (WORD_BYTES){ARP_OPCODE_REQUEST_V} ) )
  8.   {
  9.     /* 向客户端返回ARP报文 */
  10.     arp_send_reply ( (BYTE*)&rxtx_buffer, (BYTE*)&client_mac );
  11.     return;
  12.   }

  13.   /* 保存客服端的IP地址 */
  14.   memcpy ( (BYTE*)&client_ip, &rxtx_buffer[ IP_SRC_IP_P ], sizeof(IP_ADDR) );  
  15.   /* 检查该报文是否为IP报文 */
  16.   if ( ip_packet_is_ip ( (BYTE*)&rxtx_buffer ) == 0 )
  17.   {
  18.     return;
  19.   }
  20.   
  21.   /* 如果是ICMP报文 向发起方返回数据 */
  22.   if ( icmp_send_reply ( (BYTE*)&rxtx_buffer, (BYTE*)&client_mac, (BYTE*)&client_ip ) )
  23.   {
  24.     return;
  25.   }
复制代码
实验结果实例:



PING命令使用




仿真输出结果


工程文件

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2013-2-14 21:23:35 | 显示全部楼层
不顶对不起自己。

出0入0汤圆

 楼主| 发表于 2013-2-14 21:59:56 | 显示全部楼层
xslff 发表于 2013-2-14 21:23
不顶对不起自己。

太感动了,等了一天终于有人回复了!
再发一个UDP的,呵呵,TCP,HTTP还会远吗!

出0入0汤圆

发表于 2013-2-15 00:05:22 | 显示全部楼层
感动的应该是我们这些通过您的资料学到东西的人,您太无私了,这么珍贵的东西花钱都不好找啊,您却免费的施舍给了每一个人,佩服。

出0入0汤圆

发表于 2013-2-15 00:15:23 | 显示全部楼层
谢谢楼主!!!!!!!!

出0入0汤圆

发表于 2013-2-15 02:35:43 来自手机 | 显示全部楼层
关注,lz继续。谢!

出0入0汤圆

 楼主| 发表于 2013-2-15 10:33:30 | 显示全部楼层
pinpang 发表于 2013-2-15 02:35
关注,lz继续。谢!

正在努力中,接下来要写TCP了!
说句实话,这的很复杂!

出0入0汤圆

发表于 2013-2-17 09:54:13 | 显示全部楼层
好贴啊  没白来一次  

出0入0汤圆

发表于 2013-2-17 11:05:43 | 显示全部楼层
不错啊。。学习了。。

出0入0汤圆

发表于 2013-2-17 15:47:03 | 显示全部楼层
向楼主学习中,最近也在搞Y以太网 希望多指教~~~

出0入0汤圆

 楼主| 发表于 2013-2-17 18:49:35 | 显示全部楼层
honghu_99 发表于 2013-2-17 15:47
向楼主学习中,最近也在搞Y以太网 希望多指教~~~

不能说向我学习,我也是借鉴他人的代码,应该说一起学习!

出0入0汤圆

发表于 2013-2-25 12:00:20 | 显示全部楼层
最近也在看楼主推荐那个嵌入式网络编程的书,只是看的前几章,后面还没有来得及看......初步打算跟着书的节奏////
话说用STM32F107+LWIP,跑一个嵌入式系统,直接使用socket编程...但嵌入式网络编程对理论知识要求较高一些,MAC/PHY/。。。。。谢谢楼主分享

出0入0汤圆

 楼主| 发表于 2013-2-27 12:54:01 | 显示全部楼层
fenglove 发表于 2013-2-25 12:00
最近也在看楼主推荐那个嵌入式网络编程的书,只是看的前几章,后面还没有来得及看......初步打算跟着书的节 ...

这些嵌入式网络编程可以说是一通百通!需要耐心搞懂那些基础知识!

国内有一本lwIP的图书,但是书中的例子非常的少!

出0入0汤圆

发表于 2013-2-27 17:01:20 | 显示全部楼层
您好!你说的是 “嵌入式网络那些事:LwIP协议深度剖析与实战演练 ”那本书吧,听你说过之后在卓越上搜索到的,你看着怎么样啊?如果觉得好的话,我也打算买一本回来看看,

初步打算 把嵌入式Internet  TCP/IP基础、实现及应用 那本书上的历程在STM32F107上面跑一遍,这边107的硬件环境已经使用的比较多,算是比较成熟了吧,不知道楼主怎么看啊?望多多指教!

出0入0汤圆

发表于 2013-2-27 18:38:13 | 显示全部楼层
学习了 这个很好

出0入0汤圆

 楼主| 发表于 2013-2-27 19:31:07 | 显示全部楼层
fenglove 发表于 2013-2-27 17:01
您好!你说的是 “嵌入式网络那些事:LwIP协议深度剖析与实战演练 ”那本书吧,听你说过之后在卓越上搜索到 ...

非常同意,我也准备把书上的代码实践一下!
至于LwIP那本书,书上的例子比较少,如果想深入研究协议实现的话,可以入手!

出0入0汤圆

发表于 2013-2-27 20:42:18 | 显示全部楼层
真的是高手!

出0入0汤圆

发表于 2013-3-1 20:56:12 | 显示全部楼层
xukai871105 发表于 2013-2-27 19:31
非常同意,我也准备把书上的代码实践一下!
至于LwIP那本书,书上的例子比较少,如果想深入研究协议实现 ...

好的,谢谢,等把手头这个项目搞完,就去做,现在是F107上面跑一个小的系统 +LWIP 网络部分直接使用的 SOCKT API接口,只是会用,对细节并不了解,很感谢你的回复~

出0入0汤圆

发表于 2013-3-11 13:11:40 | 显示全部楼层
楼主好人
对比着楼主推荐的书看了,收获很大
感谢楼主

出0入0汤圆

发表于 2013-5-4 14:33:09 | 显示全部楼层
写的很好,非常感谢!.

出70入0汤圆

发表于 2013-5-4 17:25:43 | 显示全部楼层
这个必须顶!mark!

出0入0汤圆

 楼主| 发表于 2013-5-4 22:51:31 | 显示全部楼层
绿茶山人 发表于 2013-5-4 17:25
这个必须顶!mark!

我会继续努力的!

出110入109汤圆

发表于 2013-5-4 23:15:06 | 显示全部楼层
谢谢楼主图文代码并茂的分享
坛内Rt-thread小组用Lwip作出产品来了的,可以关注下

出0入0汤圆

 楼主| 发表于 2013-5-7 09:29:56 | 显示全部楼层
reflecter 发表于 2013-5-4 23:15
谢谢楼主图文代码并茂的分享
坛内Rt-thread小组用Lwip作出产品来了的,可以关注下 ...

请问哪里有链接,看看,学习一下!

写这个文档的主要精神是学习TCP IP协议栈,并不是拿这个来实际使用!
实际使用还是lwIP和uIP这样的协议栈比较好!

出110入109汤圆

发表于 2013-5-7 10:08:14 | 显示全部楼层
xukai871105 发表于 2013-5-7 09:29
请问哪里有链接,看看,学习一下!

写这个文档的主要精神是学习TCP IP协议栈,并不是拿这个来实际使用! ...


http://www.amobbs.com/forum-3066-1.html
http://www.rt-thread.org/

出0入0汤圆

发表于 2013-8-14 14:50:56 | 显示全部楼层
看得出楼主是个栋梁之才!

出0入0汤圆

 楼主| 发表于 2013-8-14 16:20:29 | 显示全部楼层
wolyond 发表于 2013-8-14 14:50
看得出楼主是个栋梁之才!

感谢你的回复,我会继续努力的!

出0入0汤圆

发表于 2013-10-12 20:03:24 | 显示全部楼层
先收藏了,以后学习……

出0入0汤圆

发表于 2014-1-1 23:06:46 | 显示全部楼层
mark,,,,,,

出0入0汤圆

发表于 2014-1-10 16:28:07 | 显示全部楼层
MARK,学习中,谢谢分享

出0入0汤圆

 楼主| 发表于 2014-1-11 21:50:47 | 显示全部楼层
DouglasXie 发表于 2014-1-10 16:28
MARK,学习中,谢谢分享

你把我的帖子都顶了一遍啊!

出0入0汤圆

发表于 2014-1-13 16:54:45 | 显示全部楼层
xukai871105 发表于 2014-1-11 21:50
你把我的帖子都顶了一遍啊!

呵呵,因为你写的很详细,对我这样的菜鸟来说很有帮助,必须顶

出0入0汤圆

发表于 2014-11-7 17:09:44 | 显示全部楼层
好帖,学习了
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-19 12:53

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表