/*************************************************************************************** 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 01.8.2004 - Port for MCF523x(A19257) ***************************************************************************************/ #include "opentcp.h" //#include "../../../Examples/Quadros_ss+OpenTCP/Mcf523x/tcpTest/C_Source/mcu_port.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; idestination[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; ihwadr[i]; } for( i=0; i> 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; iopt[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; iopt[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; UINT8 *dath, *datl; UINT32 temp; temp = cs; dath=(UINT8*)&dat; datl=dath+1; //mcu_cs5_on(); while(len>1) { len -=2; *dath = *buf++; *datl = *buf++; temp +=dat; } temp = (temp >> 16) + (temp & 0xFFFF); /* Add in carry */ temp += (temp >>16); /* Maybe one more */ if(len) temp = IpCheckSum(temp, *buf, 0); //mcu_cs5_off(); return( (UINT16) temp ); }