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