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