⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 arp.c

📁 51单片机上实现tcp/ip的源代码
💻 C
字号:
/*********************************************************************
 *            Copright(c) 2004,张会福 湖南科技大学计算机学院 
 *                        All rights reserved.
 *
 *文件名称:    arp.c
 *文件标识: 
 *摘    要: 实现逻辑地址(IP地址)到物理地址(以太网地址)的动态映射
 *
 *当前版本: V1.0
 *完成日期: 2004.4.10
 *
 *********************************************************************/
#define ARP_GLOBALS
#include "net_cfg.h"      //头文件定义,包含很多用到的宏的定义

/**********************************************************************
**函数原型:   void Arp_Request(unsigned long ip_address)
**入口参数:   ip_address: 要解析的IP地址
**出口参数:   无
**返 回 值:   无
**说    明:   请求对指定的IP地址进行解析,获取其物理地址
************************************************************************/
void Arp_Request(unsigned long ip_address)
{
  unsigned char i;
  TxdNetBuff.EtherFrame.NextProtocal=0x0806;      //以太网协议的下层协议为arp协议
  for(i=0;i<3;i++)                                //复制对方网卡地址或网关地址
  {
    TxdNetBuff.EtherFrame.DestMacId[i]=0xffff;    //以太网报文的目的物理地址为广播地址                                                
    TxdNetBuff.ArpFrame.SourceMacId[i]=TxdNetBuff.EtherFrame.SourceMacId[i];
    TxdNetBuff.ArpFrame.DestMacId[i]=0x0000;      //arp报文的目的物理地址填为0,由arp回答报文
                                                  //负责填充
  }
  for(i=0;i<2;i++)                                //填充源IP地址
  {
    TxdNetBuff.ArpFrame.SourceIp[i]=My_Ip_Address.words[i];
  }
  TxdNetBuff.ArpFrame.DestId[0]=ip_address>>16;   //填充目的IP地址
  TxdNetBuff.ArpFrame.DestId[1]=ip_address&0xffff;
  TxdNetBuff.ArpFrame.HardwareType=0x0001;        //硬件类型:0x0001,以太网类型
  TxdNetBuff.ArpFrame.ProtocalType=0x0800;        //协议类型:0x0800,对应IPv4
  TxdNetBuff.ArpFrame.HardwareLen=0x06;           //硬件长度:即物理地址长度,单位字节
  TxdNetBuff.ArpFrame.ProtocalLen=0x04;           //协议长度:即逻辑地址长度,单位字节
  TxdNetBuff.ArpFrame.Operation=0x0001;           //操作类型:ARP请求
/*******************************************************
 *注意:    
 *arp报文段的长度为28字节,而以太网数据包的最小单元为60字节,所以在发送arp报文时需要对
 *以太网报文段进行填充,以满足最小长度要求.
 *arp分组的封装格式:
 *发送报文:               |     以太网首部(共14字节)    |    arp请求分组(28字节)  | 填充数据 |       
 *接收报文: | RTL8019首部 |     以太网首部(共14字节)    |    arp回答分组(28字节)  | 填充数据 |
 *          |--> 4字节 <--|------->   14字节    <-------|-------> 28字节 <--------|->18字节<-|                   
 *          |--------------------------->0x00~0x<2e<-----------------------------|                                 
 *实际上4字节的8019首部在发送时是不起作用的,真正发送的数据从以太网首部起.所以在填充数据时,是从0x2e开始的.
 *因为程序中将发送数据报数据结构与接收数据报数据结构定义于公用体中,方便操作.关于数据结构定义
 *可以参看ne2000.h,以及相应的文档说明.
 ******************************************************/
  for(i=0x2e;i<(0x2e+18);i++)                    //当数据长度<60字节时,需要补足60字节数据
  {
    TxdNetBuff.bytes.bytebuf[i]=0x00;            //填充数据为0x00
  }
  Send_Packet(&TxdNetBuff,60);                   //启动发送数据,发送的是一个arp请求.
}

//===========================================================
/**********************************************************************
**函数原型:    void  Arp_Answer( )
**入口参数:    无
**出口参数:    无
**返 回 值:   无
**说    明:   对ARP请求报文的应答:填充本地物理地址,将ARP操作改为回答.
************************************************************************/
void Arp_Answer()
{
  unsigned char i;
  if (RxdNetBuff.ArpFrame.DestId[0]==My_Ip_Address.words[0])
  if (RxdNetBuff.ArpFrame.DestId[1]==My_Ip_Address.words[1])
  {                          //表示是要解析本地IP的请求
    for(i=16;i<64;i++)
    {                        //将接收的ARP数据从协议字段开始复制到发送缓冲区
        TxdNetBuff.bytes.bytebuf[i]=RxdNetBuff.bytes.bytebuf[i];
    }
    for(i=0;i<3;i++)
    {                        //复制对方物理地址或网关地址
        TxdNetBuff.EtherFrame.DestMacId[i]=RxdNetBuff.EtherFrame.SourceMacId[i];
        TxdNetBuff.ArpFrame.SourceMacId[i]=TxdNetBuff.EtherFrame.SourceMacId[i];
        TxdNetBuff.ArpFrame.DestMacId[i]=RxdNetBuff.ArpFrame.SourceMacId[i];
    }
    for(i=0;i<2;i++)         //复制对方IP地址,填充源地址
    {
        TxdNetBuff.ArpFrame.DestId[i]=RxdNetBuff.ArpFrame.SourceIp[i];
        TxdNetBuff.ArpFrame.SourceIp[i]=RxdNetBuff.ArpFrame.DestId[i];
    }
    TxdNetBuff.ArpFrame.Operation=0x0002;    //表明数据帧为ARP应答
    Send_Packet(&TxdNetBuff,60);
  }
}
/**********************************************************************
**函数原型:    void Gateway_Arp_Request( )
**入口参数:    无
**出口参数:    无
**返 回 值:   无
**说    明:   在主程序中定时对网关地址进行解析
************************************************************************/
void Gateway_Arp_Request()                    //在每分钟的前三秒对网关地址进行解析  
{
  if(Sec<3)                                  
  if(Gateway_Ip_Address.bytes[0]!=0)          //网关地址已解析
  if(Gateway_IP_TTL<5)                
    {Arp_Request(Gateway_Ip_Address.dwords);} //在网关地址生存时间<5时,重新解析
}

extern xdata    uchar   ComRxdBuf[];          //串口的接收缓冲区
extern xdata    uchar   ComTxdBuf[];          //串口的发送缓冲区
extern xdata    union   Netcard  RxdNetBuff;  //数据接收缓冲区
extern xdata    union   Netcard  TxdNetBuff;  //数据发送缓冲区

//============================================================
/**********************************************************************
**函数原型:    void Arp_Process( )
**入口参数:    无
**出口参数:    无
**返 回 值:   无
**说    明:   对ARP应答数据的处理
************************************************************************/
void Arp_Process()
{
  uchar i;
//======================================================================
  if(RxdNetBuff.ArpFrame.SourceIp[0]==Gateway_Ip_Address.words[0])
  if(RxdNetBuff.ArpFrame.SourceIp[1]==Gateway_Ip_Address.words[1])
  {                         //表示是网关对ARP请求的回答.
      for (i=0;i<3;i++)
      {
          Gateway_MAC.words[i]=RxdNetBuff.ArpFrame.SourceMacId[i];
      }
      Gateway_IP_TTL=10;    //表示网关地址已得到解析
  }
//=======================================================================
  if(RxdNetBuff.ArpFrame.SourceIp[0]==Ping_Ip_Address.words[0])
  if(RxdNetBuff.ArpFrame.SourceIp[1]==Ping_Ip_Address.words[1])
  {                         //表示是ping的ip地址的回答.
      for (i=0;i<3;i++)
      {
          Ping_MAC.words[i]=RxdNetBuff.ArpFrame.SourceMacId[i];
      }
      Ping_IP_TTL=10;       //给Ping_IP_TTL赋值,表明所ping的IP地址已得到解析
  }
}
//===========================================================================

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -