基于PLC1850平台的ARP包请求与响应

一、以太网ARP报文格式

  基于PLC1850平台的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包。

  

上一篇:栈的实现Java


下一篇:基于JWT(Json Web Token)的ASP.NET Web API授权方式