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