Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages   Examples  

/opentcp/ip.c

Go to the documentation of this file.
00001 /*
00002  *Copyright (c) 2000-2002 Viola Systems Ltd.
00003  *All rights reserved.
00004  *
00005  *Redistribution and use in source and binary forms, with or without 
00006  *modification, are permitted provided that the following conditions 
00007  *are met:
00008  *
00009  *1. Redistributions of source code must retain the above copyright 
00010  *notice, this list of conditions and the following disclaimer.
00011  *
00012  *2. Redistributions in binary form must reproduce the above copyright 
00013  *notice, this list of conditions and the following disclaimer in the 
00014  *documentation and/or other materials provided with the distribution.
00015  *
00016  *3. The end-user documentation included with the redistribution, if 
00017  *any, must include the following acknowledgment:
00018  *      "This product includes software developed by Viola 
00019  *      Systems (http://www.violasystems.com/)."
00020  *
00021  *Alternately, this acknowledgment may appear in the software itself, 
00022  *if and wherever such third-party acknowledgments normally appear.
00023  *
00024  *4. The names "OpenTCP" and "Viola Systems" must not be used to 
00025  *endorse or promote products derived from this software without prior 
00026  *written permission. For written permission, please contact 
00027  *opentcp@opentcp.org.
00028  *
00029  *5. Products derived from this software may not be called "OpenTCP", 
00030  *nor may "OpenTCP" appear in their name, without prior written 
00031  *permission of the Viola Systems Ltd.
00032  *
00033  *THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 
00034  *WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
00035  *MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
00036  *IN NO EVENT SHALL VIOLA SYSTEMS LTD. OR ITS CONTRIBUTORS BE LIABLE 
00037  *FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
00038  *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
00039  *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
00040  *BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
00041  *WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
00042  *OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
00043  *EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00044  *====================================================================
00045  *
00046  *OpenTCP is the unified open source TCP/IP stack available on a series 
00047  *of 8/16-bit microcontrollers, please see <http://www.opentcp.org>.
00048  *
00049  *For more information on how to network-enable your devices, or how to 
00050  *obtain commercial technical support for OpenTCP, please see 
00051  *<http://www.violasystems.com/>.
00052  */
00053 
00070 #include <inet/debug.h>
00071 #include <inet/datatypes.h>
00072 #include <inet/ethernet.h>
00073 #include <inet/arp.h>
00074 #include <inet/ip.h>
00075 #include <inet/system.h>
00076 
00077 
00085 struct ip_frame received_ip_packet;
00086 
00095 struct ip_frame send_ip_packet;
00096 
00097 UINT16 ip_id;   
00115 INT16 process_ip_in (struct ethernet_frame* frame)
00116 {
00117 
00118         UINT8 olen;
00119         UINT8 i;
00120         
00121         /* Check for Protocol                                                           */
00122         
00123         IP_DEBUGOUT("Checking if IP Protocol\n\r");
00124         
00125         if( frame->protocol != PROTOCOL_IP )
00126                 return(-1);
00127         
00128         
00129         IP_DEBUGOUT("It's IP\n\r");
00130         
00131         if( frame->frame_size < ETH_HEADER_LEN )
00132                 return(-1);
00133                 
00134         if( (frame->frame_size - ETH_HEADER_LEN) < IP_HLEN )
00135                 return(-1); 
00136                                 
00137         /* Get IP Header Information                                            */
00138                 
00139         NETWORK_RECEIVE_INITIALIZE(frame->buf_index);
00140                 
00141         received_ip_packet.vihl = RECEIVE_NETWORK_B();
00142                 
00143         /* Is it IPv4?  */
00144                 
00145         if( (received_ip_packet.vihl & 0xF0) != 0x40 ) {
00146                 IP_DEBUGOUT("ERROR: IP is not version 4!\n\r");
00147                 return(-1);
00148         }
00149                 
00150         IP_DEBUGOUT("IP Version 4 OK!\n\r");    
00151                 
00152         received_ip_packet.tos = RECEIVE_NETWORK_B();                                           
00153         
00154         received_ip_packet.tlen = ((UINT16)RECEIVE_NETWORK_B()) << 8;
00155         received_ip_packet.tlen |= RECEIVE_NETWORK_B();
00156                 
00157         received_ip_packet.id = ((UINT16)RECEIVE_NETWORK_B()) << 8;
00158         received_ip_packet.id |= RECEIVE_NETWORK_B();
00159                 
00160         received_ip_packet.frags = ((UINT16)RECEIVE_NETWORK_B()) << 8;
00161         received_ip_packet.frags |= RECEIVE_NETWORK_B();
00162                 
00163         received_ip_packet.ttl= RECEIVE_NETWORK_B();
00164                 
00165         received_ip_packet.protocol= RECEIVE_NETWORK_B();
00166                 
00167         received_ip_packet.checksum = ((UINT16)RECEIVE_NETWORK_B()) << 8;
00168         received_ip_packet.checksum |= RECEIVE_NETWORK_B();
00169                 
00170         received_ip_packet.sip = (((UINT32)RECEIVE_NETWORK_B()) << 24);
00171         received_ip_packet.sip |= (((UINT32)RECEIVE_NETWORK_B()) << 16);
00172         received_ip_packet.sip |= (((UINT32)RECEIVE_NETWORK_B()) << 8);
00173         received_ip_packet.sip |= RECEIVE_NETWORK_B();
00174                 
00175         received_ip_packet.dip = (((UINT32)RECEIVE_NETWORK_B()) << 24);
00176         received_ip_packet.dip |= (((UINT32)RECEIVE_NETWORK_B()) << 16);
00177         received_ip_packet.dip |= (((UINT32)RECEIVE_NETWORK_B()) << 8);
00178         received_ip_packet.dip |= RECEIVE_NETWORK_B();
00179 
00180         /* Is that packet for us?                       */
00181 
00182 
00183         if((received_ip_packet.dip != localmachine.localip )&&
00184                 (received_ip_packet.dip != IP_BROADCAST_ADDRESS)) {
00185 
00186                 /* It's not for us. Check still if ICMP with rigth physical     */
00187                 /* address that migth be used to set temporary IP                       */
00188                 
00189                 IP_DEBUGOUT("IP address does not match!\n\r");
00190                 
00191                 if( received_ip_packet.protocol != IP_ICMP) 
00192                         return(-1);
00193                         
00194                 /* Check physical address                       */
00195                 
00196                 for(i=0; i<PHY_ADR_LEN; i++)
00197                 {
00198                         if(frame->destination[i] != localmachine.localHW[i])
00199                                 return(-1);
00200                 }       
00201 
00202         }
00203         
00204         
00205         /* Is there options to copy?            */
00206                 
00207         olen = ((received_ip_packet.vihl & 0x0F) << 2) - IP_MIN_HLEN;
00208         
00209         /* Somebody bluffing with too long option field?        */
00210         
00211         if(olen > MAX_IP_OPTLEN) {
00212                 IP_DEBUGOUT("ERROR:Size of maximum allowed IP option lengt exceeded!\n\r");
00213                 return(-1);
00214         }
00215         
00216         if( olen > (frame->frame_size - ETH_HEADER_LEN - IP_HLEN) )     {
00217                 IP_DEBUGOUT("ERROR:IP option field too long!\n\r");
00218                 return(-1);
00219         }
00220                 
00221         for( i=0; i < olen; i++ ) {
00222                 received_ip_packet.opt[i] = RECEIVE_NETWORK_B();        
00223                 IP_DEBUGOUT("IP Options..\n\r");
00224         }
00225         
00226         if(received_ip_packet.tlen >  (frame->frame_size - ETH_HEADER_LEN) ) {
00227                 IP_DEBUGOUT("ERROR: Total len too long\r\n");
00228                 return(-1);
00229         }
00230         
00231         /* Is the checksum OK?  */
00232         
00233         IP_DEBUGOUT("Validating the IP checksum..\n\r");
00234         
00235         if ( ip_check_cs(&received_ip_packet) != TRUE ) {
00236                 IP_DEBUGOUT("IP Checksum Corrupted..\n\r");
00237                 return(-1);
00238         }       
00239         
00240         IP_DEBUGOUT("..Checksum OK!\n\r");      
00241         
00242         /* Add the address to ARP cache */
00243         
00244         if( received_ip_packet.sip != IP_BROADCAST_ADDRESS)
00245                 arp_add( received_ip_packet.sip, &frame->source[0], ARP_TEMP_IP);
00246         
00247         /* Calculate the start of next layer data       */
00248         
00249         received_ip_packet.buf_index = frame->buf_index + IP_HLEN + olen;
00250         
00251         /* Is this packet fragmented?                                           */
00252         /* We don't deal with those                                                     */
00253         /* TODO: Implement Stub handler for more mem. uP's      */
00254         
00255         if( received_ip_packet.frags & (IP_MOREFRAGS | IP_FRAGOFF) ) {
00256                 IP_DEBUGOUT("Fragmented IP packet\r\n");
00257                 return(-1);
00258         }
00259         /* checking moved upwards!
00260         if( received_ip_packet.frags & IP_FRAGOFF )     {
00261                 IP_DEBUGOUT("Fragmented IP packet\r\n");
00262                 return(-1);
00263         }
00264         */
00265         
00266         IP_DEBUGOUT("Leaving IP succesfully..\n\r");
00267         
00268         return(received_ip_packet.tlen - IP_HLEN - olen);
00269         
00270 }
00271 
00300 INT16 process_ip_out (UINT32 ipadr, UINT8 pcol, UINT8 tos, UINT8 ttl, UINT8* dat, UINT16 len)
00301 {
00302         struct arp_entry *qstruct;
00303         UINT16 i;
00304         
00305         /* Try to get MAC address from ARP cache        */
00306         
00307         qstruct = arp_find(ipadr, &localmachine, ARP_TEMP_IP);
00308         
00309         if( qstruct == 0 )              /* Not ready yet        */
00310                 return(-2);
00311                 
00312         /* Select network buffer                                                */
00313         /* TODO: This network related stuff should              */
00314         /* be moved and abstracted to Ethernet layer    */
00315         
00316         switch(pcol) {
00317                 case IP_ICMP:
00318                 
00319                         NETWORK_SEND_INITIALIZE(ICMP_BUF);
00320                         IP_DEBUGOUT("Assembling IP packet to ICMP buffer\n\r");
00321                         
00322                         break;
00323                         
00324                 case IP_UDP:
00325                 
00326                         NETWORK_SEND_INITIALIZE(UDP_BUF);
00327                         IP_DEBUGOUT("Assembling IP packet to UDP buffer\n\r");
00328                         
00329                         break;
00330                         
00331                 case IP_TCP:
00332                 
00333                         NETWORK_SEND_INITIALIZE(TCP_BUF);
00334                         IP_DEBUGOUT("Assembling IP packet to TCP buffer\n\r");
00335                         
00336                         break;
00337         
00338                 default:                        /* Unknown protocol     */
00339                         return(-1);
00340         }
00341         
00342         /* Fill the Ethernet information        */
00343         
00344         for( i=0; i<MAXHWALEN; i++)     {
00345                 send_frame.destination[i] = qstruct->hwadr[i];
00346                 send_frame.source[i] = localmachine.localHW[i];
00347         }
00348         
00349         send_frame.protocol = PROTOCOL_IP;
00350         
00351         NETWORK_ADD_DATALINK(&send_frame);
00352         
00353         /* Construct the IP header      */
00354         
00355         send_ip_packet.vihl = IP_DEF_VIHL;
00356         send_ip_packet.tos = tos;
00357         send_ip_packet.tlen = IP_HLEN + len;
00358         send_ip_packet.id = ip_id++;
00359         send_ip_packet.frags = 0;
00360         send_ip_packet.ttl = ttl;
00361         send_ip_packet.protocol = pcol;
00362         send_ip_packet.checksum = 0;
00363         send_ip_packet.sip = localmachine.localip;
00364         send_ip_packet.dip = ipadr;
00365         
00366         /* Calculate checksum for the IP header */
00367         
00368         send_ip_packet.checksum = ip_construct_cs( &send_ip_packet );
00369         
00370         /* Assemble bytes to network    */
00371         
00372         SEND_NETWORK_B(send_ip_packet.vihl);
00373         SEND_NETWORK_B(send_ip_packet.tos);
00374         SEND_NETWORK_B( (UINT8)(send_ip_packet.tlen >> 8) );
00375         SEND_NETWORK_B( (UINT8)send_ip_packet.tlen );           
00376         SEND_NETWORK_B( (UINT8)(send_ip_packet.id >> 8) );
00377         SEND_NETWORK_B( (UINT8)send_ip_packet.id );
00378         SEND_NETWORK_B( (UINT8)(send_ip_packet.frags >> 8) );
00379         SEND_NETWORK_B( (UINT8)send_ip_packet.frags );
00380         SEND_NETWORK_B(send_ip_packet.ttl);
00381         SEND_NETWORK_B(send_ip_packet.protocol);        
00382         SEND_NETWORK_B( (UINT8)(send_ip_packet.checksum >> 8) );
00383         SEND_NETWORK_B( (UINT8)send_ip_packet.checksum );
00384         SEND_NETWORK_B( (UINT8)(send_ip_packet.sip >> 24) );
00385         SEND_NETWORK_B( (UINT8)(send_ip_packet.sip >> 16) );
00386         SEND_NETWORK_B( (UINT8)(send_ip_packet.sip >> 8) );
00387         SEND_NETWORK_B( (UINT8)send_ip_packet.sip );
00388         SEND_NETWORK_B( (UINT8)(send_ip_packet.dip >> 24) );
00389         SEND_NETWORK_B( (UINT8)(send_ip_packet.dip >> 16) );
00390         SEND_NETWORK_B( (UINT8)(send_ip_packet.dip >> 8) );
00391         SEND_NETWORK_B( (UINT8)send_ip_packet.dip );
00392         
00393         /* Assemble data        */
00394         
00395         SEND_NETWORK_BUF(dat,len);
00396                 
00397         /* Launch it            */
00398         
00399         NETWORK_COMPLETE_SEND( send_ip_packet.tlen );
00400         
00401         return(len);
00402         
00403         
00404 }
00405 
00417 UINT32 ip_construct_cs (struct ip_frame* frame)
00418 {
00419         UINT16 ip_cs;
00420         UINT8 cs_cnt;
00421         UINT8 olen;
00422         UINT8 i;
00423         
00424         ip_cs = 0;
00425         cs_cnt = 0;
00426         
00427         ip_cs = ip_checksum(ip_cs, frame->vihl, cs_cnt++);
00428         ip_cs = ip_checksum(ip_cs, frame->tos, cs_cnt++);
00429         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->tlen >> 8), cs_cnt++);
00430         ip_cs = ip_checksum(ip_cs, (UINT8)frame->tlen, cs_cnt++);
00431         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->id >> 8), cs_cnt++);
00432         ip_cs = ip_checksum(ip_cs, (UINT8)frame->id, cs_cnt++);
00433         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->frags >> 8), cs_cnt++);
00434         ip_cs = ip_checksum(ip_cs, (UINT8)frame->frags, cs_cnt++);
00435         ip_cs = ip_checksum(ip_cs, frame->ttl, cs_cnt++);
00436         ip_cs = ip_checksum(ip_cs, frame->protocol, cs_cnt++);
00437         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->sip >> 24), cs_cnt++);
00438         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->sip >> 16), cs_cnt++);
00439         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->sip >> 8), cs_cnt++);
00440         ip_cs = ip_checksum(ip_cs, (UINT8)frame->sip, cs_cnt++);
00441         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->dip >> 24), cs_cnt++);
00442         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->dip >> 16), cs_cnt++);
00443         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->dip >> 8), cs_cnt++);
00444         ip_cs = ip_checksum(ip_cs, (UINT8)frame->dip, cs_cnt++);        
00445         
00446         /* Is there options?                            */
00447                 
00448         olen = ((frame->vihl & 0x0F) << 2) - IP_MIN_HLEN;
00449         
00450         for( i=0; i<olen; i++)
00451                 ip_cs = ip_checksum(ip_cs, (UINT8)frame->opt[i], cs_cnt++);
00452         
00453         /* Take complement      */
00454         
00455         ip_cs = ~ ip_cs;
00456 
00457         return(ip_cs);
00458 
00459 }
00460 
00474 UINT8 ip_check_cs (struct ip_frame* frame)
00475 {
00476         UINT16 ip_cs;
00477         UINT8 cs_cnt;
00478         UINT8 olen;
00479         UINT8 i;
00480         
00481         ip_cs = 0;
00482         cs_cnt = 0;
00483         
00484         ip_cs = ip_checksum(ip_cs, frame->vihl, cs_cnt++);
00485         ip_cs = ip_checksum(ip_cs, frame->tos, cs_cnt++);
00486         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->tlen >> 8), cs_cnt++);
00487         ip_cs = ip_checksum(ip_cs, (UINT8)frame->tlen, cs_cnt++);
00488         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->id >> 8), cs_cnt++);
00489         ip_cs = ip_checksum(ip_cs, (UINT8)frame->id, cs_cnt++);
00490         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->frags >> 8), cs_cnt++);
00491         ip_cs = ip_checksum(ip_cs, (UINT8)frame->frags, cs_cnt++);
00492         ip_cs = ip_checksum(ip_cs, frame->ttl, cs_cnt++);
00493         ip_cs = ip_checksum(ip_cs, frame->protocol, cs_cnt++);
00494         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->checksum >> 8), cs_cnt++);
00495         ip_cs = ip_checksum(ip_cs, (UINT8)frame->checksum, cs_cnt++);
00496         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->sip >> 24), cs_cnt++);
00497         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->sip >> 16), cs_cnt++);
00498         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->sip >> 8), cs_cnt++);
00499         ip_cs = ip_checksum(ip_cs, (UINT8)frame->sip, cs_cnt++);
00500         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->dip >> 24), cs_cnt++);
00501         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->dip >> 16), cs_cnt++);
00502         ip_cs = ip_checksum(ip_cs, (UINT8)(frame->dip >> 8), cs_cnt++);
00503         ip_cs = ip_checksum(ip_cs, (UINT8)frame->dip, cs_cnt++);        
00504         
00505         /* Is there options?                            */
00506                 
00507         olen = ((frame->vihl & 0x0F) << 2) - IP_MIN_HLEN;
00508         
00509         for( i=0; i<olen; i++)
00510                 ip_cs = ip_checksum(ip_cs, (UINT8)frame->opt[i], cs_cnt++);
00511         
00512         /* Analyze the result   */
00513         
00514         ip_cs = ~ ip_cs;
00515         
00516         if(ip_cs == IP_GOOD_CS)
00517                 return 1;
00518         
00519         /* Fuck, it failed!     */
00520         
00521         return 0;
00522         
00523 
00524 }
00525 
00539 UINT16 ip_checksum (UINT16 cs, UINT8 dat, UINT8 count)
00540 {
00541         UINT8 b = dat;
00542         UINT8 cs_l;
00543         UINT8 cs_h;
00544         
00545         cs_h = (UINT8)(cs >> 8); 
00546         cs_l = (UINT8)cs;
00547 
00548         if( count & 0x01 ) {
00549                 /* We are processing LSB        */
00550                 
00551                 if( (cs_l = cs_l + b) < b ) {
00552                         if( ++cs_h == 0 )
00553                                 cs_l++;
00554                 }
00555                 
00556         } else {
00557                 /* We are processing MSB        */
00558                 
00559                 if( (cs_h = cs_h + b) < b )     {
00560                         if( ++cs_l == 0 )
00561                                 cs_h++;
00562                 }
00563         }
00564 
00565         return( ( (UINT16)cs_h << 8 ) + cs_l);
00566 
00567 }
00568 
00569 
00582 UINT32 ip_checksum_buf (UINT16 cs, UINT8* buf, UINT16 len)
00583 {
00584         UINT16 dat;
00585         UINT32 temp;
00586         
00587         temp = cs;
00588         
00589         while(len>1)
00590         {
00591                 len -= 2;
00592                 dat = *buf++;
00593                 dat <<= 8;
00594                 dat |= *buf++;
00595                 temp += dat;
00596         }
00597         
00598         temp = (temp >> 16) + (temp & 0xFFFF);  /* Add in carry         */
00599         temp += (temp >>16);                                    /* Maybe one more       */
00600         
00601         if(len)
00602                 temp = ip_checksum(temp, *buf, 0);
00603         
00604         return( (UINT16) temp );
00605 
00606 }
00607 

Generated on Sun Aug 3 20:33:00 2003 for OpenTCP by doxygen1.2.18