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

📄 icmp.c

📁 51单片机上实现tcp/ip的源代码
💻 C
字号:
/*********************************************************************
 *            Copright(c) 2004,张会福 湖南科技大学计算机学院 
 *                        All rights reserved.
 *
 *文件名称:    icmp.c
 *文件标识: 
 *摘    要: 测试主机的可达性,其中主要的操作是ping
 *
 *当前版本: V1.0
 *完成日期: 2004.4.10
 *
 *
 *********************************************************************/
#define  ICMP_GLOBALS
#include "net_cfg.h"

/**********************************************************************
**函数原型:    void Ping_Request( )
**入口参数:    无
**出口参数:    无
**返 回 值:    无
**说    明:    发送PING请求报文,测试对方主机的可达性
************************************************************************/
void Ping_Request()
{
    TxdNetBuff.EtherFrame.DestMacId[0]=Ping_MAC.words[0];   //填充以太网协议目的物理地址字段
    TxdNetBuff.EtherFrame.DestMacId[1]=Ping_MAC.words[1];  
    TxdNetBuff.EtherFrame.DestMacId[2]=Ping_MAC.words[2];  
    TxdNetBuff.EtherFrame.NextProtocal=0x0800;              //以太网协议的下层协议为IP协议
    TxdNetBuff.IpFrame.VerandIphLen=0x45;                   //IP版本和首部长度各占VerandIphLen字段的4位,版本4,占用高4位
                                                            //首部长度5*4=20,单位字节
    TxdNetBuff.IpFrame.ServerType=0x00;                     //服务类型,默认为0
    TxdNetBuff.IpFrame.TotalLen=60;                         //IP数据报总长度40字节,其中由总长度
                                                            //减去首部长度即可得数据报长度
    TxdNetBuff.IpFrame.ttl=0x80;                            //IP生存时间
    TxdNetBuff.IpFrame.FrameIndex=FrameIndex;               //帧序号
    FrameIndex++;                                           //
    TxdNetBuff.IpFrame.Segment=0x0000;                      //标志及段偏移都为0
    TxdNetBuff.IpFrame.NextProtocal=0x0001;                 //IP的下层协议为ICMP协议:TCP 
    TxdNetBuff.IpFrame.Crc=0;                                           
    TxdNetBuff.IpFrame.DestId[0]=Ping_Ip_Address.words[0];  //填充目的IP地址
    TxdNetBuff.IpFrame.DestId[1]=Ping_Ip_Address.words[1];
    TxdNetBuff.IpFrame.SourceIp[0]=My_Ip_Address.words[0];  //填充源IP地址
    TxdNetBuff.IpFrame.SourceIp[1]=My_Ip_Address.words[1];
    TxdNetBuff.IpFrame.Crc=CreateIpHeadCrc();               //产生IP数据报首部检验和,CreateIpHeadCrc()在global.c中定义
    TxdNetBuff.IcmpFrame.type=0x08;                         //表示该ICMP数据帧为PING请求                  
    TxdNetBuff.IcmpFrame.Crc=0;                                         
    TxdNetBuff.IcmpFrame.id=0x0300;                         //标识符
    TxdNetBuff.IcmpFrame.seq=FrameIndex;                    //ICMP报文序号
    TxdNetBuff.IcmpFrame.Crc=CreateIcmpCrc();               //产生ICMP报文的校验和,CreatIcmpCrc()在global.c中定义
    Send_Packet(&TxdNetBuff,74);                            //发送数据包
}
//==========================================================
/**********************************************************************
**函数原型:        void Ping_Answer( )
**入口参数:        无
**入口参数:        无
**返 回 值:        无
**说    明:        PING应答,与PING请求一起用来测试一个主机地可达性.PING的回答
**********:        是将PING请求报文的源物理地址和目的物理地址互换,源IP地址和
**********:        目的IP地址互换,将ICMP操作类型字段换为回答,并且将PING请求
**********:        报文中的选项数据(32字节)原封不动的发回.
************************************************************************/
void Ping_Answer()
{
  uchar i;
  if(RxdNetBuff.IcmpFrame.type==0x08)//表示是ping请求
  {                                  
      for (i=16;i<RxdNetBuff.EtherFrame.length;i++)
        //从以太网协议开始复制数据到发送缓冲区
        /*  发送以太网数据帧格式如下
         *  | 目的物理地址 | 源物理地址   | 以太网协议 | 数  据  报  |
         *        6字节         6字节          2字节     46~1500字节
         *
         *  |  RTL8019 首部| 目的物理地址 | 源物理地址 | 以太网协议 | 数  据  报  |
         *        4字节         6字节         6字节        2字节     46~1500字节
         *                                             |------->
         *                                             |从此处开始复制接收到的数据报
         *因此在利用接收的数据拼装数据报时,一定要注意RTL8019自动地在接收数据报中添加
         *了4字节的首部数据,在global.c文件的以太网驱动底层数据接收程序中也有详细说明.
         */
      {
          TxdNetBuff.bytes.bytebuf[i]=RxdNetBuff.bytes.bytebuf[i];//将数据复制到发送缓冲区
      }                            
        //复制接收数据报的源物理地址到发送数据报的目的物理地址字段中
      TxdNetBuff.EtherFrame.DestMacId[0]=RxdNetBuff.EtherFrame.SourceMacId[0];
      TxdNetBuff.EtherFrame.DestMacId[1]=RxdNetBuff.EtherFrame.SourceMacId[1];
      TxdNetBuff.EtherFrame.DestMacId[2]=RxdNetBuff.EtherFrame.SourceMacId[2];
      TxdNetBuff.IpFrame.ttl=TxdNetBuff.IpFrame.ttl-1;           //IP数据包寿命减1
      TxdNetBuff.IpFrame.Crc=0;
      TxdNetBuff.IpFrame.DestId[0]=RxdNetBuff.IpFrame.SourceIp[0];//复制源IP地址到目的IP地址字段中        
      TxdNetBuff.IpFrame.DestId[1]=RxdNetBuff.IpFrame.SourceIp[1];    
      TxdNetBuff.IpFrame.SourceIp[0]=My_Ip_Address.words[0];      //填充源IP地址
      TxdNetBuff.IpFrame.SourceIp[1]=My_Ip_Address.words[1];        
      TxdNetBuff.IpFrame.Crc=CreateIpHeadCrc();                   //创建IP头校验和                
      TxdNetBuff.IcmpFrame.type=0x00;                             //操作类型:ICMP应答            
      TxdNetBuff.IcmpFrame.Crc=0;                        
      for(i=21;i<41;i++)                  //将接收缓冲区40字节的ICMP数据复制到发送缓冲区中
      {
          TxdNetBuff.words.wordbuf[i]=RxdNetBuff.words.wordbuf[i];    
      }
      TxdNetBuff.IcmpFrame.Crc=CreateIcmpCrc();
      Send_Packet(&TxdNetBuff,RxdNetBuff.EtherFrame.length);
  }
}
//==========================================================
/**********************************************************************
**函数原型:   void  Ping_Echo( )
**入口参数:   无
**出口参数:   无
**返 回 值:   无
**说    明:   接收到PING应答数据后,在本地机通过串口回显信息
************************************************************************/
void Ping_Echo()
{
  union Ip_Address_Type ip;
  
  ip.words[0] = RxdNetBuff.IpFrame.SourceIp[0];
  ip.words[1] = RxdNetBuff.IpFrame.SourceIp[1];
  Printf_String(" \r\nReply From IP=");
  Printf_IPStr(ip);
  Printf_String("   Bytes=32   ");
  Printf_String("TTL=");
  Printf_Hex(RxdNetBuff.IpFrame.ttl);
}
//===========================================================
/**********************************************************************
**函数原型:    void Process_Ping( )
**入口参数:    无
**出口参数:    无
**返 回 值:   无
**说    明:   对PING数据包进行处理
************************************************************************/
void Process_Ping()
{
  if(Ping_Count>0)
  {
      Ping_Count--;
      if(Ping_Count>0)
      {
          if((Ping_IP_TTL>0)||(Gateway_IP_TTL>0))
          //ARP请求发送后,ARP回答会对请求分组中的IP地址进行解析,并设置全局变量的值
          //如果是对网关的解析则将Gateway_IP_TTL的值置为10;若是对某一主机IP的解析则
          //将Ping_IP_TTL的值置为10.
          {                        //表示ip地址已经解析
               //Printf_String("\r\nSend Ping Request...");
               Ping_Request();                    //发送PING请求
          }
          else
          {                         //IP地址还没有解析
               //Printf_String("\r\nSend ARP Request...\r\n  ");
               Arp_Request(Ping_Ip_Address.dwords);        //发送ARP请求,对IP地址进行解析
          }
          if(Ping_Ip_Address.dwords==My_Ip_Address.dwords)    //ping的是自己的ip地址
          {
               Printf_String("\r\nReply From IP=");        //显示信息
               Printf_IPStr(My_Ip_Address);
               Printf_String("   Bytes=32   ");
               Printf_String("TTL=10");
          }

      }//if(Ping_Count>0)
      if(Ping_Count==0)                        
      {
          if(((Ping_Ip_Address.dwords!=My_Ip_Address.dwords)&(Ping_IP_TTL == 0))
                     ||((Ping_Ip_Address.dwords=Gateway_Ip_Address.dwords)&(Gateway_IP_TTL==0)))
              Printf_String("\r\nRequest Timed out.\r\n");
        
          Printf_String("\r\nPing Command Finished.\r\n");
          Ping_IP_TTL=0;
      }
  }
}

⌨️ 快捷键说明

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