基于PLC1850平台的ARP包请求与响应
Posted chenfeifen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于PLC1850平台的ARP包请求与响应相关的知识,希望对你有一定的参考价值。
一、以太网ARP报文格式
①、以太网目的地址:占6个字节(接收方的MAC地址,不清楚时发广播地址:FF-FF-FF-FF-FF-FF)
②、以太网源地址:占6个字节(发送方的MAC地址)
③、帧类型:占2个字节(IPv4: 0x0800,ARP:0x0806,PPPoE:0x8864,802.1Q tag: 0x8100,IPV6: 0x86,DDMPLS Label:0x8847)
④、硬件类型:占2个字节(以太网的值为1即:0x0001)
⑤、协议类型:占2个字节(IPv4: 0x0800,ARP:0x0806,PPPoE:0x8864,802.1Q tag: 0x8100,IPV6: 0x86,DDMPLS Label:0x8847)
⑥、硬件地址长度:占1个字节(0x06)
⑦、协议地址长度:占1个字节(0x04)
⑧、操作类型:占2个字节(ARP请求为0x0001,ARP响应为0x0002,RARP请求为0x0003,RARP响应为0x0004)
⑨、发送方硬件地址:占6个字节(发送方的MAC地址)
⑩、发送方IP地址:占4个字节(发送方的IPv4地址)、目标硬件地址:占6个字节(接收方的MAC地址)、目标IP地址:占4个字节(接收方的IPv4地址)
二、实现ARP请求与响应程序
主程序:
1 #include "LPC18xx.h" 2 #include "led.h" 3 4 extern void taskEth (void); 5 6 int main(void) 7 { 8 SystemInit(); 9 10 ledInit(); 11 SysTick_Config(GetCoreClock() / 1000); 12 13 taskEth(); 14 15 while (1); 16 } 17 18 void SysTick_Handler(void) 19 { 20 static int counter = 0; 21 22 counter++; 23 if (counter >= 100) 24 { 25 counter = 0; 26 //ledRolling(); 27 } 28 }
taskEth()函数程序:
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 extern void arpSndRsp1(uint32_t dstIp,uint32_t resIp, uint8_t *f_mac,uint8_t *mac); 10 11 uint8_t gFlag; 12 13 uint8_t g_emacBuffer[2048]; 14 15 uint8_t g_ethMac[6]; 16 17 uint8_t F_ethMac[6]; 18 19 // EMAC接口接收到的数据,通知应用层回调函数 20 void ethReadReadyCb() 21 { 22 gFlag = 1; 23 } 24 25 void taskEth (void) 26 { 27 uint32_t len; 28 29 // 板子的MAK地址 30 g_ethMac[0] = 0x11; 31 g_ethMac[1] = 0x1F; 32 g_ethMac[2] = 0xE0; 33 g_ethMac[3] = 0x12; 34 g_ethMac[4] = 0x1E; 35 g_ethMac[5] = 0x0F; 36 37 //广播地址 38 F_ethMac[0]=0xff; 39 F_ethMac[1]=0xff; 40 F_ethMac[2]=0xff; 41 F_ethMac[3]=0xff; 42 F_ethMac[4]=0xff; 43 F_ethMac[5]=0xff; 44 //串口初始化 45 debugComInit(); 46 uartPrint("uart init\\r\\n"); 47 48 //以太网初始化 49 while (ethInit(ethReadReadyCb, g_ethMac) == 0); 50 51 uartPrint("eth init complete\\r\\n"); 52 // 为以太网接口指定MAC地址和IP地址 53 ipInit(g_ethMac, 0xBE01A8C0); // 192.168.1.190 54 //发送ARP请求函数 55 arpSndRsp1(0x0201A8C0,0xBE01A8C0,F_ethMac,g_ethMac); 56 while (1) 57 { 58 if (!gFlag) 59 { 60 continue; 61 } 62 //读取是否接收到报文 63 len = ethRead(g_emacBuffer, 2048); 64 65 if(len) 66 { 67 ipRcvMacFrame((uint8_t *)g_emacBuffer, len); //接收报文 68 } 69 gFlag=0; 70 } 71 }
arpSndRsp1()、ethRead()和ipRcvMacFrame()函数程序如下:
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 uint8_t PLC_ethMacAddr[6]; 26 uint8_t F_ethMacAddr[6]; 27 28 uint8_t g_ethMacAddr[6]; 29 uint32_t g_ethIpAddr; 30 31 uint32_t g_ipSndBuffer[64]; 32 33 uint16_t g_ipIdentifier = 0; 34 35 //将字从主机序转为网络序 36 uint16_t htons(uint16_t word) 37 { 38 return ((word >> 8) & 0x00FF) | ((word << 8) & 0xFF00); 39 } 40 41 //将字从网络序转为主机序 42 uint16_t ntohs(uint16_t word) 43 { 44 return ((word >> 8) & 0x00FF) | ((word << 8) & 0xFF00); 45 } 46 47 48 uint16_t calcChecksum(uint16_t * buffer, uint32_t size) 49 { 50 uint32_t cksum; 51 52 cksum = 0; 53 54 while (size > 1) 55 { 56 cksum += *buffer++; 57 size -= sizeof(uint16_t); 58 } 59 60 if (size) 61 { 62 cksum += *(uint8_t*)buffer; 63 } 64 65 cksum = (cksum >> 16) + (cksum & 0xffff); 66 cksum += (cksum >>16); 67 68 return (uint16_t)(~cksum); 69 } 70 //发送ARP请求 71 void arpSndRsp1(uint32_t dstIp,uint32_t resIp, uint8_t *f_mac,uint8_t *mac) 72 { 73 uint8_t * block; 74 //uint32_t blockLen; 75 76 block = (uint8_t *)g_ipSndBuffer;//64 77 78 memcpy(block, mac, 6);//以太网目的广播地址 79 80 memcpy(block + 6, mac, 6);//以太网的源地址,也就是板子的MAC地址 81 82 // arp type 83 *(uint16_t *)&block[12] = htons(MAC_TYPE_ARP);//mac类型 84 85 // --------- ARP 层 86 87 // Hardway type : Ethernet 88 block[14] = 0x00; 89 block[15] = 0x01; 90 91 // ip type 92 *(uint16_t *)&block[16] = htons(MAC_TYPE_IP);//IP类型 93 94 // Hardway size 95 block[18] = 0x06;//硬件地址长度 96 97 // Protocal size 98 block[19] = 0x04;//协议地址长度 99 100 // arp reply 101 *(uint16_t *)&block[20] = htons(ARP_REQ);//ARPARP请求 102 103 // Sender MAC address 104 memcpy(block + 22, mac, 6);//发送者的Mac地址 105 106 memcpy(PLC_ethMacAddr, mac, 6);//复制发送者的mac地址107 108 // Sender IP address 109 *(uint32_t *)&block[28] = resIp;//发送者IP地址110 111 // Target MAC address 112 memcpy(block + 32, f_mac, 6); 113 114 memcpy(F_ethMacAddr, f_mac, 6);//复制目的广播地址115 116 // Target IP address : 192.168.0.67 117 block[38] = (uint8_t)dstIp; 118 block[39] = (uint8_t)(dstIp >> 8); 119 block[40] = (uint8_t)(dstIp >> 16); 120 block[41] = (uint8_t)(dstIp >> 24); 121 122 // 18填充 123 memset(block + 42, 0, 18); 124 125 ethWrite((uint8_t *)block, 60); 126 uartPrint("sended ARP\\r\\n"); 127 } 128 //发送ARP响应 129 void arpSndRsp(uint32_t dstIp, uint8_t * mac) 130 { 131 uint8_t * block; 132 //uint32_t blockLen; 133 134 block = (uint8_t *)g_ipSndBuffer;//64 135 136 memcpy(block, mac, 6); 137 138 memcpy(block + 6, g_ethMacAddr, 6); 139 140 // arp type 141 *(uint16_t *)&block[12] = htons(MAC_TYPE_ARP); 142 143 // --------- ARP 层 144 145 // Hardway type : Ethernet 146 block[14] = 0x00; 147 block[15] = 0x01; 148 149 // ip type 150 *(uint16_t *)&block[16] = htons(MAC_TYPE_IP); 151 152 // Hardway size 153 block[18] = 0x06; 154 155 // Protocal size 156 block[19] = 0x04; 157 158 // arp reply 159 *(uint16_t *)&block[20] = htons(ARP_RSP); 160 161 // Sender MAC address 162 memcpy(block + 22, g_ethMacAddr, 6); 163 164 // Sender IP address 165 *(uint32_t *)&block[28] = g_ethIpAddr; 166 167 // Target MAC address 168 memcpy(block + 32, mac, 6); 169 170 // Target IP address : 192.168.0.67 171 block[38] = (uint8_t)dstIp; 172 block[39] = (uint8_t)(dstIp >> 8); 173 block[40] = (uint8_t)(dstIp >> 16); 174 block[41] = (uint8_t)(dstIp >> 24); 175 176 // 18个填充字节 177 memset(block + 42, 0, 18); 178 179 ethWrite((uint8_t *)block, 60); 181 } 182 //接收ARP数据包 183 void arpRcv(uint8_t * block, uint32_t frameLen) 184 { 185 uint64_t dstMac; 186 uint32_t srcIp, dstIp,i; 187 uint16_t msgType; 188 189 //报文类型,占2个字节 190 msgType = ntohs(*(uint16_t *)(block+6)); 191 //源IP 192 srcIp = (uint32_t)*(uint16_t *)(block + 14); 193 srcIp|= ((uint32_t)*(uint16_t *)(block + 16)) << 16; 194 195 dstMac=(uint64_t)*(uint16_t *)(block + 18); 196 dstMac|=((uint64_t)*(uint16_t *)(block + 20)) << 16; 197 dstMac|=((uint64_t)*(uint16_t *)(block + 22)) << 16; 198 199 //目的IP 200 dstIp = (uint32_t)*(uint16_t *)(block + 24); 201 dstIp|= ((uint32_t)*(uint16_t *)(block + 26)) << 16; 202 203 if (dstIp != g_ethIpAddr) 204 { 205 return; 206 } 207 if (msgType == ARP_RSP) 208 { 209 uartPrint("ARP Information:\\r\\n"); 210 //硬件类型 211 uartPrint("ar_pro:%x%x\\r\\n",*(block+2),*(block+3)); 212 //硬件地址长度 213 uartPrint("ar_hln:%d\\r\\n",*(block+4)); 214 //协议地址长度 215 uartPrint("ar_pln:%d\\r\\n",*(block+5)); 216 //操作类型 217 uartPrint(" AR_op:%x\\r\\n",msgType); 218 //电脑的MAC地址 219 uartPrint("ComputerMac:%x.%x.%x.%x.%x.%x\\r\\n",*(block+8),*(block+9),*(block+10),*(block+11),*(block+12),*(block+13)); 220 //电脑的IP地址 221 uartPrint("ComputerIp:%d.%d.%d.%d\\r\\n",*(block+14),*(block+15),*(block+16),*(block+17)); 222 //板子的MAC地址 223 uartPrint("PLC1850Mac:%x.%x.%x.%x.%x.%x\\r\\n",*(block+18),*(block+19),*(block+20),*(block+21),*(block+22),*(block+23)); 224 //板子的IP地址 225 uartPrint("PLC1850Ip:%d.%d.%d.%d",*(block+24),*(block+25),*(block+26),*(block+27)); 226 // arpSndRsp(srcIp, block + 8); 227 } 228 } 229 230 //不管成功与否,都由IP层来释放数据包 231 void ipSnd(uint32_t dstIp, uint8_t * block, uint32_t len, uint8_t protoType, uint8_t * mac) 232 { 233 block-= 20; 234 len+= 20; 235 236 // ------------ IP 层 237 238 block[0] = 0x45; // IP V4. length 20(5*4) 239 240 block[1] = 0x00; // service 241 242 *(uint16_t *)&block[2] = htons(len); 243 244 *(uint16_t *)&block[4] = htons((uint16_t)g_ipIdentifier++); // identification 245 246 *(uint16_t *)&block[6] = 0x0040; // flag and fragment 247 248 block[8] = 128; // TTL 249 250 block[9] = protoType; 251 252 *(uint16_t *)&block[10] = 0; // 校验和先填上0 253 254 *(uint16_t *)&block[12] = (uint16_t)g_ethIpAddr; 255 *(uint16_t *)&block[14] = (uint16_t)(g_ethIpAddr >> 16); 256 257 *(uint16_t *)&block[16] = (uint16_t)dstIp; 258 *(uint16_t *)&block[18] = (uint16_t)(dstIp >> 16); 259 260 *(uint16_t *)&block[10] = calcChecksum((uint16_t *)block, 20); 261 262 // ------------ MAC 层 263 264 block-= 14; 265 len+= 14; 266 267 memcpy(block, mac , 6); 268 269 memcpy(block + 6, g_ethMacAddr, 6); 270 271 *(uint16_t *)&block[12] = htons(MAC_TYPE_IP); 272 273 if (len < 60) 274 { 275 // MAC帧太短,补到最短长度 276 memset(block + len, 0, 60 - len); 277 len = 60; 278 } 279 280 ethWrite((uint8_t *)block, len); 281 } 282 283 // ICMP收到请求,需要回响应 284 void icmpRcvRequest(uint32_t srcIp, uint8_t * icmp, uint32_t len, uint8_t * mac) 285 { 286 uint8_t * block; 287 288 block = (uint8_t *)g_ipSndBuffer; 289 290 //留出14(MAC)+20(IP)个字节 291 block+=(14+20); 292 293 // ----------- ICMP层 294 memcpy(block, icmp, len); 295 296 block[0] = ICMP_ECHO_REPLY; 297 block[1] = 0; // code 298 299 *(uint16_t *)&block[2] = 0; //校验和先填上0 300 301 *(uint16_t *)&block[2] = calcChecksum((uint16_t *)block, len); 302 303 ipSnd(srcIp, (void *)block, len, PROT_ICMP, mac); 304 } 305 306 //接收到IP包的处理 307 void ipRcv(uint8_t * frame, uint32_t frameLen, uint8_t * mac) 308 { 309 uint16_t ipLength, flag; 310 uint32_t srcIp, dstIp; 311 312 if (frameLen < 20) 313 { 314 return; 315 } 316 317 if (calcChecksum((uint16_t *)frame, 20)) 318 { 319 //校验和不正确 320 return; 321 } 322 323 if (frame[0] != 0x45) 324 { 325 // IP VERSION应为4,长度应为20(5个bit 32)字节 326 return; 327 } 328 329 // ignore Type Of Service 330 331 ipLength = ntohs(*(uint16_t *)&frame[2]); 332 333 // ignore identification 334 335 flag = ntohs(*(uint16_t *)&frame[6]); 336 337 if (!(flag & DONT_FRAGMENT)) 338 { 339 // IP可以被分包,但只处理不分包情况 340 341 if (flag & MORE_FRAGMENT) 342 { 343 // 非最后一包,丢弃 344 return; 345 } 346 347 // 是最后一包 348 349 if (flag & FRAGMENT_OFFSET) 350 { 351 // 是最后一包,且偏移量不为0,也丢弃 352 return; 353 } 354 355 //最后一包,且偏移量为0,是整包,处理 356 } 357 358 if (frameLen < ipLength) 359 { 360 return; 361 } 362 363 // ignore fragment offset 364 365 //ttl = (uint32_t)frame[8]; 366 367 //srcIp = (frame[12] | (frame[13]<< 8) | (frame[14] << 16) | (frame[15] << 24)); 368 //dstIp = (frame[16] | (frame[17]<< 8) | (frame[18] << 16) | (frame[19] << 24)); 369 370 srcIp = *(uint16_t *)(frame + 12) | ((uint32_t)*(uint16_t *)(frame + 14) << 16); 371 dstIp = *(uint16_t *)(frame + 16) | ((uint32_t)*(uint16_t *)(frame + 18) << 16); 372 373 if ((dstIp != g_ethIpAddr) && (dstIp != 0x0100007F) && (dstIp != 0xffffffff)) 374 { 375 return; 376 } 377 378 if (frame[9] != PROT_ICMP) 379 { 380 // 非ICMP包,暂不处理 381 return; 382 } 383 384 if (frame[20] == ICMP_ECHO_REQUEST) 385 { 386 icmpRcvRequest(srcIp, frame + 20, ipLength - 20, mac); 387 } 388 } 389 390 // IP层接收MAC层数据帧的函数 391 uint32_t ipRcvMacFrame(uint8_t * block, uint32_t frameLen) 392 { 393 uint32_t i; 394 //判断是否收到ARP响应 397 if ((memcmp(block, PLC_ethMacAddr, 6) == 0)) 398 { 399 uartPrint("received\\r\\n"); 400 //发给本机的 401 switch (ntohs(*(uint16_t *)(block+12))) 402 { 403 case MAC_TYPE_ARP://ARP报文 405 arpRcv(block + 14, frameLen -14);//去掉针头,从ARP包开始 406 break; 407 case MAC_TYPE_IP://IP报文 408 ipRcv(block + 14, frameLen - 14, block+6); 409 break; 410 default: 411 break; 412 } 413 } 414 else //若没有收到,继续发送ARP请求 415 { 416 arpSndRsp1(0x0201A8C0,0xBE01A8C0,F_ethMacAddr,PLC_ethMacAddr); 417 } 418 return 1; 419 } 420 421 void ipInit(uint8_t * mac, uint32_t ip) 422 { 423 memcpy(g_ethMacAddr, mac, 6); 424 g_ethIpAddr = ip; 425 }
以上代码实现LPC1850对电脑以太网口发起ARP请求以及抓取响应的ARP包。
以上是关于基于PLC1850平台的ARP包请求与响应的主要内容,如果未能解决你的问题,请参考以下文章