|
ARP.C
//==========================================================================
// 嵌入式 TCP/IP 协议栈 MSC51 专用版
// ARP.C
// 作 者:南开大学-李章林
// 注 释:李清林
// 日 期:2008 年3 月
// 声 明:英文注释由作者李章林添加,中文注释由■李清林■添加。
// 转载时请保留上述信息。
// 成都理工学院/应用数字系/应用数字专业
//==========================================================================
#include "..\GloblDef\GloblDef.h"
#include "..\TCPIP\TCPIPmem.h"
#include "..\TCPIP\IP.h"
#include "..\Netif\etherif.h"
#include "..\Netif\ARP.h"
#include "..\TCPIP\Netif.h"
// 本机以太网网卡物理地址
BYTE DT_XDATA EtherAddrAny[ETHER_ADDR_LEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
// ARP 高速缓存表
struct SARPEntry DT_XDATA ARPTable[ARP_ENTRY_MAX_NUM];
//==========================================================================
// 嵌入式 TCP/IP 协议栈 MSC51 专用版
// 作 者:南开大学-李章林
// 注 释:李清林
// 日 期:2008 年3 月
// 声 明:英文注释由作者李章林添加,中文注释由■李清林■添加。
// 转载时请保留上述信息。
// 成都理工学院/应用数字系/应用数字专业
//---------------------------------------------------------------
// 程序名称:ARPInit= ARP 高速缓存表初始化子程序
// 入口参数:
// 无
// 出口参数:
// 无
//==========================================================================
void ARPInit() REENTRANT_MUL
{
BYTE i;
/* set every unit in arp tabel invalid */
// ARP 高速缓存表每个表项的生存时间初始化为零
for (i = 0; i < ARP_ENTRY_MAX_NUM; i++)
ARPTable.time = 0; ARP.C
}
//==========================================================================
// 嵌入式 TCP/IP 协议栈 MSC51 专用版
// 作 者:南开大学-李章林
// 注 释:李清林
// 日 期:2008 年3 月
// 声 明:英文注释由作者李章林添加,中文注释由■李清林■添加。
// 转载时请保留上述信息。
// 成都理工学院/应用数字系/应用数字专业
//---------------------------------------------------------------
// 程序名称:ARPQuery= ARP 发送请求子程序
// 功 能:填写数据链路层首部和 ARP 数据报文内容
// (1).以太网数据链路层首部的目的网卡物理地址由本机填写?????????????
// (2).以太网数据链路层首部的源网卡物理地址由网络接口设备填写???????
// (3).ARP 报文接收端以太网物理地址由本机填写????????????????????????
// (4).ARP 报文发送端以太网物理地址由网络接口设备填写????????????????
// (5).ARP 报文接收端 IP 地址由入口参数填写????????????????????????????
// (6).ARP 报文发送端 IP 地址由网络接口设备填写????????????????????????
// 入口参数:
// *NetIf=网络接口设备指针
// DestIP=目的IP 地址
// 出口参数:
// SMemHead=缓存控制块指针
//==========================================================================
struct SMemHead DT_XDATA * ARPQuery(struct SNetIf DT_XDATA *NetIf,
IP_ADDR DestIP) REENTRANT_SIG
{
struct SMemHead DT_XDATA *MemHead; // 缓存控制块指针
struct SEtherHead DT_XDATA *EtherHead; // 数据链路层报文首部指针
struct SARPPacket DT_XDATA *ARPPacket; // ARP 数据报文指针
// 缓存池申请内存空间(准备填充 ARP 数据报文以及以太网数据链路层首部)
if ((MemHead = MemAllocate(sizeof(struct SARPPacket) +
sizeof(struct SEtherHead))) == NULL)
return NULL; // 分配失败,返回 NULL
// 以太网数据链路层报文首部指针指向申请到的缓存控制块(数据区域)
EtherHead = (struct SEtherHead DT_XDATA *)(MemHead->pStart);
// ARP 数据报文指针指向申请空间 ARP 数据报文存放位置
ARPPacket = (struct SARPPacket DT_XDATA *)(MemHead->pStart +
sizeof(struct SEtherHead));
//-----------------------------------------------------------------
// 填写以太网数据链路层首部
//-----------------------------------------------------------------
// 填写以太网数据链路层首部的.DestAddr 域(以太网目的网卡地址) ARP.C
MemCopy(EtherHead->DestAddr,EtherAddrAny,ETHER_ADDR_LEN);
// 填写以太网数据链路层首部的.ScrAddr 域(以太网源网卡地址)
// 网络接口设备指针中获取以太网源网卡地址
MemCopy(EtherHead->ScrAddr ,
((struct SEtherDevice DT_XDATA *)(NetIf->Info))->Addr,ETHER_ADDR_LEN);
// 填写以太网数据链路层首部的.type 域(以太网帧类型=ARP 数据包[0x0806])
EtherHead->type = htons(ETHER_TYPE_ARP);
//----------------------------------------------------------------------------
// 填写 ARP 数据报文首部
//----------------------------------------------------------------------------
// 填写 ARP 数据报文硬件地址长度=6(因为网卡地址=48 位)
ARPPacket->HardWareAddrLen = ARP_HARDWARE_ADDR_LEN_ETHER;
// 填写 ARP 数据报文硬件类型=0x0001 代表以太网
ARPPacket->HardwareType = htons(ARP_HARDWARE_TYPE_ETHER);
// 填写 ARP 数据报文协议长度=4 (因为 IP 地址=32 位)
ARPPacket->ProtocolAddrLen = ARP_PROTOCOL_ADDR_LEN_IP;
// 填写 ARP 数据报文协议类型=0x0800 代表网际协议
ARPPacket->ProtocolType = htons(ARP_PROTOCOL_TYPE_IP);
// 填写 ARP 数据报文操作码=0x0001(ARP 请求)
ARPPacket->type = htons(ARP_TYPE_ARP_REQUEST);
//----------------------------------------------------------------------------
// 填写 ARP 数据报文内容
//----------------------------------------------------------------------------
// 填写 ARP 数据报文接收端 IP 地址(入口参数获取)
ARPPacket->IPDestAddr = DestIP;
// 填写 ARP 数据报文发送端 IP 地址(网络接口设备指针获取)
ARPPacket->IPScrAddr = NetIf->IPAddr;
// 填写 ARP 数据报文接收端以太网物理地址
MemCopy(ARPPacket->EtherDestAddr,EtherAddrAny,ETHER_ADDR_LEN);
// 填写 ARP 数据报文发送端以太网物理地址(网络接口设备指针获取)
MemCopy(ARPPacket->EtherScrAddr,
((struct SEtherDevice DT_XDATA *)(NetIf->Info))->Addr,ETHER_ADDR_LEN);
return MemHead;
}
//==========================================================================
// deel with a input arp packet. if send a reply is needed return
// this replay packet, oterhwise return NULL
// 嵌入式 TCP/IP 协议栈 MSC51 专用版
// 作 者:南开大学-李章林
// 注 释:李清林
// 日 期:2008 年3 月
// 声 明:英文注释由作者李章林添加,中文注释由■李清林■添加。
// 转载时请保留上述信息。
// 成都理工学院/应用数字系/应用数字专业 ARP.C
//---------------------------------------------------------------
// 程序名称:ARPInput=ARP 接收子程序
// 入口参数:
// MemHead:缓存控制块指针
// *NetIf=网络接口设备指针
// 出口参数:
// MemHead: 缓存控制块指针
//==========================================================================
struct SMemHead DT_XDATA *ARPInput(struct SMemHead DT_XDATA *MemHead,
struct SNetIf DT_XDATA *NetIf) REENTRANT_MUL
{
struct SEtherHead DT_XDATA *EtherHead; // 以太网数据链路层报文首部指针
struct SARPPacket DT_XDATA *ARPPacket; // ARP 数据报文指针
// 以太网数据链路层首部指针指向缓存控制块
EtherHead = (struct SEtherHead DT_XDATA *)(MemHead->pStart);
// ARP 数据报文指针指向缓存控制块 ARP 数据报文位置
ARPPacket = (struct SARPPacket DT_XDATA *)(MemHead->pStart +
sizeof(struct SEtherHead));
switch(ntohs(ARPPacket->type)) // 检查 ARP 数据报文类型
{
case ARP_TYPE_ARP_REQUEST: // ARP 请求报文
//----------------------------------------------------------------------------
// 如果 ARP 报文中的目的 IP 地址=网络接口设备中的 IP 地址
//----------------------------------------------------------------------------
if (ARPPacket->IPDestAddr == NetIf->IPAddr)
{
// send arp replay , fill Ether head
//----------------------------------------------------------------------------
// 发送 ARP 应答报文,填写以太网数据链路层首部
//----------------------------------------------------------------------------
// 填写链路层首部的.DestAddr 域(以太网目的网卡物理地址)
MemCopy(EtherHead->DestAddr,ARPPacket->EtherScrAddr,
ETHER_ADDR_LEN);
// 填写链路层首部的.ScrAddr 域(以太网源网卡物理地址)
// 网络接口设备中获取源网卡物理地址
MemCopy(EtherHead->ScrAddr,
((struct SEtherDevice DT_XDATA *)(NetIf->Info))->Addr,
ETHER_ADDR_LEN);
// 填写链路层首部的.type 域(以太网帧类型=ARP 数据包[0x0806])
EtherHead->type = htons(ETHER_TYPE_ARP);
//----------------------------------------------------------------------------
// 发送 ARP 应答报文,填写 ARP 报文
//----------------------------------------------------------------------------
/* copy source part to dest part.include Ether addr and Ip addr */ ARP.C
// 填写 ARP 应答报文接收端网卡物理地址和接收端 IP 地址
// =ARP 请求报文的发送端网卡物理地址和发送端 IP 地址
MemCopy(ARPPacket->EtherDestAddr,ARPPacket->EtherScrAddr,
(sizeof(IP_ADDR) + ETHER_ADDR_LEN));
/* fill source part. include Ether addr and Ip addr*/
// 填写 ARP 应答报文发送端 IP 地址=网络接口设备的 IP 地址
ARPPacket->IPScrAddr = NetIf->IPAddr;
// 填写 ARP 应答报文发送端网卡物理地址
// =网络接口设备的网卡物理地址
MemCopy(ARPPacket->EtherScrAddr,
((struct SEtherDevice DT_XDATA *)(NetIf->Info))->Addr,
ETHER_ADDR_LEN);
/* arp type */
// 填写 ARP 应答报文的操作码=ARP 应答
ARPPacket->type = htons(ARP_TYPE_ARP_REPLY);
return MemHead;
}
break;
case ARP_TYPE_ARP_REPLY: // ARP 应答报文
/* add to arp table */
ARPAddEntry(ARPPacket); // 添加网卡物理地址到高速缓存表
break;
}
/* for any case except ARP_TYPE_ARP_REQUEST for this IP,
arp packet is released */
MemFree(MemHead); // 释放缓冲控制块
/* no packet need send */
return NULL;
}
//==========================================================================
/* add a entry to arp table */
// 嵌入式 TCP/IP 协议栈 MSC51 专用版
// 作 者:南开大学-李章林
// 注 释:李清林
// 日 期:2008 年3 月
// 声 明:英文注释由作者李章林添加,中文注释由■李清林■添加。
// 转载时请保留上述信息。
// 成都理工学院/应用数字系/应用数字专业
//---------------------------------------------------------------
// 程序名称:ARPAddEntry=ARP 高速缓存表添加网卡物理地址子程序
// 入口参数:
// ARPPacket= ARP 报文指针
// 出口参数:
// 无 ARP.C
//==========================================================================
void ARPAddEntry(struct SARPPacket DT_XDATA *ARPPacket) REENTRANT_MUL
{
BYTE i;
WORD MinTime; // 最小生存时间
BYTE iToReplace; /* index of entry going to be replace */
// 高速缓存表查找一个空白表项
for (i = 0; i < ARP_ENTRY_MAX_NUM ; i++)
{
if (ARPTable.time == 0) // 如果找到空白项
{
iToReplace = i; // 记录下索引号
break;
}
}
if (i == ARP_ENTRY_MAX_NUM) // 如果未找到空白项
{ // 寻找生存时间最老的一个表项
MinTime = ARP_ENTRY_TIME_OUT;
iToReplace = 0;
for (i = 0 ; i < ARP_ENTRY_MAX_NUM ; i++)
{
if (MinTime> ARPTable.time)
{
MinTime = ARPTable.time; // 找到生存时间最老的表项
iToReplace = i; // 记录下索引号
}
}
}
/* replace the entry */
// 填写网卡物理地址=ARP 报文指针->源网卡源物理地址
MemCopy(ARPTable[iToReplace].EtherAddr,ARPPacket->EtherScrAddr,ETHER_ADDR_LEN);
// 填写 IP 地址=ARP 报文指针->源 IP 地址
ARPTable[iToReplace].IPAddr = ARPPacket->IPScrAddr;
/* start timer */
// 填写生存时间=0xFFFF
ARPTable[iToReplace].time = ARP_ENTRY_TIME_OUT;
}
//==========================================================================
/* find IPAddr in arptable copy it to EtherAddr. if can't find return false*/
// 嵌入式 TCP/IP 协议栈 MSC51 专用版
// 作 者:南开大学-李章林
// 注 释:李清林
// 日 期:2008 年3 月 ARP.C
// 声 明:英文注释由作者李章林添加,中文注释由■李清林■添加。
// 转载时请保留上述信息。
// 成都理工学院/应用数字系/应用数字专业
//---------------------------------------------------------------
// 程序名称:ARPFind=高速缓存表查找子程序
// 功 能:ARP 高速缓存表查找 IP 地址对应的网卡物理地址
// 入口参数:
// IPAddr= 待查找 IP 地址
// 出口参数:
// EtherAddr[]=IPAddr 地址相对应的以太网网卡物理地址
//==========================================================================
BOOL ARPFind(BYTE EtherAddr[],IP_ADDR IPAddr) REENTRANT_SIG
{
BYTE i;
for (i = 0 ; i < ARP_ENTRY_MAX_NUM ; i++)
{
if (ARPTable.time != 0) // 如果当前表项的生存时间有效
{
if (ARPTable.IPAddr == IPAddr) // 如果找到规定的 IP 地址
{ // 高速缓存表当前表项的网卡物理地址拷贝到数组
MemCopy(EtherAddr,ARPTable.EtherAddr,ETHER_ADDR_LEN);
return (TRUE);
}
}
}
return (FALSE); // 未找到入口参数规定的 IP 地址
}
//==========================================================================
// 嵌入式 TCP/IP 协议栈 MSC51 专用版
// 作 者:南开大学-李章林
// 注 释:李清林
// 日 期:2008 年3 月
// 声 明:英文注释由作者李章林添加,中文注释由■李清林■添加。
// 转载时请保留上述信息。
// 成都理工学院/应用数字系/应用数字专业
//---------------------------------------------------------------
// 程序名称:ARPTimer=ARP 定时器化子程序
// 功 能:每隔一定的时间将高速缓存表表项的生存时间递减
// 入口参数:
// 无
// 出口参数:
// 无 ARP.C
//==========================================================================
void ARPTimer() REENTRANT_MUL
{
BYTE i;
for (i = 0 ; i < ARP_ENTRY_MAX_NUM ; i++)
{
if (ARPTable.time != 0) // 如果当前表项生存时间不为零
{
ARPTable.time--; // 当前表项的生存时间递减
}
}
} |
阿莫论坛20周年了!感谢大家的支持与爱护!!
知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)
|