基於PLC1850平臺的ICMP包請求與響應

1、以太網IP包報文格式shell

  IP包是鏈接在以太網首部(以太網目的MAC地址(6個字節)+以太網源MAC地址(6個字節)+幀類型(2個字節))以後。ide

  IP報文中各個字段分析以下:函數

  ①、版本:在IP報文中,版本佔了4個bit位,用來表示該協議採用的是哪個版本的IP,相同版本的IP才能進行通訊。通常此處的值爲4,表示IPv4。ui

  ②、頭長度:指IP報文中頭部的長度,佔了4個bit位,一個數值單位表示4個字節(32個bit)。若是忽略可選項,此處的值爲5,表示IP包頭部爲20個字節。spa

  ③、服務類型:指所須要服務的質量,佔1個字節。debug

    優先(0~2比特位):該值越大,數據報相對於其餘數據報的優先級越高。3d

    時延(3比特位):若是須要較低的時延,需將該位置1,不然置0。code

    吞吐量(4比特位):若是須要較高的吞吐量,須要將該位置1,不然置0。blog

    可靠性(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位的數據取出,加到數據尾部。而後對結果進行取反。

  十一、源IP地址:佔4個字節。目的IP地址:佔4個字節。

  十二、可選項:佔4個字節。

  1三、數據:長度可變,要發送的數據部份內容(原始數據報被分片後的一個分片數據部分)。

2、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軟件查看相關信息。

相關文章
相關標籤/搜索