基于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) ...
随机推荐
- 201771010126 王燕《面向对象程序设计(java)》第二周学习总结
201771010126 王燕<面向对象程序设计(java)>第二周学习总结 一.理论知识学习部分 3.1j简单 的java应用程序 标识符由字母.下划线.美元符号和数字组成, 且第一个符 ...
- CSS3_动画 animation
在项目中,颜色,图片,等等数据都保存在数组中 动画 使元素从一种样式逐渐变化到另一种样式的 animation: name ; 无顺序要求,但是必须先写 持续时间 ,再写 延迟时间 原理 人眼在看 ...
- 1. js数据类型_对象_函数_内存
1. js数据类型有哪些? 基本(值)类型 Number ---- 任意数值 String ---- 任意字符串 Boolean ---- true/false undefined ---- unde ...
- linux命令技巧
printf "%-5s %-10s %-4s\n" No Name Mark printf "%-5s %-10s %-4.2f\n" 1 Sarath 80 ...
- JavaFTP文件传输上传和下载文件
首先在电脑上创建一个ftp服务器,具体步骤自行百度. 接下来开始写有用的java连接TFP站点和传输文件的代码. 1.首先jar用的是apache 的工具包 请自行下载 . 2.俩个文件代码 一个Ft ...
- 19.3.25 sql查询语句
1.单表查询:select * from 表名 where id = 111 2.查询表内数据并以id排序:select * from 表名 order by id (降序:desc/升序:asc) ...
- java.util中,util是什么意思
Util是utiliy的缩写,是一个多功能.基于工具的包. java.util是包含集合框架.遗留的 collection 类.事件模型.日期和时间设施.国际化和各种实用工具类(字符串标记生成器.随机 ...
- mac下git安装与使用
1.下载git客户端,下载地址为:https://git-scm.com/download/mac 2.打开安装包,可以看到此时的界面为: 我们需要把.pkg的安装包安装到系统当中.我双击了安装包 ...
- 多线程之Synchronized锁的基本介绍
基本介绍 synchronized是Java实现同步的一种机制,它属于Java中关键字,是一种jvm级别的锁.synchronized锁的创建和释放是此关键字控制的代码的开始和结束位置,锁是有jvm控 ...
- pandas(二)
层级索引: index=[('a',2010),('b',2011),('c',2010'),('a',2012),('e',2010),('f',2011)] age=[18,17,18,16,18 ...