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

  以上代码实现LPC1850对电脑以太网口发起ARP请求以及抓取响应的ARP包。

  

基于PLC1850平台的ARP包请求与响应的更多相关文章

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

    一.以太网IP包报文格式 IP包是连接在以太网首部(以太网目的MAC地址(6个字节)+以太网源MAC地址(6个字节)+帧类型(2个字节))之后. IP报文中各个字段分析如下: ①.版本:在IP报文中, ...

  2. 基于PLC1850平台的UDP报文接收与发送

    一.UDP报文格式 源端口(2个字节):发送报文的进程的16位端口号. 目的端口(2个字节):目的设备上的接收进程的16位端口号. 长度(2个字节):整个UDP数据报的长度,包括首都和数据字段. 校验 ...

  3. 基于Linux平台的libpcap源码分析和优化

    目录 1..... libpcap简介... 1 2..... libpcap捕包过程... 2 2.1        数据包基本捕包流程... 2 2.2        libpcap捕包过程... ...

  4. 基于Android 平台简易即时通讯的研究与设计[转]

    摘要:论文简单介绍Android 平台的特性,主要阐述了基于Android 平台简易即时通讯(IM)的作用和功能以及实现方法.(复杂的通讯如引入视频音频等可以考虑AnyChat SDK~)关键词:An ...

  5. c语言Winpcap编程构造并接收解析arp包

    /* 程序功能: 1.构造arp包,并发送.程序参数顺序:源IP.目的IP.mac地址.flag 2.获取网络中的ARP数据包,解析数据包的内容.程序参数:日志文件名 winpacp中文技术文档(基本 ...

  6. 基于java平台的常用资源整理

    这里整理了基于java平台的常用资源 翻译 from :akullpp | awesome-java 大家一起学习,共同进步. 如果大家觉得有用,就mark一下,赞一下,或评论一下,让更多的人知道.t ...

  7. 基于X86平台的PC机通过网络发送一个int(32位)整数的字节顺序

    1.字节顺序 字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端.大端两种字节顺序.小端字节序指低字节数据存放在内存低地址处,高字节数据存放在内存高地址处:大端字节序是高字节数据存 ...

  8. 这里整理了基于java平台的常用资源

    这里整理了基于java平台的常用资源 翻译 from :akullpp | awesome-java 大家一起学习,共同进步. 如果大家觉得有用,就mark一下,赞一下,或评论一下,让更多的人知道.t ...

  9. ARP包分析(wireshark)

    ARP数据报格式(42字节) 这是用wireshark抓到的一个ARP包,42个字节. 这个ARP包的 以太网首部(14字节): 字段               长度(Byte)           ...

随机推荐

  1. Centos7 Nagios 搭建

    Nagios 是一款自动化运维工具,可以协助运维人员监控服务器的运行状况,并且拥有报警功能.本文章将介绍其安装方法和详细的配置方法. 总结 可以做资源,网络,应用服务的监控 配置上需要配置被监控的,服 ...

  2. Linux 命令分类学习

    Linux常用命令大全(非常全!!!) 系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q ...

  3. Ehcache 3.7文档—基础篇—Tiering Options

    Ehcache支持分层缓存的概念,这节主要介绍不同的配置选项,同时也解释了规则和最佳实践. 一. 数据缓存到堆外 当在cache中除了有heap层之外,有一些需要注意的: 添加一个key-value到 ...

  4. 电子产品使用感受之--DJI OSMO Pocket VS OSMO MOBILE

    2019.02.20 更新 打算出掉OSMO MOBILE,有需要的可以联系我啊 2019.1.26 更新 快要到春节了,购物中心的过年气氛很浓,网络上也是喜气洋洋. 今年天津有很多活动在春节期间举办 ...

  5. 关于vue页面多了之后,webpack热更新速度慢的解决办法

    vue项目大了之后,每次热更新都要10多秒的时间, 网上找了一大堆发现一个有用的办法 "env": { "development":{ "plugin ...

  6. linux中启动 java -jar 后台运行程序

    直接用java -jar xxx.jar,当退出或关闭shell时,程序就会停止掉.以下方法可让jar运行后一直在后台运行. 1. java -jar xxx.jar & 说明: 在末尾加入 ...

  7. webpack 知识点

    安装 webpack npm install -g webpack npm install -g webpack-cli@2.x 初始化项目 npm init -y npm install --sav ...

  8. 《Redis 命令操作》

    一:Redis 的启动与关闭 - 关闭指定端口的 Redis - redis-cli -p 9200 shutdown - 开启 Redis - redis-server redis.config 二 ...

  9. Spring Boot事务管理(上)

    摘要 本文主要介绍基于Spring Boot的事务管理,尤其是@Transactional注解详细用法.首先,简要介绍Spring Boot中如何开启事务管理:其次,介绍在Spring,Spring ...

  10. Spring Boot Thmeleaf的语法 day04

    一.Thmeleaf语法的使用 html格式的页面放在classpath:/templates/就会自动渲染. 1.在pom.xml导入 <dependency> <groupId& ...