Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Related Pages  

C:/proj/src/ethernut/nut/eboot/ip.c

00001 /*
00002  * Copyright (C) 2001-2002 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. All advertising materials mentioning features or use of this
00014  *    software must display the following acknowledgement:
00015  *
00016  *    This product includes software developed by egnite Software GmbH
00017  *    and its contributors.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00020  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00021  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00022  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00023  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00024  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00025  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00026  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00027  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00028  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00029  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00030  * SUCH DAMAGE.
00031  *
00032  * For additional information see http://www.ethernut.de/
00033  *
00034  * -
00035  * Portions Copyright (C) 2000 David J. Hudson <dave@humbug.demon.co.uk>
00036  *
00037  * This file is distributed in the hope that it will be useful, but WITHOUT
00038  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00039  * FITNESS FOR A PARTICULAR PURPOSE.
00040  *
00041  * You can redistribute this file and/or modify it under the terms of the GNU
00042  * General Public License (GPL) as published by the Free Software Foundation;
00043  * either version 2 of the License, or (at your discretion) any later version.
00044  * See the accompanying file "copying-gpl.txt" for more details.
00045  *
00046  * As a special exception to the GPL, permission is granted for additional
00047  * uses of the text contained in this file.  See the accompanying file
00048  * "copying-liquorice.txt" for details.
00049  *
00050  * -
00051  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
00052  *
00053  * Permission to use, copy, modify, and distribute this software for any
00054  * purpose with or without fee is hereby granted, provided that the above
00055  * copyright notice and this permission notice appear in all copies, and that
00056  * the name of Digital Equipment Corporation not be used in advertising or
00057  * publicity pertaining to distribution of the document or software without
00058  * specific, written prior permission.
00059  * 
00060  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
00061  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
00062  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
00063  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
00064  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
00065  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
00066  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00067  * SOFTWARE.
00068  */
00069 
00070 /*
00071  * $Log: ip.c,v $
00072  * Revision 1.1  2002/08/01 17:34:30  harald
00073  * First check in
00074  *
00075  */
00076 
00077 #include "eboot.h"
00078 #include "arp.h"
00079 #include "ip.h"
00080 
00081 /*!
00082  * \addtogroup xgStack
00083  */
00084 /*@{*/
00085 
00086 /*!
00087  * \brief Calculates a partial IP checksum over a block of data.
00088  *
00089  * Note that this returns the checksum in network byte order, and thus does
00090  * not need to be converted via hton16(), etc.  Of course this means that
00091  * we mustn't use this value for normal arithmetic!
00092  *
00093  * This is a partial checksum because it doesn't take the 1's complement
00094  * of the overall sum.
00095  *
00096  * \note by Harald Kipp: Yes, it looks wrong. I assume that this will not 
00097  *       work for all packet sizes. Not yet confirmed.
00098  */
00099 u_short IpChkSumPartial(u_short partial_csum, void *buf, u_short count)
00100 {
00101     u_short words;
00102     void *d1;
00103     u_short d2;
00104 
00105     words = count >> 1;
00106     d1 = buf;
00107 
00108     if(words != 0) {
00109         /*
00110          * This doesn't look particularly intuitive at first sight - in fact
00111          * it probably looks plain wrong.  It does work however (take my word
00112          * for it), but for some explanation the reader is referred to
00113          * RFC1071 where the maths is explained in detail.
00114          */
00115         asm volatile(
00116             "\n"
00117             "L_redo%=:\n\t"
00118             "ld __tmp_reg__, %a1+\n\t"
00119             "add %A0, __tmp_reg__\n\t"
00120             "ld __tmp_reg__, %a1+\n\t"
00121             "adc %B0, __tmp_reg__\n\t"
00122             "adc %A0, r1\n\t"
00123             "adc %B0, r1\n\t"
00124             "dec %A2\n\t"
00125             "brne L_redo%=\n\t"
00126             "subi %B2, 1\n\t"
00127             "brsh L_redo%=\n\t"
00128             "\n\t"
00129             : "=r" (partial_csum), "=e" (d1), "=w" (d2)
00130             : "0" (partial_csum), "1" (d1), "2" (words)
00131         );
00132     }
00133 
00134     /*
00135      * Did we have an odd number of bytes to do?
00136      */
00137     if(count & 0x01) {
00138         asm volatile (
00139             "ld __tmp_reg__, %a1+\n\t"
00140             "add %A0, __tmp_reg__\n\t"
00141             "adc %B0, r1\n\t"
00142             "adc %A0, r1\n\t"
00143             : "=r" (partial_csum), "=e" (d1)
00144             : "0" (partial_csum), "1" (d1)
00145         );
00146     }
00147     return partial_csum;
00148 }
00149 
00150 
00151 /*!
00152  * \brief Calculates an the final IP checksum over a block of data.
00153  *
00154  * Unlike the partial checksum in NutIpChkSumPartial(), this function takes
00155  * the one's complement of the final result, thus making it the full checksum.
00156  */
00157 u_short IpChkSum(u_short partial_csum, void *buf, u_short count)
00158 {
00159     return IpChkSumPartial(partial_csum, buf, count) ^ 0xffff;
00160 }
00161 
00162 /*!
00163  * \brief Receive an IP packet with the specified protocol type.
00164  *
00165  * This function calls EtherInput(). Any incoming Ethernet 
00166  * frame, which is not of the specified type will be discarded.
00167  *
00168  * \param proto Protocol type.
00169  * \param tms   Return with timeout after the specified
00170  *              number of waiting loops. On a 14 Mhz ATmega
00171  *              this value represents approximately the number
00172  *              of milliseconds to wait.
00173  *
00174  * \return The number of bytes received, 0 on timeout 
00175  *         or -1 in case of a failure.
00176  */
00177 int IpInput(u_char proto, u_short tms)
00178 {
00179     int rc = 0;
00180     IPHDR *ip;
00181     u_short ip_hdrlen;
00182     u_long dst;
00183     u_char bcast;
00184 
00185     for(;;) {
00186 
00187         /*
00188          * Return 0, if no frame is available.
00189          */
00190         if((rc = EtherInput(ETHERTYPE_IP, tms)) <= 0) {
00191             break;
00192         }
00193         ip = &rframe.ip_hdr;
00194 
00195         /*
00196          * Silently discard datagrams of different IP version
00197          * and fragmented datagrams.
00198          */
00199         if(ip->ip_v != IPVERSION) {
00200             continue;
00201         }
00202         if((ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK)) != 0) {
00203             continue;
00204         }
00205 
00206         ip_hdrlen = ip->ip_hl * 4;
00207 
00208         /*
00209          * Check for broadcast.
00210          */
00211         dst = ip->ip_dst;
00212 
00213         if(dst == 0xffffffff || (local_ip && (dst | netmask) == 0xffffffff)) 
00214             bcast = 1;
00215 
00216         /*
00217          * Silently discard datagrams for other destinations.
00218          */
00219         else if(dst == 0 || dst != local_ip) {
00220             continue;
00221         }
00222 
00223         else
00224             bcast = 0;
00225 
00226         /*
00227          * Check the requested protocol.
00228          */
00229         if(ip->ip_p == proto) {
00230             rc = htons(ip->ip_len) - (ip_hdrlen);
00231             break;
00232         }
00233     }
00234     return  rc;
00235 }
00236 
00237 /*!
00238  * \brief
00239  *
00240  * \return 0 on success, -1 otherwise.
00241  */
00242 int IpOutput(u_long dip, u_char proto, u_short len)
00243 {
00244     u_char dmac[6];
00245 
00246     IPHDR *ip = &sframe.ip_hdr;
00247 
00248     ip->ip_v = 4;
00249     ip->ip_hl = sizeof(IPHDR) >> 2;
00250     ip->ip_len = htons(sizeof(IPHDR) + len);
00251     ip->ip_ttl = 0x40;
00252     ip->ip_p = proto;
00253     ip->ip_dst = dip;
00254     ip->ip_src = local_ip;
00255     ip->ip_id++;
00256     ip->ip_sum = 0;
00257     ip->ip_sum = IpChkSum(0, ip, sizeof(IPHDR));
00258 
00259     if(ArpRequest(dip, dmac))
00260         return -1;
00261 
00262     return EtherOutput(dmac, ETHERTYPE_IP, sizeof(IPHDR) + len);
00263 }
00264 
00265 /*@}*/

© 2002 by egnite Software GmbH - visit http://www.ethernut.de/