📄 ip.c
字号:
/***************************************************************************************
File: ip.c
Date: 11.6.2002
Version: 0.1
Author: Jari Lahti (jari@violasystems.com)
Description: This file contains functions for processing IP frames received from and
to be sent to Ethernet
Version Info: 11.6.2002 - First version (JaL)
22.1.2004 - Port to MCF5282
***************************************************************************************/
#include "opentcp.h"
struct IPFrame ReceivedIPPacket;
struct IPFrame SendIPPacket;
UINT16 IPID;
/********************************************************************************
Function: ProcessIPIn
Parameters: struct otcp_ethframe* frame - pointer to received frame structure
Return val: INT16 - (-1) Not OK
>0 Length of next layer data (Packet OK)
Date: 11.6.2002
Desc: Check received IP Frame if it's OK to sent it to upper layers
*********************************************************************************/
INT16 ProcessIPIn (struct otcp_ethframe* frame)
{
UINT8 olen;
UINT8 i;
/* Check for Protocol */
DEBUGOUT("Checking if IP Protocol\n\r");
if( frame->protocol != PROTOCOL_IP )
return(-1);
DEBUGOUT("It's IP\n\r");
if( frame->framesize < ETH_HEADER_LEN )
return(-1);
if( (frame->framesize - ETH_HEADER_LEN) < IP_HLEN )
return(-1);
/* Get IP Header Information */
NETWORK_RECEIVE_INITIALIZE(frame->bufindex);
ReceivedIPPacket.vihl = RECEIVE_NETWORK_B();
/* Is it IPv4? */
if( (ReceivedIPPacket.vihl & 0xF0) != 0x40 )
{
DEBUGOUT("ERROR: IP is not version 4!\n\r");
return(-1);
}
DEBUGOUT("IP Version 4 OK!\n\r");
ReceivedIPPacket.tos = RECEIVE_NETWORK_B();
ReceivedIPPacket.tlen = RECEIVE_NETWORK_B();
ReceivedIPPacket.tlen <<= 8;
ReceivedIPPacket.tlen |= RECEIVE_NETWORK_B();
ReceivedIPPacket.id = RECEIVE_NETWORK_B();
ReceivedIPPacket.id <<= 8;
ReceivedIPPacket.id |= RECEIVE_NETWORK_B();
ReceivedIPPacket.frags = RECEIVE_NETWORK_B();
ReceivedIPPacket.frags <<= 8;
ReceivedIPPacket.frags |= RECEIVE_NETWORK_B();
ReceivedIPPacket.ttl= RECEIVE_NETWORK_B();
ReceivedIPPacket.protocol= RECEIVE_NETWORK_B();
ReceivedIPPacket.checksum = RECEIVE_NETWORK_B();
ReceivedIPPacket.checksum <<= 8;
ReceivedIPPacket.checksum |= RECEIVE_NETWORK_B();
ReceivedIPPacket.sip = RECEIVE_NETWORK_B();
ReceivedIPPacket.sip <<= 8;
ReceivedIPPacket.sip |= RECEIVE_NETWORK_B();
ReceivedIPPacket.sip <<= 8;
ReceivedIPPacket.sip |= RECEIVE_NETWORK_B();
ReceivedIPPacket.sip <<= 8;
ReceivedIPPacket.sip |= RECEIVE_NETWORK_B();
ReceivedIPPacket.dip = RECEIVE_NETWORK_B();
ReceivedIPPacket.dip <<= 8;
ReceivedIPPacket.dip |= RECEIVE_NETWORK_B();
ReceivedIPPacket.dip <<= 8;
ReceivedIPPacket.dip |= RECEIVE_NETWORK_B();
ReceivedIPPacket.dip <<= 8;
ReceivedIPPacket.dip |= RECEIVE_NETWORK_B();
/* Is that packet for us? */
if( (ReceivedIPPacket.dip != localmachine.localip) &&
(ReceivedIPPacket.dip != IP_BROADCAST_ADDRESS) )
{
/* It's not for us. Check still if ICMP with rigth physical */
/* address that migth be used to set temporary IP */
DEBUGOUT("IP address does not match!\n\r");
if( ReceivedIPPacket.protocol != IP_ICMP)
return(-1);
/* Check physical address */
for(i=0; i<PHY_ADR_LEN; i++)
{
if(frame->destination[i] != localmachine.localHW[i])
return(-1);
}
}
/* Is there options to copy? */
olen = ReceivedIPPacket.vihl & 0x0F;
olen <<= 2;
olen -= IP_MIN_HLEN;
/* Somebody bluffing with too long option field? */
if(olen > MAX_IP_OPTLEN)
{
DEBUGOUT("ERROR:Size of maximum allowed IP option lengt exceeded!\n\r");
return(-1);
}
if( olen > (frame->framesize - ETH_HEADER_LEN - IP_HLEN) )
{
DEBUGOUT("ERROR:IP option field too long!\n\r");
return(-1);
}
for( i=0; i < olen; i++ )
{
ReceivedIPPacket.opt[i] = RECEIVE_NETWORK_B();
DEBUGOUT("IP Options..\n\r");
}
if(ReceivedIPPacket.tlen > (frame->framesize - ETH_HEADER_LEN) )
{
DEBUGOUT("ERROR: Total len too long\r\n");
return(-1);
}
/* Is the checksum OK? */
DEBUGOUT("Validating the IP checksum..\n\r");
if ( IP_CheckCS(&ReceivedIPPacket) != TRUE )
{
DEBUGOUT("IP Checksum Corrupted..\n\r");
return(-1);
}
DEBUGOUT("..Checksum OK!\n\r");
/* Add the address to ARP cache */
if( ReceivedIPPacket.sip != IP_BROADCAST_ADDRESS)
arpadd( ReceivedIPPacket.sip, &frame->source[0], ARP_TEMP_IP);
/* Calculate the start of next layer data */
ReceivedIPPacket.BufIndex = frame->bufindex + IP_HLEN + olen;
/* Is this packet fragmented? */
/* We don't deal with those */
/* TODO: Implement Stub handler for more mem. uP's */
if( ReceivedIPPacket.frags & IP_MOREFRAGS )
{
DEBUGOUT("Fragmented IP packet\r\n");
return(-1);
}
if( ReceivedIPPacket.frags & IP_FRAGOFF )
{
DEBUGOUT("Fragmented IP packet\r\n");
return(-1);
}
DEBUGOUT("Leaving IP succesfully..\n\r");
/* Return the legth left for next layers */
if( (ReceivedIPPacket.tlen - IP_HLEN - olen) == 20 )
{
DEBUGOUT("20 bytes to next layer\r\n");
}
else if( (ReceivedIPPacket.tlen - IP_HLEN - olen) > 20 )
{
DEBUGOUT("Over 20 bytes to next layers\r\n");
}
else
{
DEBUGOUT("Less than 20 bytes to next layer\r\n");
}
return(ReceivedIPPacket.tlen - IP_HLEN - olen);
}
/********************************************************************************
Function: ProcessIPOut
Parameters: UINT32 ipadr - remote IP address
UINT8 pcol - protocol over IP
UINT8 tos - type of service required
UINT8 ttl - time to live for IP packet
UINT8* dat - pointer to data buffer
UINT16 len - legth of data
Return val: INT16 - (-1) Not OK (General)
(-2) ARP cache not ready
>0 Number of data bytes sent (Packet OK)
Date: 17.6.2002
Desc: Try to send out the IP frame
*********************************************************************************/
INT16 ProcessIPOut (UINT32 ipadr, UINT8 pcol, UINT8 tos, UINT8 ttl, UINT8* dat, UINT16 len)
{
struct arpentry *qstruct;
UINT16 i;
/* Try to get MAC address from ARP cache */
qstruct = arpfind(ipadr, &localmachine, ARP_TEMP_IP);
if( qstruct == 0 ) /* Not ready yet */
return(-2);
/* Select network buffer */
/* TODO: This network related stuff should */
/* be moved and abstracted to Ethernet layer */
switch(pcol)
{
case IP_ICMP:
NETWORK_SEND_INITIALIZE(TXBUF_ENET);
DEBUGOUT("Assembling IP packet to ICMP buffer\n\r");
break;
case IP_UDP:
NETWORK_SEND_INITIALIZE(TXBUF_ENET);
DEBUGOUT("Assembling IP packet to UDP buffer\n\r");
break;
case IP_TCP:
NETWORK_SEND_INITIALIZE(TXBUF_ENET);
DEBUGOUT("Assembling IP packet to TCP buffer\n\r");
break;
default: /* Unknown protocol */
return(-1);
}
/* Fill the Ethernet information */
for( i=0; i<MAXHWALEN; i++)
{
otcp_txframe.destination[i] = qstruct->hwadr[i];
}
for( i=0; i<MAXHWALEN; i++)
{
otcp_txframe.source[i] = localmachine.localHW[i];
}
otcp_txframe.protocol = PROTOCOL_IP;
NETWORK_ADD_DATALINK(&otcp_txframe);
/* Construct the IP header */
SendIPPacket.vihl = IP_DEF_VIHL;
if(tos != 0)
SendIPPacket.tos = tos;
else
SendIPPacket.tos = localmachine.tos;
SendIPPacket.tlen = IP_HLEN + len;
SendIPPacket.id = IPID++;
SendIPPacket.frags = 0;
SendIPPacket.ttl = ttl;
SendIPPacket.protocol = pcol;
SendIPPacket.checksum = 0;
SendIPPacket.sip = localmachine.localip;
SendIPPacket.dip = ipadr;
/* Calculate checksum for the IP header */
SendIPPacket.checksum = IP_ConstructCS( &SendIPPacket );
/* Assemble bytes to network */
SEND_NETWORK_B(SendIPPacket.vihl);
SEND_NETWORK_B(SendIPPacket.tos);
SEND_NETWORK_B( (UINT8)(SendIPPacket.tlen >> 8) );
SEND_NETWORK_B( (UINT8)SendIPPacket.tlen );
SEND_NETWORK_B( (UINT8)(SendIPPacket.id >> 8) );
SEND_NETWORK_B( (UINT8)SendIPPacket.id );
SEND_NETWORK_B( (UINT8)(SendIPPacket.frags >> 8) );
SEND_NETWORK_B( (UINT8)SendIPPacket.frags );
SEND_NETWORK_B(SendIPPacket.ttl);
SEND_NETWORK_B(SendIPPacket.protocol);
SEND_NETWORK_B( (UINT8)(SendIPPacket.checksum >> 8) );
SEND_NETWORK_B( (UINT8)SendIPPacket.checksum );
SEND_NETWORK_B( (UINT8)(SendIPPacket.sip >> 24) );
SEND_NETWORK_B( (UINT8)(SendIPPacket.sip >> 16) );
SEND_NETWORK_B( (UINT8)(SendIPPacket.sip >> 8) );
SEND_NETWORK_B( (UINT8)SendIPPacket.sip );
SEND_NETWORK_B( (UINT8)(SendIPPacket.dip >> 24) );
SEND_NETWORK_B( (UINT8)(SendIPPacket.dip >> 16) );
SEND_NETWORK_B( (UINT8)(SendIPPacket.dip >> 8) );
SEND_NETWORK_B( (UINT8)SendIPPacket.dip );
/* Assemble data */
SEND_NETWORK_BUF(dat, len);
/* Launch it */
NETWORK_COMPLETE_SEND( SendIPPacket.tlen );
return(len);
}
/********************************************************************************
Function: IP_ConstructCS
Parameters: struct IPFrame* frame - pointer to IP frame to be checked
Return val: UINT32 - calculated checksum
Date: 8.7.2002
Desc: Calculate checksum for given IP header
*********************************************************************************/
UINT32 IP_ConstructCS (struct IPFrame* frame)
{
UINT16 ip_cs;
UINT8 cs_cnt;
UINT8 olen;
UINT8 i;
ip_cs = 0;
cs_cnt = 0;
ip_cs = IpCheckSum(ip_cs, frame->vihl, cs_cnt++);
ip_cs = IpCheckSum(ip_cs, frame->tos, cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->tlen >> 8), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)frame->tlen, cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->id >> 8), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)frame->id, cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->frags >> 8), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)frame->frags, cs_cnt++);
ip_cs = IpCheckSum(ip_cs, frame->ttl, cs_cnt++);
ip_cs = IpCheckSum(ip_cs, frame->protocol, cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->sip >> 24), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->sip >> 16), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->sip >> 8), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)frame->sip, cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->dip >> 24), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->dip >> 16), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->dip >> 8), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)frame->dip, cs_cnt++);
/* Is there options? */
olen = frame->vihl & 0x0F;
olen <<= 2;
olen -= IP_MIN_HLEN;
for( i=0; i<olen; i++)
ip_cs = IpCheckSum(ip_cs, (UINT8)frame->opt[i], cs_cnt++);
/* Take complement */
ip_cs = ~ ip_cs;
return(ip_cs);
}
/********************************************************************************
Function: IP_CheckCS
Parameters: struct IPFrame* frame - pointer to IP frame to be checked
Return val: UINT8 0 - Checksum corrupted
UINT8 1 - Checksum OK
Date: 12.6.2002
Desc: Calculate if the IP frame header CS is not corrupted. May be
made more intelligent/faster by using carry method.
*********************************************************************************/
UINT8 IP_CheckCS (struct IPFrame* frame)
{
UINT16 ip_cs;
UINT8 cs_cnt;
UINT8 olen;
UINT8 i;
ip_cs = 0;
cs_cnt = 0;
ip_cs = IpCheckSum(ip_cs, frame->vihl, cs_cnt++);
ip_cs = IpCheckSum(ip_cs, frame->tos, cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->tlen >> 8), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)frame->tlen, cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->id >> 8), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)frame->id, cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->frags >> 8), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)frame->frags, cs_cnt++);
ip_cs = IpCheckSum(ip_cs, frame->ttl, cs_cnt++);
ip_cs = IpCheckSum(ip_cs, frame->protocol, cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->checksum >> 8), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)frame->checksum, cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->sip >> 24), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->sip >> 16), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->sip >> 8), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)frame->sip, cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->dip >> 24), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->dip >> 16), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)(frame->dip >> 8), cs_cnt++);
ip_cs = IpCheckSum(ip_cs, (UINT8)frame->dip, cs_cnt++);
/* Is there options? */
olen = frame->vihl & 0x0F;
olen <<= 2;
olen -= IP_MIN_HLEN;
for( i=0; i<olen; i++)
ip_cs = IpCheckSum(ip_cs, (UINT8)frame->opt[i], cs_cnt++);
/* Analyze the result */
ip_cs = ~ ip_cs;
if(ip_cs == IP_GOOD_CS)
return 1;
/* Fuck, it failed! */
return 0;
}
/********************************************************************************
Function: IpCheckSum
Parameters: UINT16 cs - last checksum value
UINT8 dat - byte to be added to checksum
UINT8 count - is this byte MSB or LSB
Return val: UINT16 - new checksum value
Date: 24.2.2002
Desc: Add one given byte to given checksum and return the new
checksum value
*********************************************************************************/
UINT16 IpCheckSum (UINT16 cs, UINT8 dat, UINT8 count)
{
UINT8 b = dat;
UINT8 Cs_L;
UINT8 Cs_H;
Cs_H = (UINT8)(cs >> 8);
Cs_L = (UINT8)cs;
if( count & 0x01 )
{
/* We are processing LSB */
if( (Cs_L = Cs_L + b) < b )
{
if( ++Cs_H == 0 )
Cs_L++;
}
}
else
{
/* We are processing MSB */
if( (Cs_H = Cs_H + b) < b )
{
if( ++Cs_L == 0 )
Cs_H++;
}
}
return( ( (UINT16)Cs_H << 8 ) + Cs_L);
}
/********************************************************************************
Function: IpCheckSumBuf
Parameters: UINT16 cs - last checksum value
UINT8* buf - buffer checksummed
UINT16 len - length of data
Return val: UINT16 - new checksum value
Date: 4.4.2003
Desc: Calculates CS to buffer and return the new
checksum value.
*********************************************************************************/
UINT32 IpCheckSumBuf (UINT16 cs, UINT8* buf, UINT16 len)
{
UINT16 dat;
UINT32 temp;
temp = cs;
while(len>1)
{
len -= 2;
dat = *buf++;
dat <<= 8;
dat |= *buf++;
temp += dat;
}
temp = (temp >> 16) + (temp & 0xFFFF); /* Add in carry */
temp += (temp >>16); /* Maybe one more */
if(len)
temp = IpCheckSum(temp, *buf, 0);
return( (UINT16) temp );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -