基于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包请求与响应的主要内容,如果未能解决你的问题,请参考以下文章

22.周期性发送ARP响应包

http协议常见的请求头和响应头

什么是HTTP协议响应流

TCP/IP总结arp协议

21.如何伪造ARP响应?

ICMP