基于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请求与响应程序
主程序:
- #include "LPC18xx.h"
- #include "led.h"
- extern void taskEth (void);
- int main(void)
- {
- SystemInit();
- ledInit();
- SysTick_Config(GetCoreClock() / );
- taskEth();
- while ();
- }
- void SysTick_Handler(void)
- {
- static int counter = ;
- counter++;
- if (counter >= )
- {
- counter = ;
- //ledRolling();
- }
- }
taskEth()函数程序:
- #include <stdlib.h>
- #include <lpc18xx.h>
- #include "lpc18xx_emac.h"
- #include "lpc18xx_debug.h"
- extern uint32_t ipatol(char * p_input);
- extern void ipInit(uint8_t * mac, uint32_t ip);
- extern uint32_t ipRcvMacFrame(uint8_t * block, uint32_t frameLen);
- extern void arpSndRsp1(uint32_t dstIp,uint32_t resIp, uint8_t *f_mac,uint8_t *mac);
- uint8_t gFlag;
- uint8_t g_emacBuffer[];
- uint8_t g_ethMac[];
- uint8_t F_ethMac[];
- // EMAC接口接收到的数据,通知应用层回调函数
- void ethReadReadyCb()
- {
- gFlag = ;
- }
- void taskEth (void)
- {
- uint32_t len;
- // 板子的MAK地址
- g_ethMac[] = 0x11;
- g_ethMac[] = 0x1F;
- g_ethMac[] = 0xE0;
- g_ethMac[] = 0x12;
- g_ethMac[] = 0x1E;
- g_ethMac[] = 0x0F;
- //广播地址
- F_ethMac[]=0xff;
- F_ethMac[]=0xff;
- F_ethMac[]=0xff;
- F_ethMac[]=0xff;
- F_ethMac[]=0xff;
- F_ethMac[]=0xff;
- //串口初始化
- debugComInit();
- uartPrint("uart init\r\n");
- //以太网初始化
- while (ethInit(ethReadReadyCb, g_ethMac) == );
- uartPrint("eth init complete\r\n");
- // 为以太网接口指定MAC地址和IP地址
- ipInit(g_ethMac, 0xBE01A8C0); // 192.168.1.190
- //发送ARP请求函数
- arpSndRsp1(0x0201A8C0,0xBE01A8C0,F_ethMac,g_ethMac);
- while ()
- {
- if (!gFlag)
- {
- continue;
- }
- //读取是否接收到报文
- len = ethRead(g_emacBuffer, );
- if(len)
- {
- ipRcvMacFrame((uint8_t *)g_emacBuffer, len); //接收报文
- }
- gFlag=;
- }
- }
arpSndRsp1()、ethRead()和ipRcvMacFrame()函数程序如下:
- #include <stdint.h>
- #include <string.h>
- #include <stdlib.h>
- #include "lpc18xx_emac.h"
- #include "lpc18xx_debug.h"
- //#include "shell.h"
- #define MAC_TYPE_IP 0x0800 //ip类型
- #define MAC_TYPE_ARP 0x0806 //mac类型
- #define ARP_REQ 0x0001 //ARP请求
- #define ARP_RSP 0x0002 //ARP响应
- #define ICMP_ECHO_REQUEST 8 // message is an echo request
- #define ICMP_ECHO_REPLY 0 // message is an echo reply
- #define PROT_ICMP 1 // Internet Control Message Protocol
- #define PROT_TCP 6 // Transmission Control Protocol
- #define PROT_UDP 17 // User Datagram Protocol
- #define DONT_FRAGMENT 0x4000 //fragment
- #define MORE_FRAGMENT 0x2000
- #define FRAGMENT_OFFSET 0x1FFF
- uint8_t PLC_ethMacAddr[];
- uint8_t F_ethMacAddr[];
- uint8_t g_ethMacAddr[];
- uint32_t g_ethIpAddr;
- uint32_t g_ipSndBuffer[];
- uint16_t g_ipIdentifier = ;
- //将字从主机序转为网络序
- uint16_t htons(uint16_t word)
- {
- return ((word >> ) & 0x00FF) | ((word << ) & 0xFF00);
- }
- //将字从网络序转为主机序
- uint16_t ntohs(uint16_t word)
- {
- return ((word >> ) & 0x00FF) | ((word << ) & 0xFF00);
- }
- uint16_t calcChecksum(uint16_t * buffer, uint32_t size)
- {
- uint32_t cksum;
- cksum = ;
- while (size > )
- {
- cksum += *buffer++;
- size -= sizeof(uint16_t);
- }
- if (size)
- {
- cksum += *(uint8_t*)buffer;
- }
- cksum = (cksum >> ) + (cksum & 0xffff);
- cksum += (cksum >>);
- return (uint16_t)(~cksum);
- }
- //发送ARP请求
- void arpSndRsp1(uint32_t dstIp,uint32_t resIp, uint8_t *f_mac,uint8_t *mac)
- {
- uint8_t * block;
- //uint32_t blockLen;
- block = (uint8_t *)g_ipSndBuffer;//
- memcpy(block, mac, );//以太网目的广播地址
- memcpy(block + , mac, );//以太网的源地址,也就是板子的MAC地址
- // arp type
- *(uint16_t *)&block[] = htons(MAC_TYPE_ARP);//mac类型
- // --------- ARP 层
- // Hardway type : Ethernet
- block[] = 0x00;
- block[] = 0x01;
- // ip type
- *(uint16_t *)&block[] = htons(MAC_TYPE_IP);//IP类型
- // Hardway size
- block[] = 0x06;//硬件地址长度
- // Protocal size
- block[] = 0x04;//协议地址长度
- // arp reply
- *(uint16_t *)&block[] = htons(ARP_REQ);//ARPARP请求
- // Sender MAC address
- memcpy(block + , mac, );//发送者的Mac地址
- memcpy(PLC_ethMacAddr, mac, );//复制发送者的mac地址
- // Sender IP address
- *(uint32_t *)&block[] = resIp;//发送者IP地址
- // Target MAC address
- memcpy(block + , f_mac, );
- memcpy(F_ethMacAddr, f_mac, );//复制目的广播地址
- // Target IP address : 192.168.0.67
- block[] = (uint8_t)dstIp;
- block[] = (uint8_t)(dstIp >> );
- block[] = (uint8_t)(dstIp >> );
- block[] = (uint8_t)(dstIp >> );
- // 18填充
- memset(block + , , );
- ethWrite((uint8_t *)block, );
- uartPrint("sended ARP\r\n");
- }
- //发送ARP响应
- void arpSndRsp(uint32_t dstIp, uint8_t * mac)
- {
- uint8_t * block;
- //uint32_t blockLen;
- block = (uint8_t *)g_ipSndBuffer;//
- memcpy(block, mac, );
- memcpy(block + , g_ethMacAddr, );
- // arp type
- *(uint16_t *)&block[] = htons(MAC_TYPE_ARP);
- // --------- ARP 层
- // Hardway type : Ethernet
- block[] = 0x00;
- block[] = 0x01;
- // ip type
- *(uint16_t *)&block[] = htons(MAC_TYPE_IP);
- // Hardway size
- block[] = 0x06;
- // Protocal size
- block[] = 0x04;
- // arp reply
- *(uint16_t *)&block[] = htons(ARP_RSP);
- // Sender MAC address
- memcpy(block + , g_ethMacAddr, );
- // Sender IP address
- *(uint32_t *)&block[] = g_ethIpAddr;
- // Target MAC address
- memcpy(block + , mac, );
- // Target IP address : 192.168.0.67
- block[] = (uint8_t)dstIp;
- block[] = (uint8_t)(dstIp >> );
- block[] = (uint8_t)(dstIp >> );
- block[] = (uint8_t)(dstIp >> );
- // 18个填充字节
- memset(block + , , );
- ethWrite((uint8_t *)block, );
- }
- //接收ARP数据包
- void arpRcv(uint8_t * block, uint32_t frameLen)
- {
- uint64_t dstMac;
- uint32_t srcIp, dstIp,i;
- uint16_t msgType;
- //报文类型,占2个字节
- msgType = ntohs(*(uint16_t *)(block+));
- //源IP
- srcIp = (uint32_t)*(uint16_t *)(block + );
- srcIp|= ((uint32_t)*(uint16_t *)(block + )) << ;
- dstMac=(uint64_t)*(uint16_t *)(block + );
- dstMac|=((uint64_t)*(uint16_t *)(block + )) << ;
- dstMac|=((uint64_t)*(uint16_t *)(block + )) << ;
- //目的IP
- dstIp = (uint32_t)*(uint16_t *)(block + );
- dstIp|= ((uint32_t)*(uint16_t *)(block + )) << ;
- if (dstIp != g_ethIpAddr)
- {
- return;
- }
- if (msgType == ARP_RSP)
- {
- uartPrint("ARP Information:\r\n");
- //硬件类型
- uartPrint("ar_pro:%x%x\r\n",*(block+),*(block+));
- //硬件地址长度
- uartPrint("ar_hln:%d\r\n",*(block+));
- //协议地址长度
- uartPrint("ar_pln:%d\r\n",*(block+));
- //操作类型
- uartPrint(" AR_op:%x\r\n",msgType);
- //电脑的MAC地址
- uartPrint("ComputerMac:%x.%x.%x.%x.%x.%x\r\n",*(block+),*(block+),*(block+),*(block+),*(block+),*(block+));
- //电脑的IP地址
- uartPrint("ComputerIp:%d.%d.%d.%d\r\n",*(block+),*(block+),*(block+),*(block+));
- //板子的MAC地址
- uartPrint("PLC1850Mac:%x.%x.%x.%x.%x.%x\r\n",*(block+),*(block+),*(block+),*(block+),*(block+),*(block+));
- //板子的IP地址
- uartPrint("PLC1850Ip:%d.%d.%d.%d",*(block+),*(block+),*(block+),*(block+));
- // arpSndRsp(srcIp, block + 8);
- }
- }
- //不管成功与否,都由IP层来释放数据包
- void ipSnd(uint32_t dstIp, uint8_t * block, uint32_t len, uint8_t protoType, uint8_t * mac)
- {
- block-= ;
- len+= ;
- // ------------ IP 层
- block[] = 0x45; // IP V4. length 20(5*4)
- block[] = 0x00; // service
- *(uint16_t *)&block[] = htons(len);
- *(uint16_t *)&block[] = htons((uint16_t)g_ipIdentifier++); // identification
- *(uint16_t *)&block[] = 0x0040; // flag and fragment
- block[] = ; // TTL
- block[] = protoType;
- *(uint16_t *)&block[] = ; // 校验和先填上0
- *(uint16_t *)&block[] = (uint16_t)g_ethIpAddr;
- *(uint16_t *)&block[] = (uint16_t)(g_ethIpAddr >> );
- *(uint16_t *)&block[] = (uint16_t)dstIp;
- *(uint16_t *)&block[] = (uint16_t)(dstIp >> );
- *(uint16_t *)&block[] = calcChecksum((uint16_t *)block, );
- // ------------ MAC 层
- block-= ;
- len+= ;
- memcpy(block, mac , );
- memcpy(block + , g_ethMacAddr, );
- *(uint16_t *)&block[] = htons(MAC_TYPE_IP);
- if (len < )
- {
- // MAC帧太短,补到最短长度
- memset(block + len, , - len);
- len = ;
- }
- ethWrite((uint8_t *)block, len);
- }
- // ICMP收到请求,需要回响应
- void icmpRcvRequest(uint32_t srcIp, uint8_t * icmp, uint32_t len, uint8_t * mac)
- {
- uint8_t * block;
- block = (uint8_t *)g_ipSndBuffer;
- //留出14(MAC)+20(IP)个字节
- block+=(+);
- // ----------- ICMP层
- memcpy(block, icmp, len);
- block[] = ICMP_ECHO_REPLY;
- block[] = ; // code
- *(uint16_t *)&block[] = ; //校验和先填上0
- *(uint16_t *)&block[] = calcChecksum((uint16_t *)block, len);
- ipSnd(srcIp, (void *)block, len, PROT_ICMP, mac);
- }
- //接收到IP包的处理
- void ipRcv(uint8_t * frame, uint32_t frameLen, uint8_t * mac)
- {
- uint16_t ipLength, flag;
- uint32_t srcIp, dstIp;
- if (frameLen < )
- {
- return;
- }
- if (calcChecksum((uint16_t *)frame, ))
- {
- //校验和不正确
- return;
- }
- if (frame[] != 0x45)
- {
- // IP VERSION应为4,长度应为20(5个bit 32)字节
- return;
- }
- // ignore Type Of Service
- ipLength = ntohs(*(uint16_t *)&frame[]);
- // ignore identification
- flag = ntohs(*(uint16_t *)&frame[]);
- if (!(flag & DONT_FRAGMENT))
- {
- // IP可以被分包,但只处理不分包情况
- if (flag & MORE_FRAGMENT)
- {
- // 非最后一包,丢弃
- return;
- }
- // 是最后一包
- if (flag & FRAGMENT_OFFSET)
- {
- // 是最后一包,且偏移量不为0,也丢弃
- return;
- }
- //最后一包,且偏移量为0,是整包,处理
- }
- if (frameLen < ipLength)
- {
- return;
- }
- // ignore fragment offset
- //ttl = (uint32_t)frame[8];
- //srcIp = (frame[12] | (frame[13]<< 8) | (frame[14] << 16) | (frame[15] << 24));
- //dstIp = (frame[16] | (frame[17]<< 8) | (frame[18] << 16) | (frame[19] << 24));
- srcIp = *(uint16_t *)(frame + ) | ((uint32_t)*(uint16_t *)(frame + ) << );
- dstIp = *(uint16_t *)(frame + ) | ((uint32_t)*(uint16_t *)(frame + ) << );
- if ((dstIp != g_ethIpAddr) && (dstIp != 0x0100007F) && (dstIp != 0xffffffff))
- {
- return;
- }
- if (frame[] != PROT_ICMP)
- {
- // 非ICMP包,暂不处理
- return;
- }
- if (frame[] == ICMP_ECHO_REQUEST)
- {
- icmpRcvRequest(srcIp, frame + , ipLength - , mac);
- }
- }
- // IP层接收MAC层数据帧的函数
- uint32_t ipRcvMacFrame(uint8_t * block, uint32_t frameLen)
- {
- uint32_t i;
- //判断是否收到ARP响应
- if ((memcmp(block, PLC_ethMacAddr, ) == ))
- {
- uartPrint("received\r\n");
- //发给本机的
- switch (ntohs(*(uint16_t *)(block+)))
- {
- case MAC_TYPE_ARP://ARP报文
- arpRcv(block + , frameLen -);//去掉针头,从ARP包开始
- break;
- case MAC_TYPE_IP://IP报文
- ipRcv(block + , frameLen - , block+);
- break;
- default:
- break;
- }
- }
- else //若没有收到,继续发送ARP请求
- {
- arpSndRsp1(0x0201A8C0,0xBE01A8C0,F_ethMacAddr,PLC_ethMacAddr);
- }
- return ;
- }
- void ipInit(uint8_t * mac, uint32_t ip)
- {
- memcpy(g_ethMacAddr, mac, );
- g_ethIpAddr = ip;
- }
以上代码实现LPC1850对电脑以太网口发起ARP请求以及抓取响应的ARP包。
基于PLC1850平台的ARP包请求与响应的更多相关文章
- 基于PLC1850平台的ICMP包请求与响应
一.以太网IP包报文格式 IP包是连接在以太网首部(以太网目的MAC地址(6个字节)+以太网源MAC地址(6个字节)+帧类型(2个字节))之后. IP报文中各个字段分析如下: ①.版本:在IP报文中, ...
- 基于PLC1850平台的UDP报文接收与发送
一.UDP报文格式 源端口(2个字节):发送报文的进程的16位端口号. 目的端口(2个字节):目的设备上的接收进程的16位端口号. 长度(2个字节):整个UDP数据报的长度,包括首都和数据字段. 校验 ...
- 基于Linux平台的libpcap源码分析和优化
目录 1..... libpcap简介... 1 2..... libpcap捕包过程... 2 2.1 数据包基本捕包流程... 2 2.2 libpcap捕包过程... ...
- 基于Android 平台简易即时通讯的研究与设计[转]
摘要:论文简单介绍Android 平台的特性,主要阐述了基于Android 平台简易即时通讯(IM)的作用和功能以及实现方法.(复杂的通讯如引入视频音频等可以考虑AnyChat SDK~)关键词:An ...
- c语言Winpcap编程构造并接收解析arp包
/* 程序功能: 1.构造arp包,并发送.程序参数顺序:源IP.目的IP.mac地址.flag 2.获取网络中的ARP数据包,解析数据包的内容.程序参数:日志文件名 winpacp中文技术文档(基本 ...
- 基于java平台的常用资源整理
这里整理了基于java平台的常用资源 翻译 from :akullpp | awesome-java 大家一起学习,共同进步. 如果大家觉得有用,就mark一下,赞一下,或评论一下,让更多的人知道.t ...
- 基于X86平台的PC机通过网络发送一个int(32位)整数的字节顺序
1.字节顺序 字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端.大端两种字节顺序.小端字节序指低字节数据存放在内存低地址处,高字节数据存放在内存高地址处:大端字节序是高字节数据存 ...
- 这里整理了基于java平台的常用资源
这里整理了基于java平台的常用资源 翻译 from :akullpp | awesome-java 大家一起学习,共同进步. 如果大家觉得有用,就mark一下,赞一下,或评论一下,让更多的人知道.t ...
- ARP包分析(wireshark)
ARP数据报格式(42字节) 这是用wireshark抓到的一个ARP包,42个字节. 这个ARP包的 以太网首部(14字节): 字段 长度(Byte) ...
随机推荐
- Centos7 Nagios 搭建
Nagios 是一款自动化运维工具,可以协助运维人员监控服务器的运行状况,并且拥有报警功能.本文章将介绍其安装方法和详细的配置方法. 总结 可以做资源,网络,应用服务的监控 配置上需要配置被监控的,服 ...
- Linux 命令分类学习
Linux常用命令大全(非常全!!!) 系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q ...
- Ehcache 3.7文档—基础篇—Tiering Options
Ehcache支持分层缓存的概念,这节主要介绍不同的配置选项,同时也解释了规则和最佳实践. 一. 数据缓存到堆外 当在cache中除了有heap层之外,有一些需要注意的: 添加一个key-value到 ...
- 电子产品使用感受之--DJI OSMO Pocket VS OSMO MOBILE
2019.02.20 更新 打算出掉OSMO MOBILE,有需要的可以联系我啊 2019.1.26 更新 快要到春节了,购物中心的过年气氛很浓,网络上也是喜气洋洋. 今年天津有很多活动在春节期间举办 ...
- 关于vue页面多了之后,webpack热更新速度慢的解决办法
vue项目大了之后,每次热更新都要10多秒的时间, 网上找了一大堆发现一个有用的办法 "env": { "development":{ "plugin ...
- linux中启动 java -jar 后台运行程序
直接用java -jar xxx.jar,当退出或关闭shell时,程序就会停止掉.以下方法可让jar运行后一直在后台运行. 1. java -jar xxx.jar & 说明: 在末尾加入 ...
- webpack 知识点
安装 webpack npm install -g webpack npm install -g webpack-cli@2.x 初始化项目 npm init -y npm install --sav ...
- 《Redis 命令操作》
一:Redis 的启动与关闭 - 关闭指定端口的 Redis - redis-cli -p 9200 shutdown - 开启 Redis - redis-server redis.config 二 ...
- Spring Boot事务管理(上)
摘要 本文主要介绍基于Spring Boot的事务管理,尤其是@Transactional注解详细用法.首先,简要介绍Spring Boot中如何开启事务管理:其次,介绍在Spring,Spring ...
- Spring Boot Thmeleaf的语法 day04
一.Thmeleaf语法的使用 html格式的页面放在classpath:/templates/就会自动渲染. 1.在pom.xml导入 <dependency> <groupId& ...