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

📄 ip_udp.c

📁 AVR单片机基础上的以太网协议编程
💻 C
字号:
/**************************************************************************
**
**    文件: IP_UDP.c
**    描述: 该文件完成该文件完成与IP/UDP协议相关的报文的收发
**
**************************************************************************/

//include library files
#include <stdio.h>
#include <string.h>
#include <iom128v.h>

//include user defined files
#include "Define.h"
#include "Global_Variable.h"
#include "Extern_Function.h"
#include "IP_UDP.h"

static uchar Req_MAC[6]={0x00,0x00,0x00,0x00,0x00,0x00}; //ARP请求的MAC地址
static uchar *Req_IP;    //ARP请求的IP地址
static uint IP_Seq=0;    //IP标识,即发送第几个IP报文
static uint ICMP_Seq=0;  //Ping序号,即第几个Ping包
uchar ARP_Ed=FALSE;      //是否接收到ARP应答的标志
uchar Ping_Ed=FALSE;     //是否接收到Ping应答的标志

/**************************************************************************
**
**    函数: void Make_Ether_Header(uchar *,uchar *,uint)
**    描述: 该函数完成以太网头的构造,入口参数分别为目标MAC、源MAC、帧类型
**
**************************************************************************/
void Make_Ether_Header(uchar *dhost,uchar *shost,uint type)
{
    memcpy(S_Ehe->Ether_Dest_MAC,dhost,6);
    memcpy(S_Ehe->Ether_Sour_MAC,shost,6);
    S_Ehe->Ether_Type=htons(type);//变字节序,将一个16位数从主机字节顺序转换成网络字节顺序
}

/**************************************************************************
**
**    函数: uint Check_Sum(uint *,uint)
**    描述: 该函数用于计算校验和,入口参数为待校验的数据首地址和数据长度,返回校验值
**
**************************************************************************/
uint Check_Sum(uint *data,uint nbytes)
{
    uint index;
    ulong sum=0;
    
	for(;nbytes>1;nbytes-=2)
    {
	    sum+=*(data++);
	    if(sum&0x80000000)
	    sum=(sum&0xffff)+(sum>>16);
    }
    if(nbytes==1)
    {
	    index=0;
	    *(uchar *)(&index)=*(uchar *)data;
	    sum+=index;
    }
    while(sum>>16)
    sum=(sum&0xffff)+(sum>>16);
    return (sum==0xffff)?sum:~sum;
}

/**************************************************************************
**
**    函数: void Send_ARP_REQ(uchar *)
**    描述: 该函数完成ARP请求报文的发送,入口参数为ARP请求的IP地址
**
**************************************************************************/
void Send_ARP_REQ(uchar *ip)
{
    ulong *remip,*locip,*msk;
 
    remip=(ulong *)ip;
    locip=(ulong *)My_IP;
    msk=(ulong *)Mask;
    Req_IP=(((*remip^*locip)&*msk)==0)?ip:Gate; //判断是否属于同一个子网
	 
    Make_Ether_Header(Bro_MAC,My_MAC,Ether_Type_ARP);
	
    S_Arp->ARP_Net_Type=htons(1);             //以太网为0x0001
	S_Arp->ARP_Protocol=htons(Ether_Type_IP); //要转换的协议类型,IP协议为0x0800
    S_Arp->ARP_MAC_Len=6;                     //MAC地址字节长度为0x06
    S_Arp->ARP_IP_Len=4;                      //IP地址字节长度为0x04
    S_Arp->ARP_Operator=htons(ARP_REQ);       //操作类型ARP_REQ=0x0001,ARP_ACK=0x0002
    memcpy(S_Arp->ARP_Sour_MAC,My_MAC,6);     //发送方MAC地址
    memcpy(S_Arp->ARP_Sour_IP,My_IP,4);       //发送方IP地址
    memcpy(S_Arp->ARP_Dest_MAC,Req_MAC,6);    //接收方MAC地址
    memcpy(S_Arp->ARP_Dest_IP,Req_IP,4);      //接收方IP地址
 
    //ARP请求报文打包结束,作为优先级为1的非周期报文传给EPA_CSME
	EPA_CSME(sizeof(struct Ether_Header)+sizeof(struct ARP));
}

/**************************************************************************
**
**    函数: void Send_ARP_ACK(uint)
**    描述: 该函数完成ARP应答报文的发送,入口参数为接收到的包的长度
**
**************************************************************************/
void Send_ARP_ACK(uint packetlen)
{
    memcpy(Send_Buf,Rece_Buf,packetlen); //利用ICMP请求构造ICMP应答
  
    memcpy(S_Ehe->Ether_Dest_MAC,S_Ehe->Ether_Sour_MAC,6);
    memcpy(S_Ehe->Ether_Sour_MAC,My_MAC,6);
	
	S_Arp->ARP_Operator=htons(ARP_ACK);               //操作类型ARP_REQ=0x0001,ARP_ACK=0x0002
    memcpy(S_Arp->ARP_Dest_MAC,S_Arp->ARP_Sour_MAC,6);//接收方MAC地址
    memcpy(S_Arp->ARP_Dest_IP,S_Arp->ARP_Sour_IP,4);  //接收方IP地址
	memcpy(S_Arp->ARP_Sour_MAC,My_MAC,6);             //发送方MAC地址
    memcpy(S_Arp->ARP_Sour_IP,My_IP,4);               //发送方IP地址
 
    EPA_CSME(packetlen);  //ARP应答报文打包结束,作为优先级为1的非周期报文传给EPA_CSME
}

/**************************************************************************
**
**    函数: void Receive_ARP(uint)
**    描述: 该函数完成ARP报文的接收,入口参数为接收到的包的长度
**
**************************************************************************/
void Receive_ARP(uint len)
{
    if(memcmp(R_Arp->ARP_Dest_IP,My_IP,4)==0)           //ARP报文是在呼叫自己
    {
        if((ntohs(R_Arp->ARP_Net_Type)==1)&&(ntohs(R_Arp->ARP_Protocol)==Ether_Type_IP)) //以太网且为IP协议                                       
        {
	        if(ntohs(R_Arp->ARP_Operator)==ARP_REQ)      //处理ARP请求 
            Send_ARP_ACK(len);
            else if(ntohs(R_Arp->ARP_Operator)==ARP_ACK) //处理ARP应答 
            {
		       if(memcmp(R_Arp->ARP_Sour_IP,Req_IP,4)==0)//发送方IP与一开始本地发送的IP请求地址一致 
               {
			       memcpy(Dest_MAC,R_Arp->ARP_Sour_MAC,6);  //将获得的MAC地址拷贝 
                   ARP_Ed=TRUE;
               }
            }
	    }
    }
}

/**************************************************************************
**
**    函数: void Send_IP(uchar *,uchar *,uint,uchar,uchar,uchar)
**    描述: 该函数完成IP报文的发送,入口参数为目的MAC、目的IP、数据长度、上层协议、服务类型、生存时间
**
**************************************************************************/
void Send_IP(uchar *dmac,uchar *dip,uint datalen,uchar pro,uchar tos,uchar ttl)
{
    uint type=0,packetlen=0;
	
	if(memcmp(dmac,Bro_MAC,6)!=0 && ARP_Ed==FALSE)    //还未收到正确的ARP响应
    {
	    Send_ARP_REQ(dip);
        while(ARP_Ed==FALSE)
        {
            if((packetlen=Receive_Packet(Rece_Buf))>0)
            {	       
	            Set_R_Pointer();
			    type=ntohs(R_Ehe->Ether_Type);
                if(type==Ether_Type_ARP)
                Receive_ARP(packetlen);
		        else if(type==Ether_Type_IP)
		        Receive_IP(packetlen);           
            }
        }
	}
    
	Make_Ether_Header(dmac,My_MAC,Ether_Type_IP);
		 
    IP_Seq++;  //IP标识加1
	S_Pip->IP_VerLen=(IP_Version<<4)|(IP_Header_MinLen>>2);//IP版本以及头长度
    S_Pip->IP_Tos=tos;                                //服务类型
    S_Pip->IP_Len=htons(IP_Header_MinLen+datalen);    //除去以太网头的包的总长度
    S_Pip->IP_ID=htons(IP_Seq);                       //IP标识
    S_Pip->IP_FlagOffset=htons(0);                    //标志及片偏移
    S_Pip->IP_TTL=ttl;                                //IP数据报的生存时间,通常用可经过的最大路由器数来表征
    S_Pip->IP_Protocol=pro;                           //上层协议标识,1为ICMP,6为TCP,17为UDP
    S_Pip->IP_Check=0;                                //头部校验和
	memcpy(S_Pip->IP_Sour_IP,My_IP,4);                //IP源地址
    memcpy(S_Pip->IP_Dest_IP,dip,4);                  //IP目标地址
	S_Pip->IP_Check=Check_Sum((uint *)S_Pip,IP_Header_MinLen);
    
    EPA_CSME(IP_Header_MinLen+datalen+sizeof(struct Ether_Header)); //UDP/IP封装结束,传给EPA_CSME
}

/**************************************************************************
**
**    函数: void Receive_IP(uint)
**    描述: 该函数完成IP报文的接收,入口参数为接收到的包的总长度
**
**************************************************************************/
void Receive_IP(uint len)
{
    if(((R_Pip->IP_VerLen>>4)==IP_Version)&&((memcmp(R_Pip->IP_Dest_IP,My_IP,4)==0)\
    ||(memcmp(R_Pip->IP_Dest_IP,Bro_IP,4)==0)))           //接收到正确的IP报文
    {
	    if(ARP_Ed==FALSE)
        {
		    memcpy(Dest_MAC,R_Ehe->Ether_Sour_MAC,6);
            ARP_Ed=TRUE;
        }
	    if(Check_Sum((uint *)R_Pip,IP_Header_Len)==0xffff)//校验值正确
        {
		    switch(R_Pip->IP_Protocol)
            {
			    case IP_ICMP:Receive_ICMP(len);break;
                //case IP_TCP:Receive_TCP();break;
                case IP_UDP:Receive_UDP();break;
                default:break;
            }
        }
    }
}

/**************************************************************************
**
**    函数: void Send_ICMP_REQ(uchar *)
**    描述: 该函数完成ICMP请求报文的发送,入口参数为ICMP请求的IP地址
**
**************************************************************************/
void Send_ICMP_REQ(uchar *ip)
{
    uint i;
    
	ICMP_Seq++;                          //ICMP标识加1
    S_Pic->ICMP_Type=ICMP_Type_REQ;
    S_Pic->ICMP_Code=0;
	S_Pic->ICMP_Check=0;
    S_Pic->ICMP_ID=htons(0);             //多个Ping请求时,用于识别与所发送的报文相对应的应答
    S_Pic->ICMP_Sequence=htons(ICMP_Seq);//记录发送端的ICMP报文序号
    for(i=0;i<ICMP_Num;i++)
    S_Pic->ICMP_Data[i]=(uchar)(i%23+'a'); //测试数据
	S_Pic->ICMP_Check=Check_Sum((uint *)S_Pic,sizeof(struct ICMP));
	
    Send_IP(Dest_MAC,ip,sizeof(struct ICMP),IP_ICMP,IP_Tos_Value,IP_TTL_Value);
}

/**************************************************************************
**
**    函数: void Send_ICMP_ACK(uint)
**    描述: 该函数完成ICMP应答报文的发送,入口参数为接收到的ICMP请求的包长度
**
**************************************************************************/
void Send_ICMP_ACK(uint packetlen)
{
    memcpy(Send_Buf,Rece_Buf,packetlen); //利用ICMP请求构造ICMP应答
  
    memcpy(S_Ehe->Ether_Dest_MAC,S_Ehe->Ether_Sour_MAC,6);
    memcpy(S_Ehe->Ether_Sour_MAC,My_MAC,6);
	
    memcpy(S_Pip->IP_Dest_IP,S_Pip->IP_Sour_IP,4);
    memcpy(S_Pip->IP_Sour_IP,My_IP,4);
    S_Pip->IP_Check=0;
    S_Pip->IP_Check=Check_Sum((uint *)S_Pip,IP_Header_Len);
 
    S_Pic->ICMP_Type=ICMP_Type_ACK;
    S_Pic->ICMP_Check=0;
    S_Pic->ICMP_Check=Check_Sum((uint *)S_Pic,packetlen-sizeof(struct Ether_Header)-IP_Header_Len);
	
    EPA_CSME(packetlen);  //Ping应答报文打包结束,作为优先级为4的非周期报文传给EPA_CSME
}

/**************************************************************************
**
**    函数: void Receive_ICMP(uint)
**    描述: 该函数完成ICMP报文的接收,入口参数为接收到的ICMP包长度
**
**************************************************************************/
void Receive_ICMP(uint packetlen)
{
    if(Check_Sum((uint *)R_Pic,packetlen-sizeof(struct Ether_Header)-IP_Header_Len)==0xffff)//收到正确的ICMP报文
    {
	    switch(R_Pic->ICMP_Type) 
        {
	        case ICMP_Type_REQ:Send_ICMP_ACK(packetlen);break; //收到Ping请求,发Ping应答
            case ICMP_Type_ACK:Ping_Ed=TRUE;break;             //收到Ping应答,置标志位
            default:break;
        }
    }
}

/**************************************************************************
**
**    函数: void Send_UDP(uchar *,uchar *,uint,uint,uint)
**    描述: 该函数完成UDP报文的发送,入口参数为目标MAC、目标IP、源端口、目的端口、数据长度
**
**************************************************************************/
void Send_UDP(uchar *fmac,uchar *fip,uint sport,uint dport,uint datalen)
{
    S_Pdp->UDP_Sour_Port=htons(sport);
    S_Pdp->UDP_Dest_Port=htons(dport);
    S_Pdp->UDP_Len=htons(UDP_Header_Len+datalen);
    S_Pdp->UDP_Check=0;
    S_Pdp->UDP_Check=Check_Sum((uint *)S_Pdp,UDP_Header_Len+datalen);
	
    Send_IP(fmac,fip,UDP_Header_Len+datalen,IP_UDP,IP_Tos_Value,IP_TTL_Value);
} 

/**************************************************************************
**
**    函数: void Receive_UDP(void)
**    描述: 该函数完成UDP报文的接收
**
**************************************************************************/
void Receive_UDP(void)
{
    if(Check_Sum((uint *)R_Pdp,ntohs(R_Pdp->UDP_Len))==0xffff) //收到正确的UDP报文
	    Socket_Depacket(); //传给EPA套接字映射接口    
}

/******************* End Of File **********************/

⌨️ 快捷键说明

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