www.pudn.com > TcpIpOn8051.rar > IP.C


/*------------------------------------------------------------------------------ 
ip.C 
 
 
------------------------------------------------------------------------------*/ 
#include "public.h" 
#include "ether.h" 
#include "arp.h" 
#include "ip.h" 
 
static WORD xdata IDENT;				//标识 
WORD xdata OSET;						//偏移量 
 
netcard xdata revbuffer; 
netcard xdata sendbuffer[2]; 
 
BYTE xdata arp_sennum;					//the number of sended arp request 
extern bit arp_flag; 
extern BYTE arp_count; 
extern void print(char str[]); 
					 
ippack_senflag xdata ipsenflag[2]; 
arpreqbuf xdata arp_reqflag[2]; 
mycomp xdata mypara; 
 
extern arp_entry xdata arp_gate;      	//默认网关 
extern arp_entry xdata arp_table[10]; 	//arp表 
 
fragbuffer xdata frag_buf[NFRAGS];             // Fragment buffer 
 
WORD csum(void *dp, WORD count); 
WORD mindata(WORD a, WORD b); 
void move_up(void *destaddr,void *srcaddr,WORD len); 
bit is_local(ip p); 
bit ip_look_mac(ip *ipaddr,WORD *macaddr); 
bit ip_send_pack(netcard *netbuf,BYTE bufnum,ip destip,BYTE pcol,WORD len); 
void ip_send(netcard *netbuf,ip destip,WORD *macaddr,BYTE pcol,WORD dlen); 
BYTE ip_deal_pack(netcard *netbuf); 
void icmp_send(netcard *netbuf,ip destip,BYTE type,BYTE icode,WORD ident,WORD seq,WORD len); 
void icmp_reply(netcard *netbuf,WORD len); 
bit icmp_deal_pack(netcard *netbuf); 
BYTE deal_packet(netcard *rxdnet); 
WORD ip_defrag(netcard *netbuf,WORD dlen); 
 
extern DWORD get_current(); 
extern void send_packet(netcard *txdnet,WORD length); 
extern bit recv_packet(netcard *rxdnet); 
extern bit arp_deal_pack(netcard *netbuf); 
extern void arp_update(ip *ipaddr,WORD *macaddr); 
extern void arp_request(ip *destip); 
extern BYTE arp_lookup(ip *ipaddr); 
extern void tcp_deal_pack(netcard *netbuf); 
/*--------------------------- 
 ip init 
 ----------------------------*/ 
void ip_init(void) 
{ 
	ipsenflag[0].flag=0; 
	ipsenflag[1].flag=0; 
	arp_reqflag[0].flag=0; 
	arp_reqflag[0].arpsenf=0; 
	arp_reqflag[1].flag=0; 
	arp_reqflag[1].arpsenf=0; 
} 
/*--------------------------- 
 计算校验和(直接相加,校验和需取反) 
 ----------------------------*/ 
WORD csum(void *dp, WORD count) 
{ 
    register DWORD total=0; 
    register WORD n, *p, carries; 
 
    n = count / 2; 
    p = (WORD *)dp; 
    while (n--) 
        total += *p++; 
    if (count & 1) 
	{ 
		n=*(BYTE *)p; 
        total +=n<<8; 
	} 
    while ((carries=(WORD)(total>>16))!=0) 
        total = (total & 0xffff) + carries; 
    return((WORD)total); 
} 
/*----------------------------------------- 
返回最小值 
------------------------------------------*/ 
 
WORD mindata(WORD a, WORD b) 
{ 
    return(a=ipsenflag[i].ttl) 
				ipsenflag[i].flag=0; 
	} 
 
	for(i=0;i<2;i++) 
	{ 
		if(arp_reqflag[i].flag==1) 
			if((WORD)(time-arp_reqflag[i].starttime)>=arp_reqflag[i].ttl) 
			{ 
				arp_reqflag[i].arpsenf=1; 
				//update task flag 
			} 
	}	 
} 
/*----------------------------- 
 if arp_dealpack receive a mac 
 look ip send buffer 
-----------------------------*/ 
void ip_updatebuf(ip destip) 
{ 
	register BYTE i; 
	bit index; 
	WORD macaddr[3]; 
 
	for(i=0;i<2;i++)										//update arp buffer 
	{ 
		if(arp_reqflag[i].destip==destip) 
			arp_reqflag[i].flag=0; 
	} 
 
	for(i=0;i<2;i++){										//update ip buffer 
		if(ipsenflag[i].flag==1) 
		{ 
			index=is_local(ipsenflag[i].dest_ip); 
			if(index==1 && destip==mypara.mygate)			//外网ip 
			{ 
				macaddr[0]=arp_gate.hw_addr[0]; 
				macaddr[1]=arp_gate.hw_addr[1];//目的地址 
				macaddr[2]=arp_gate.hw_addr[2]; 
				ipsenflag[i].flag=0; 
				ip_send(ipsenflag[i].net_buf,ipsenflag[i].dest_ip,&macaddr[0],ipsenflag[i].p_col,ipsenflag[i].lenn); 
				OSET=0; 
			} 
			else if(index==0 && destip==ipsenflag[i].dest_ip) 
			{ 
				index=ip_look_mac(&destip,&macaddr[0]);			 
				arp_update(&destip,&macaddr[0]); 
				ipsenflag[i].flag=0; 
				ip_send(ipsenflag[i].net_buf,ipsenflag[i].dest_ip,&macaddr[0],ipsenflag[i].p_col,ipsenflag[i].lenn); 
				OSET=0; 
			} 
		} 
	} 
} 
/*------------------------------------------- 
ip send function 
--------------------------------------------*/ 
bit ip_send_pack(netcard *netbuf,BYTE bufnum,ip destip,BYTE pcol,WORD len) 
{ 
	register BYTE i; 
	bit rez=0; 
	bit index; 
	WORD macaddr[3]; 
 
	index=is_local(destip); 
	if(index==0){										//local ip 
		index=ip_look_mac(&destip,&macaddr[0]);			 
		if(index==1) 									//exit mac in arp_table 
		{ 
			arp_update(&destip,&macaddr[0]); 
			// 
			ipsenflag[bufnum].flag=0; 
			ip_send(netbuf,destip,&macaddr[0],pcol,len); 
			OSET=0; 
			rez=1; 
		} 
		else  
		{ 
			//update ip send buffer 
			for(i=0;i<2;i++){ 
				if(ipsenflag[i].flag==0) 
				{ 
					ipsenflag[i].flag=1; 
					ipsenflag[i].net_buf=netbuf; 
					ipsenflag[i].buf_num=bufnum; 
					ipsenflag[i].dest_ip=destip; 
					ipsenflag[i].p_col=pcol; 
					ipsenflag[i].lenn=len; 
					ipsenflag[i].starttime=get_current(); 
					ipsenflag[i].ttl=IPBUF_TTL; 
					rez=1; 
					break; 
				} 
				rez=0; 
			} 
		//arpreq 
		ip_arpreq(destip); 
		} 
	} 
	else 												//remote ip 
	{ 
		if(arp_gate.arp_flag!=255)						//exit gate mac 
		{ 
			macaddr[0]=arp_gate.hw_addr[0]; 
			macaddr[1]=arp_gate.hw_addr[1];//目的地址 
			macaddr[2]=arp_gate.hw_addr[2]; 
			//update gate_addr ttl 
			ip_send(netbuf,destip,&macaddr[0],pcol,len); 
			OSET=0; 
			rez=1; 
		} 
		else  
		{ 
			for(i=0;i<2;i++){ 
				if(ipsenflag[i].flag==0) 
				{ 
					ipsenflag[i].flag=1; 
					ipsenflag[i].net_buf=netbuf; 
					ipsenflag[i].buf_num=bufnum; 
					ipsenflag[i].dest_ip=destip; 
					ipsenflag[i].p_col=pcol; 
					ipsenflag[i].lenn=len; 
					ipsenflag[i].starttime=get_current(); 
					ipsenflag[i].ttl=IPBUF_TTL; 
					rez=1; 
					break; 
				} 
				rez=0; 
			} 
		//arpreq 
		ip_arpreq(mypara.mygate); 
		} 
	} 
	return rez; 
	//OSET=0; 
	//ip_send(); 
} 
/*--------------------------------------------- 
发送ip报文 
if return 1,send secess,release buffer 
if return 0,can not find mac,keep and wait 
 ---------------------------------------------*/ 
void ip_send(netcard *netbuf,ip destip,WORD *macaddr,BYTE pcol,WORD dlen) 
{ 
	bit secc=1; 
	ippacket *ip_buf; 
	WORD len,mtu; 
	//netcard xdata net_buf2; 
	//netcard *netbuf2; 
	//netbuf2=&net_buf2; 
 
	ip_buf=(ippacket *)&netbuf->etherframe.packet[0]; 
	ip_buf->i.identification=IDENT;										//标识 
	ip_buf->i.fragment=OSET>>3; 
	mtu=(MAXDATA-sizeof(ipheader)) & 0xfff8; 
	len=mindata(dlen,mtu); 
	ip_buf->i.vershlen=0x45; 
	ip_buf->i.servicetype=0; 
	ip_buf->i.ttl=IP_TTL; 
	ip_buf->i.type=pcol; 
	ip_buf->i.srcip=mypara.myip; 
	ip_buf->i.destip=destip; 
 
	ip_buf->i.totallen=len+sizeof(ipheader); 
	ip_buf->i.checksum=0; 
	ip_buf->i.checksum=~csum((WORD *)&ip_buf->i,sizeof(ipheader)); 
	IDENT++; 
	OSET=0; 
	//make netframe 
	netbuf->etherframe.destnodeid[0]=macaddr[0]; 
	netbuf->etherframe.destnodeid[1]=macaddr[1];//目的地址 
	netbuf->etherframe.destnodeid[2]=macaddr[2]; 
	netbuf->etherframe.protocal=PCOL_IP;//协议类型 
	send_packet(netbuf,ip_buf->i.totallen+DLENGTH);//send ip packet 
	//cal sum 
	//return secc; 
} 
/* 
void ip_send(netcard *netbuf,BYTE *buf,ip destip,WORD *macaddr,BYTE pcol,WORD dlen) 
{ 
	bit secc=1; 
	ippacket *ip_buf; 
	WORD len,sublen=0,mtu; 
	 
	ip_buf=(ippacket *)&netbuf->etherframe.packet[0]; 
	ip_buf->i.identification=IDENT;					//标识 
	ip_buf->i.fragment=OSET>>3; 
 
    ip_buf->i.vershlen=0x45; 
	ip_buf->i.servicetype=0; 
	ip_buf->i.ttl=IP_TTL; 
	ip_buf->i.type=pcol; 
	ip_buf->i.srcip=mypara.myip; 
	ip_buf->i.destip=destip; 
 
    //make netframe 
	netbuf->etherframe.destnodeid[0]=macaddr[0]; 
	netbuf->etherframe.destnodeid[1]=macaddr[1];//目的地址 
	netbuf->etherframe.destnodeid[2]=macaddr[2]; 
	netbuf->etherframe.protocal=PCOL_IP;//协议类型 
 
	mtu=(MAXDATA-sizeof(ipheader)) & 0xfff8; 
	len=mindata(dlen,mtu); 
    //frag or not? 
	while(dlen>len) 
	{ 
	 ip_buf->i.fragment = (OSET>>3)+0x2000;                 // Show there is frag          
	 move_up(&ip_buf->ipdata[0],&buf[OSET],len);       
         
	 ip_buf->i.totallen=len+sizeof(ipheader); 
	 ip_buf->i.checksum=0; 
	 ip_buf->i.checksum=~csum((WORD *)&ip_buf->i,sizeof(ipheader)); 
         OSET+=len; 
         dlen-=len; 
	 
	send_packet(netbuf,ip_buf->i.totallen+DLENGTH);//send ip packet     
        } 
        sublen=dlen; 
        move_up(&ip_buf->ipdata[0],&buf[OSET],sublen); 
        ip_buf->i.fragment=OSET>>3;     
	//ip_buf->i.identification=IDENT;					//标识 
	netbuf->etherframe.length=sublen; 
        ip_buf->i.totallen=sublen+sizeof(ipheader); 
	ip_buf->i.checksum=0; 
	ip_buf->i.checksum=~csum((WORD *)&ip_buf->i,sizeof(ipheader)); 
        ip_buf->i.totallen=sublen+sizeof(ipheader); 
        send_packet(netbuf,ip_buf->i.totallen+DLENGTH);//send sub ip packet 
	IDENT++;   
        OSET=0; 
}*/ 
/*--------------------------- 
function:deal ip packet 
parameter: net buffer ,length 
icmp	:return 1 
udp		:return 2 
tcp		:return 3 
else 	:return 0 
----------------------------*/ 
BYTE ip_deal_pack(netcard *netbuf) 
{ 
	BYTE rez; 
	ippacket *ip_buf; 
	ipheader *ip_head; 
	WORD ver,dlen,hlen,sum,pcol,totallen,len; 
	bit localip; 
	WORD *mac; 
 
	rez=0; 
	len=netbuf->etherframe.length; 
	ip_buf=(ippacket *)netbuf->etherframe.packet; 
	pcol=netbuf->etherframe.protocal; 
	if(pcol==PCOL_IP && len>=sizeof(ipheader)) 
	{ 
		ip_head=(ipheader *)&netbuf->etherframe.packet;			//get pointer to IP frame 
		ver=ip_head->vershlen>>4;								//get IP version & hdr len 
		hlen=(ip_head->vershlen & 0x0f)<<2;						//<<2 means *4 ,byte length 
		totallen=ip_buf->i.totallen;							//byte length 
		sum=~csum((WORD *)&ip_head->vershlen,(WORD)hlen);//checksum 
		if(ver==4 && len>=hlen && sum==0 && ip_head->destip==mypara.myip)//if ok 
		{ 
			if(ip_head->type==PICMP)  
				rez=1; 
			else if(ip_head->type==PUDP)  
				rez=2; 
			else if(ip_head->type==PTCP)  
				rez=3; 
			localip=is_local(ip_head->srcip); 
			if(localip==0)										//local ip 
			{ 
				mac=&netbuf->etherframe.sourcenodeid[0];		//get souce mac addr 
				arp_update(&ip_head->srcip,mac);				//updata arp table 
			} 
			else 												//update gate table 
			{ 
				arp_gate.hw_addr[0]=netbuf->etherframe.sourcenodeid[0]; 
				arp_gate.hw_addr[1]=netbuf->etherframe.sourcenodeid[1]; 
				arp_gate.hw_addr[2]=netbuf->etherframe.sourcenodeid[2]; 
				arp_gate.arp_flag=1; 
			} 
			dlen=ip_buf->i.totallen-hlen; 
			//if exit ip options,delete 
			if(hlen>sizeof(ipheader))							//if exit ip option 
			{ 
				move_up(&ip_buf->ipdata,&ip_buf->ipdata[hlen-sizeof(ipheader)],totallen-hlen);//delete ip option 
				dlen=dlen-(hlen-sizeof(ipheader));				//				 
			} 
			ip_head->vershlen=0x45; 
			ip_head->totallen=dlen+sizeof(ipheader); 
			//frag 
			if((ip_buf->i.fragment & 0x3fff)!=0)				//if a fragment 
				ip_defrag(netbuf,len);							//call deal frag func 
		} 
	} 
	if(rez==1) icmp_deal_pack(netbuf); 
//	else if(rez==2) udp_deal_pack(netbuf); 
	else if(rez==3) tcp_deal_pack(netbuf); 
	return rez; 
} 
/*------------------------------------------------------------------------------- 
function: icmp send,pack the icmp header 
parameter:net buffer,source ip,dest ip,type in icmp header 
			code in icmp header,identifier in icmp header,seq in icmp header 
--------------------------------------------------------------------------------*/ 
void icmp_send(netcard *netbuf,ip destip,BYTE type,BYTE icode,WORD ident,WORD seq,WORD len) 
{ 
	icmppacket *icmp_buf;				//icmppacket have both ipheader and icmpheader 
	WORD sum=0; 
	 
	icmp_buf=(icmppacket *)&netbuf->etherframe.packet; 
	icmp_buf->c.type=type; 
	icmp_buf->c.icode=icode; 
	icmp_buf->c.ident=ident; 
	icmp_buf->c.seq=seq; 
	icmp_buf->c.check=0; 
	sum=~csum((WORD *)&icmp_buf->c,len); 
	icmp_buf->c.check=sum; 
	ip_send_pack(netbuf,0,destip,PICMP,len); 
} 
/*-------------------------------------------------- 
function: icmp reply,change type=0 
parameter:ip buffer , packet length 
---------------------------------------------------*/ 
void icmp_reply(netcard *netbuf,WORD len) 
{ 
	ippacket *ip_buf; 
	icmppacket *icmp_buf; 
	WORD sum; 
	ip tempip; 
 
	ip_buf=(ippacket *)&netbuf->etherframe.packet; 
	icmp_buf=(icmppacket *)ip_buf; 
 
	tempip=ip_buf->i.srcip; 
	ip_buf->i.identification=IDENT; 
	IDENT++; 
	ip_buf->i.srcip=ip_buf->i.destip; 
	ip_buf->i.destip=tempip; 
	ip_buf->i.checksum=0; 
	ip_buf->i.checksum=~csum((WORD *)&ip_buf->i,sizeof(ipheader)); 
 
	netbuf->etherframe.destnodeid[0]=netbuf->etherframe.sourcenodeid[0]; 
	netbuf->etherframe.destnodeid[1]=netbuf->etherframe.sourcenodeid[1]; 
	netbuf->etherframe.destnodeid[2]=netbuf->etherframe.sourcenodeid[2]; 
 
	icmp_buf->c.type=ICREP; 
	icmp_buf->c.check=0; 
	sum=~csum((WORD *)&icmp_buf->c,len); 
	icmp_buf->c.check=sum; 
 
	send_packet(netbuf,ip_buf->i.totallen+DLENGTH); 
 
	//release the received buffer 
} 
/*-------------------------------------------------- 
icmp包处理函数若为ping请求则直接调用ping应答,并返回0 
若为ping应答则返回1 
---------------------------------------------------*/ 
bit icmp_deal_pack(netcard *netbuf) 
{ 
	bit rez=0; 
	ippacket *ip_buf; 
	icmppacket *icmp_buf; 
	WORD sum,dlen,len; 
	 
	ip_buf=(ippacket *)&netbuf->etherframe.packet; 
	len=netbuf->etherframe.length-14; 
	dlen=mindata(ip_buf->i.totallen,len)-sizeof(ipheader); 
	if(ip_buf->i.type==PICMP && dlen>=sizeof(icmpheader)) 
	{ 
		dlen=ip_buf->i.totallen-sizeof(ipheader); 
		icmp_buf=(icmppacket *)ip_buf; 
		sum=~csum((WORD *)&icmp_buf->c,(WORD)dlen); 
		if(sum==0) 
		{ 
			if(icmp_buf->c.type==ICREQ && icmp_buf->c.icode==UNREACH_NET)		//ping request 
			{ 
				#if ICMP_REQ 
				icmp_reply(netbuf,dlen); 
				print("reply from local:202.118.19.173!\n\r"); 
				#endif 
			} 
			else if(icmp_buf->c.type==ICREP && icmp_buf->c.icode==UNREACH_NET)	//ping echo 
			{ 
				rez=1; 
				print("reply from remote:202.118.19.174!\n\r"); 
			} 
		} 
	} 
	return rez; 
} 
/*---------------------------- 
 
----------------------------*/ 
void dealpack_atem(void) 
{ 
	deal_packet(&revbuffer); 
} 
/*--------------------------- 
function: deal received packet 
parameter :net buffer pointer 
arp packet:return 1 
ip packet:return 2 
else :return 0 
 ----------------------------*/ 
BYTE deal_packet(netcard *rxdnet) 
{ 
	//netcard *rxdnet; 
	//netcard xdata rev; 
	arpheader *arpbuf; 
	ipheader *ipbuf; 
	WORD len; 
	bit revb; 
	bit arp_up; 
	BYTE pack_type; 
	pack_type=0; 
	rxdnet=&revbuffer; 
	revb=recv_packet(rxdnet); 
	if(revb==1)                     //接收到正确的数据包 
	{ 
		//revb=0; 
		//P1=P1&0x7f; 
		if(rxdnet->etherframe.protocal==PCOL_ARP) 
		{ 
			arpbuf=(arpheader *)(&rxdnet->etherframe.packet[0]); 
			len=rxdnet->etherframe.length; 
			pack_type=1; 
			arp_up=arp_deal_pack(rxdnet); 
		} 
		else if(rxdnet->etherframe.protocal==PCOL_IP) 
		{ 
			ipbuf=(ipheader *)(&rxdnet->etherframe.packet[0]); 
			len=rxdnet->etherframe.length; 
			pack_type=2; 
			ip_deal_pack(rxdnet); 
		} 
    } 
	return pack_type; 
} 
/*--------------------------- 
function: deal frag packet 
 
 ----------------------------*/ 
WORD ip_defrag(netcard *netbuf,WORD dlen) 
{ 
    int n=0, match=0; 
    WORD oset; 
    fragbuffer *fp, *fp2=0; 
    ippacket *ip_buf; 
	BYTE *data_buf; 
	BYTE xdata data_buffer[3000]; 
 
	data_buf=&data_buffer; 
    ip_buf=(ippacket *)&netbuf->etherframe.packet[0]; 
     
    oset = (ip_buf->i.fragment & 0x1fff) << 3; // Get offset for imcoming frag  
	 
    //匹配过程 
    while (ntries) 
        {                               // ..by checking ident  
            if (!(match = (ip_buf->i.identification==fp->ident && ip_buf->i.srcip==fp->sip))) 
                fp->tries--;            // If no match, reduce attempts left  
        } 
        else 
            fp2 = fp; 
    } 
     
    if (match) 
    {                                   // Matched: check isn't a duplicate  
        if ((oset+dlen == fp->oset || fp->oset+fp->len == oset) && 
            dlen+fp->len <= (MAXIP*2+sizeof(ipheader)))     // ..and length is OK  
        { 
            if (oset)                   // Move old data as necessary  
                 
                move_up(&data_buf[oset],&ip_buf->ipdata[0],dlen); 
 
            ip_buf->i.totallen = dlen += fp->len;   // ..and add in new data  
 
            //move_up(&ip->data[fp->oset], fp->data, fp->len); 
            move_up(&data_buf[fp->oset],&fp->fragdata,(WORD)fp->len); 
 
            fp->tries = 0; 
        } 
        else 
        { 
            match = 0; 
        } 
    } 
    else if (fp2)                       // No match, but there is spare space  
    { 
        fp2->tries = FRAGTRIES;         // Save frag for matching later  
        fp2->ident = ip_buf->i.identification; 
        fp2->sip = ip_buf->i.srcip; 
        fp2->oset = oset; 
        fp2->len = dlen; 
 
        //move_up(fp2->data, ip->data, dlen); 
        move_up(&fp2->fragdata[0],&ip_buf->ipdata[0],dlen); 
    } 
    return(match ? dlen : 0); 
} 
 
/*EOF*/