基于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) ...
随机推荐
- Android Studio帮助文档的安装及智能提示设置
初次使用Android Studio,发现其智能提示不能像Visual Studio一样显示系统方法等的详细用途描述.经查找资料,问题原因是未安装SDK Document. 解决办法如下: 1.打开如 ...
- GMA Round 1 数列与方程
传送门 数列与方程 首项为1,各项均大于0的数列{$a_n$}的前n项和$S_n$满足对于任意正整数n:$S_{n+1}^2-2*S_{n+1}*S_{n}-\sqrt{2}*S_n-1=0$,求$a ...
- ECMA Script 6_async 函数
async 函数 const promise = new Promise((resolve, reject)=>{ setTimeout(function(){ console.log(&quo ...
- linux学习:xargs与grep用法整理
xargs xargs 是给命令传递参数的一个过滤器,也是组合多个命令的一个工具. xargs 可以将管道或标准输入(stdin)数据转换成命令行参数,也能够从文件的输出中读取数据. xargs 也可 ...
- eclipse创建spring boot项目,tomcat启动成功,但http://localhost:8080无法访问报错404解决方案
spring boot的启动程序启动后,在访问http://localhost:8080地址的时候出现了错误,为什么出错网上我找了好久也没有得出具体的解决办法 当我指定到具体的action的时候,却可 ...
- MVC 向页面传值方式总结(1)
ViewData传值. HomeController.cs Co de: public ActionResult Index() { ViewData["Title" ...
- CodeForces #549 Div.2 D. The Beatles
题目 解题思路 关键是要 ,找出L 的组合,然后遍历L的组合,用最大公约数就可以算出来当前L的值要停多少次 怎么找出L的组合呢?饭店是每隔K 有一个,是重复的,我们只需要算出第一个饭店两侧,起点和停顿 ...
- k8s-No.1-概述与架构
本章目录 k8s概述 k8s系统架构 k8s工作流程图 一 概述 k8s是什么 k8s是谷歌公司基于内部容器管理系统borg开源出的一个容器集群管理工具,它是用go语言开发,提供了容器的应用部署,规 ...
- vim模式下报错E37: No write since last change (add ! to override)
故障现象: 使用vim修改文件报错,系统提示如下: E37: No write since last change (add ! to override) 故障原因: 文件为只读文件,无法修改. 解决 ...
- C# 图片识别
项目需要识别图片上的信息,网上搜索试了Asprise-OCR.Microsoft Office Document Imaging(Office 2007) 组件实现两种方式,后者可以识别中文等其他语言 ...