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*/