基于PLC1850平台的ICMP包请求与响应

一、以太网IP包报文格式

  IP包是连接在以太网首部(以太网目的MAC地址(6个字节)+以太网源MAC地址(6个字节)+帧类型(2个字节))之后。

  IP报文中各个字段分析如下:

  ①、版本:在IP报文中,版本占了4个bit位,用来表示该协议采用的是哪一个版本的IP,相同版本的IP才能进行通信。一般此处的值为4,表示IPv4。

  ②、头长度:指IP报文中头部的长度,占了4个bit位,一个数值单位表示4个字节(32个bit)。如果忽略可选项,此处的值为5,表示IP包头部为20个字节。

  ③、服务类型:指所需要服务的质量,占1个字节。

    优先(0~2比特位):该值越大,数据报相对于其他数据报的优先级越高。

    时延(3比特位):如果需要较低的时延,需将该位置1,否则置0。

    吞吐量(4比特位):如果需要较高的吞吐量,需要将该位置1,否则置0。

    可靠性(5比特位):如果需要较高的可靠性,需将该位置1,否则置0。

    保留(6,7比特位):未使用。

  ④、总长度:指IP数据报的总长度,占2个字节。最大为65535字节,单位:字节。

  ⑤、标识:在分片中使用,同一报文的所有分片具有相同的标识号,占2个字节,方便IP分片的重组。

  ⑥、标志:占3个bit。该字段是与IP分片有关的。只有两位是有效的,分别为MF和DF。MF标识后面是否还有分片,为1时,表示后面还有分片。DF标识是否能分片,为0表示可以分片。保留(0比特位)表示未使用;不分                                片(1比特位)指该数据报信息字段不能分片;还有分片(2比特位)指如果该位置1表示后面还有分片,如果为0,表示该数据包为最后一个分片或者数据报未分片。

  ⑦、段偏移:该字段是与IP分片后,相应的IP片在总的IP片的位置。该字段的单位是8字节。比如,一个长度为4000字节的IP报文,到达路由器。这是超过了链路层的MTU,需要进行分片,4000字节中,20字节为包头,                                      3980字节为数据,需要分成3个IP片(链路层MTU为1500),那么第一个分片的片偏移就是0,表示该分片在3980的第0位开始,第1479位结束。第二个IP片的片偏移为185(1480/8),表示该分片开始的位                                    置在原来IP的第1480位,结束在2959。第三个IP片的片偏移为370(2960/8),表示开始的时候是2960位,结束的时候在3979位。

  ⑧、生存时间(TTL):占1个字节。IP数据包每经过一个路由器,该值减1,如果该值减为0,那么该数据包将被丢弃。Windows系统该值默认为128。

  ⑨、协议:占1个字节。协议值如下表所示。

    

  ⑩、校验和:占2个字节。该值是对整个数据包的包头进行的校验。将整个IP报头部一个字节一个字节相加,最后结果将超过16位的数据取出,加到数据尾部。然后对结果进行取反。

  11、源IP地址:占4个字节。目的IP地址:占4个字节。

  12、可选项:占4个字节。

  13、数据:长度可变,要发送的数据部分内容(原始数据报被分片后的一个分片数据部分)。

二、ICMP报的请求与响应

  ICMP报文是放在IP报的数据部分,ICMP报格式如下:

  ①、类型:占1个字节。类型值有如下:

  ②、代码:占1个字节,指示不同的“子类型”。

  ③、校验和:占2个字节。为ICMP报文提供错误检测,它是ICMP报文从ICMP类型开始计算的16位反码和的密码。为了计算该校验和,校验和字段应为0。

  ④、数据:取决于报文的类型。一般情况下,在差错报告报文中,该字段包含不能被交付的原始IP数据报的一部分。

  ICMP请求:

  第一步:将LPC1850网口与电脑网口相连接,将电脑IP改成与板子IP在同一个网段,如:板子IP为192.168.1.190,则电脑IP可以改为192.168.1.2。

  主程序代码如下:

 1 #include "LPC18xx.h"
 2 #include "led.h"
 3 
 4 
 5 extern void taskEth (void);
 6 
 7 int main(void)
 8 {
 9     SystemInit();
10 
11     ledInit();
12     SysTick_Config(GetCoreClock() / 1000);
13 
14     taskEth();
15 
16     while (1);  
17 }
18 
19 void SysTick_Handler(void)
20 {
21     static int counter = 0;
22 
23     counter++;
24     if (counter >= 100)
25     {
26         counter = 0;
27         ledRolling();
28     }
29 }
 1 #include <stdlib.h>
 2 #include <lpc18xx.h>
 3 #include "lpc18xx_emac.h"
 4 #include "lpc18xx_debug.h"
 5 
 6 extern uint32_t ipatol(char * p_input);
 7 extern void ipInit(uint8_t * mac, uint32_t ip);
 8 extern uint32_t ipRcvMacFrame(uint8_t * block, uint32_t frameLen);
 9 
10 uint8_t gFlag = 0;
11 
12 uint8_t g_emacBuffer[2048];
13 
14 uint8_t g_ethMac[6];
15 
16 // EMAC接口接收到数据,通知应用层回调函数
17 void ethReadReadyCb()
18 {
19     gFlag = 1;
20 }
21 
22 void taskEth (void)
23 {    
24     uint32_t len;
25 
26     g_ethMac[0] = 0x11;
27     g_ethMac[1] = 0x1F;
28     g_ethMac[2] = 0xE0;
29     g_ethMac[3] = 0x12;
30     g_ethMac[4] = 0x1E;
31     g_ethMac[5] = 0x0F;
32 
33     debugComInit();
34     uartPrint("uart init\r\n");
35 
36     while (ethInit(ethReadReadyCb, g_ethMac) == 0);
37 
38     uartPrint("eth init complete\r\n");
39     //为以太网接口指定MAC地址和IP地址
40     ipInit(g_ethMac, 0xBE01A8C0);   // 192.168.1.190
41 
42     while (1)
43     {
44         if (!gFlag)
45         {
46             continue;
47         }
48 
49         len = ethRead(g_emacBuffer, 2048); 
50         if (len)
51         {
52             ipRcvMacFrame((uint8_t *)g_emacBuffer, len);
53         }
54 
55         gFlag = 0;
56     }
57 }

  IP代码如下:

  1 #include <stdint.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #include "lpc18xx_emac.h"
  5 #include "lpc18xx_debug.h"
  6 //#include "shell.h"
  7 
  8 #define MAC_TYPE_IP   0x0800  //ipÀàÐÍ
  9 #define MAC_TYPE_ARP  0x0806  //macÀàÐÍ
 10 
 11 #define ARP_REQ 0x0001      //ARPÇëÇó
 12 #define ARP_RSP 0x0002        //ARPÏìÓ¦
 13 
 14 #define ICMP_ECHO_REQUEST    8                   // message is an echo request
 15 #define ICMP_ECHO_REPLY      0                   // message is an echo reply
 16 
 17 #define PROT_ICMP            1                   // Internet Control Message Protocol
 18 #define PROT_TCP             6                   // Transmission Control Protocol
 19 #define PROT_UDP             17                  // User Datagram Protocol
 20 
 21 #define DONT_FRAGMENT       0x4000 //fragment
 22 #define MORE_FRAGMENT       0x2000
 23 #define FRAGMENT_OFFSET     0x1FFF
 24 
 25 
 26 uint8_t g_ethMacAddr[6];
 27 uint32_t g_ethIpAddr;
 28 
 29 uint32_t g_ipSndBuffer[64];
 30 
 31 uint16_t g_ipIdentifier = 0;
 32 
 33 // ½«×Ö´ÓÖ÷»úÐòתΪÍøÂçÐò
 34 uint16_t htons(uint16_t word)
 35 {
 36     return ((word >> 8) & 0x00FF) | ((word << 8) & 0xFF00);
 37 }
 38 
 39 // ½«×Ö´ÓÍøÂçÐòתΪÖ÷»úÐò
 40 uint16_t ntohs(uint16_t word)
 41 {
 42     return ((word >> 8) & 0x00FF) | ((word << 8) & 0xFF00);
 43 }
 44 
 45 
 46 uint16_t calcChecksum(uint16_t * buffer, uint32_t size)   
 47 {   
 48     uint32_t cksum;   
 49     
 50     cksum = 0;   
 51 
 52     while (size > 1)   
 53     {   
 54         cksum += *buffer++;   
 55         size -= sizeof(uint16_t);         
 56     }   
 57 
 58     if (size)   
 59     {   
 60         cksum += *(uint8_t*)buffer;         
 61     }   
 62 
 63     cksum = (cksum >> 16) + (cksum & 0xffff);   
 64     cksum += (cksum >>16);     
 65     
 66     return (uint16_t)(~cksum);     
 67 }
 68 
 69 // ·¢ËÍARPÏìÓ¦
 70 void arpSndRsp(uint32_t dstIp, uint8_t * mac)
 71 {
 72     uint8_t * block;
 73     //uint32_t blockLen;
 74 
 75     block = (uint8_t *)g_ipSndBuffer;
 76 
 77     memcpy(block, mac, 6);
 78 
 79     memcpy(block + 6, g_ethMacAddr, 6);
 80 
 81     // arp type
 82     *(uint16_t *)&block[12] = htons(MAC_TYPE_ARP);
 83 
 84     // --------- ARP ²ã
 85     
 86     // Hardway type : Ethernet
 87     block[14] = 0x00;
 88     block[15] = 0x01;
 89 
 90     // ip type
 91     *(uint16_t *)&block[16] = htons(MAC_TYPE_IP);
 92 
 93     // Hardway size
 94     block[18] = 0x06;
 95 
 96     // Protocal size
 97     block[19] = 0x04;
 98 
 99     // arp reply
100     *(uint16_t *)&block[20] = htons(ARP_RSP);
101 
102     // Sender MAC address
103     memcpy(block + 22, g_ethMacAddr, 6);
104 
105     // Sender IP address
106     *(uint32_t *)&block[28] = g_ethIpAddr;
107 
108     // Target MAC address
109     memcpy(block + 32, mac, 6);
110 
111     // Target IP address : 192.168.0.67
112     block[38] = (uint8_t)dstIp;
113     block[39] = (uint8_t)(dstIp >> 8);
114     block[40] = (uint8_t)(dstIp >> 16);
115     block[41] = (uint8_t)(dstIp >> 24);
116 
117     // 18¸öÌî³ä×Ö½Ú
118     memset(block + 42, 0, 18);
119 
120     ethWrite((uint8_t *)block, 60);
121 }
122 
123 void arpRcv(uint8_t * block, uint32_t frameLen)
124 {
125     uint32_t srcIp, dstIp;
126     uint16_t msgType;
127                
128     msgType = ntohs(*(uint16_t *)(block+6));   
129 
130     srcIp = (uint32_t)*(uint16_t *)(block + 14);
131     srcIp|= ((uint32_t)*(uint16_t *)(block + 16)) << 16;
132 
133     dstIp = (uint32_t)*(uint16_t *)(block + 24);
134     dstIp|= ((uint32_t)*(uint16_t *)(block + 26)) << 16;
135 
136     if (dstIp != g_ethIpAddr)
137     {
138         return;
139     }
140 
141     if (msgType == ARP_REQ)
142     {
143         arpSndRsp(srcIp, block + 8);
144     }
145 }
146 
147 // ²»¹Ü³É¹¦Óë·ñ,¶¼ÓÉIP²ãÀ´ÊÍ·ÅÊý¾Ý°ü¡£
148 void ipSnd(uint32_t dstIp, uint8_t * block, uint32_t len, uint8_t protoType, uint8_t * mac)
149 {
150     block-= 20;
151     len+= 20;
152     
153     // ------------ IP ²ã
154     
155     block[0] = 0x45;  // IP V4.  length 20(5*4)
156     
157     block[1] = 0x00;  // service
158     
159     *(uint16_t *)&block[2] = htons(len);
160     
161     *(uint16_t *)&block[4] = htons((uint16_t)g_ipIdentifier++); // identification
162     
163     *(uint16_t *)&block[6] = 0x0040; // flag and fragment
164 
165     block[8] = 128;  // TTL
166 
167     block[9] = protoType;
168     
169     *(uint16_t *)&block[10] = 0; // УÑéºÍÏÈÌîÉÏ0
170     
171     *(uint16_t *)&block[12] = (uint16_t)g_ethIpAddr;
172     *(uint16_t *)&block[14] = (uint16_t)(g_ethIpAddr >> 16);
173 
174     *(uint16_t *)&block[16] = (uint16_t)dstIp;
175     *(uint16_t *)&block[18] = (uint16_t)(dstIp >> 16);
176     
177     *(uint16_t *)&block[10] = calcChecksum((uint16_t *)block, 20);
178 
179     // ------------ MAC ²ã
180 
181     block-= 14;
182     len+= 14;
183     
184     memcpy(block, mac , 6);
185     
186     memcpy(block + 6, g_ethMacAddr, 6);
187 
188     *(uint16_t *)&block[12] = htons(MAC_TYPE_IP);
189 
190     if (len < 60)
191     {
192         // MACÖ¡Ì«¶Ì£¬²¹µ½×î¶Ì³¤¶È¡£
193         memset(block + len, 0, 60 - len);
194         len = 60;
195     }
196 
197     ethWrite((uint8_t *)block, len);
198 }
199 
200 // ICMPÊÕµ½ÇëÇó£¬ÐèÒª»ØÏìÓ¦¡£
201 void icmpRcvRequest(uint32_t srcIp, uint8_t * icmp, uint32_t len, uint8_t * mac)
202 {
203     uint8_t * block;
204 
205     block = (uint8_t *)g_ipSndBuffer;
206 
207     // Áô³ö 14(MAC)+20(IP)¸ö×Ö½Ú   
208     block+=(14+20);
209     
210     // ----------- ICMP ²ã
211         icmp[8]='R';
212         icmp[9]='e';
213         icmp[10]='c';
214         icmp[11]='e';
215         icmp[12]='i';
216         icmp[13]='v';
217         icmp[14]='e';
218         icmp[15]='d';
219         
220         icmp[16]=' ';
221         icmp[17]='I';
222         icmp[18]='C';
223         icmp[19]='M';
224         icmp[20]='P';
225         icmp[22]=' ';
226         icmp[22]='R';
227         icmp[23]='e';
228         icmp[24]='q';
229         icmp[25]='u';
230         icmp[26]='e';
231         icmp[27]='s';
232         icmp[28]='t';
233         icmp[29]='!';
234         
235     memcpy(block, icmp, len);
236     
237     block[0] = ICMP_ECHO_REPLY;
238     block[1] = 0;   // code
239     
240     *(uint16_t *)&block[2] = 0;  // УÑéºÍÏÈÌîÉÏ0
241     
242     *(uint16_t *)&block[2] = calcChecksum((uint16_t *)block, len);
243         uartPrint("The ICMP response!\r\n");
244     ipSnd(srcIp, (void *)block, len, PROT_ICMP, mac);
245 }
246 
247 // ½ÓÊÕµ½IP°üµÄ´¦Àí
248 void ipRcv(uint8_t * frame, uint32_t frameLen, uint8_t * mac)
249 {
250     uint16_t ipLength, flag,i;
251     uint32_t srcIp, dstIp;
252 
253     if (frameLen < 20)
254     {
255         return;
256     }
257 
258     if (calcChecksum((uint16_t *)frame, 20))
259     {
260         // УÑéºÍ²»ÕýÈ·
261         return;
262     }
263 
264     if (frame[0] != 0x45)
265     {
266         // IP VERSION ӦΪ4£¬³¤¶ÈӦΪ20£¨5¸öbit32£©×Ö½Ú¡£
267         return;
268     }
269 
270     // ignore Type Of Service
271     
272     ipLength = ntohs(*(uint16_t *)&frame[2]);
273     // ignore identification
274 
275     flag = ntohs(*(uint16_t *)&frame[6]);
276 
277     if (!(flag & DONT_FRAGMENT))
278     {
279         // IP¿ÉÒÔ±»·Ö°ü£¬µ«ÎÒÃÇÖ»´¦Àí²»·Ö°üµÄÇé¿ö¡£
280         
281         if (flag & MORE_FRAGMENT)
282         {
283             // ·Ç×îºóµÄÒ»°ü£¬¶ªÆú¡£
284             return;
285         }
286         
287         // ÊÇ×îºóÒ»°ü¡£
288         
289         if (flag & FRAGMENT_OFFSET)
290         {
291             // ÊÇ×îºóÒ»°ü£¬ÇÒÆ«ÒÆÁ¿²»Îª0£¬Ò²¶ªÆú¡£
292             return;
293         }
294         
295         // ×îºóÒ»°ü£¬ÇÒÆ«ÒÆÁ¿Îª0£¬ÊÇÕû°ü£¬´¦Àí£¡
296     }
297     
298     if (frameLen < ipLength)
299     {
300         return;
301     }
302     
303     // ignore fragment offset
304 
305     //ttl = (uint32_t)frame[8];
306 
307     //srcIp = (frame[12] | (frame[13]<< 8) | (frame[14] << 16) | (frame[15] << 24));
308     //dstIp = (frame[16] | (frame[17]<< 8) | (frame[18] << 16) | (frame[19] << 24));
309 
310     srcIp = *(uint16_t *)(frame + 12) | ((uint32_t)*(uint16_t *)(frame + 14) << 16);
311     dstIp = *(uint16_t *)(frame + 16) | ((uint32_t)*(uint16_t *)(frame + 18) << 16);
312 
313     if ((dstIp != g_ethIpAddr) && (dstIp != 0x0100007F) && (dstIp != 0xffffffff))
314     {
315         return;
316     }
317 
318     if (frame[9] != PROT_ICMP)
319     {
320         // ·ÇICMP°ü£¬Ôݲ»´¦Àí
321         return;
322     }
323         //ÊÕµ½ICMPÇëÇ󣬴òÓ¡³öICMP°ü
324     if (frame[20] == ICMP_ECHO_REQUEST)
325     {
326             uartPrint("ICMP Header:\r\n");
327             uartPrint("Type:%d\r\n",*(frame+20));
328             uartPrint("Code:%d\r\n",*(frame+21));
329             uartPrint("Checksum:0x%04x\r\n",ntohs(*(uint16_t *)(frame+22)));
330       uartPrint("Id:0x%04x\r\n",ntohs(*(uint16_t *)(frame+24)));
331       uartPrint("Sequence:%d\r\n",ntohs(*(uint16_t *)(frame+26)));
332       uartPrint("Data:\r\n");
333        for(i=0;i<ipLength-28;i++)
334       {
335          uartPrint("%c",frame[28+i]);
336       }
337       uartPrint("\r\n---------------------------------\r\n");
338       icmpRcvRequest(srcIp, frame + 20, ipLength - 20, mac);
339     }
340 }
341 
342 
343 // IP²ã½ÓÊÕMAC²ãÊý¾ÝÖ¡µÄº¯Êý
344 uint32_t ipRcvMacFrame(uint8_t * block, uint32_t frameLen)
345 {
346     //0xFFFF ¹ã²¥·½Ê½
347     if ( ((*(uint16_t *)block == 0xFFFF) && (*(uint16_t *)(block + 2) == 0xFFFF) && (*(uint16_t *)(block + 4) == 0xFFFF))
348        ||(memcmp(block, g_ethMacAddr, 6) == 0))
349     {
350         // ÊÇ·¢¸ø±¾»úµÄ¡£
351         switch (ntohs(*(uint16_t *)(block+12)))
352         {
353         case MAC_TYPE_ARP:
354             arpRcv(block + 14, frameLen -14);
355             break;
356         case MAC_TYPE_IP:
357             ipRcv(block + 14, frameLen - 14, block+6);
358             break;
359         default:
360             break;
361         }
362     }
363 
364     return 1;
365 }
366 
367 void ipInit(uint8_t * mac, uint32_t ip)
368 {
369     memcpy(g_ethMacAddr, mac, 6);
370     g_ethIpAddr = ip;
371 }

  将程序烧写到PLC1850板子上,将板子与电脑用网线,串口线连接。打开cmd,输入ping 192.168.1.190回车。串口将打印出电脑请求的ICMP报的信息。同时可使用wireshark软件查看相关信息。

 

转载于:https://www.cnblogs.com/chenfeifen/p/10655097.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值