Nut/OS  4.10.3
API Reference
ipin.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 by egnite GmbH.
00003  * Copyright (C) 2001-2007 by egnite Software GmbH.
00004  * Copyright (c) 1983, 1993 by The Regents of the University of California.
00005  * Copyright (c) 1993 by Digital Equipment Corporation.
00006  *
00007  * All rights reserved.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted provided that the following conditions
00011  * are met:
00012  *
00013  * 1. Redistributions of source code must retain the above copyright
00014  *    notice, this list of conditions and the following disclaimer.
00015  * 2. Redistributions in binary form must reproduce the above copyright
00016  *    notice, this list of conditions and the following disclaimer in the
00017  *    documentation and/or other materials provided with the distribution.
00018  * 3. Neither the name of the copyright holders nor the names of
00019  *    contributors may be used to endorse or promote products derived
00020  *    from this software without specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00023  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00026  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00029  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00030  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00031  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00032  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00033  * SUCH DAMAGE.
00034  *
00035  * For additional information see http://www.ethernut.de/
00036  */
00037 
00038 /*
00039  * $Log$
00040  * Revision 1.15  2008/10/05 16:48:52  haraldkipp
00041  * Security fix. Check various lengths of incoming packets.
00042  *
00043  * Revision 1.14  2008/08/20 06:57:00  haraldkipp
00044  * Implemented IP demultiplexer.
00045  *
00046  * Revision 1.13  2008/08/11 07:00:30  haraldkipp
00047  * BSD types replaced by stdint types (feature request #1282721).
00048  *
00049  * Revision 1.12  2008/04/18 13:13:11  haraldkipp
00050  * Using fast ints.
00051  *
00052  * Revision 1.11  2007/07/09 16:20:19  olereinhardt
00053  * 2007-07-09  Ole Reinhardt <ole.reinhardt@embedded-it.de>
00054  *         * net/Makefile: Commented in igmp_in.c and igmp_out.c again
00055  *         * net/ipin.c: igmp support reenabled
00056  *
00057  * Revision 1.10  2007/07/09 15:59:00  olereinhardt
00058  * 2007-07-09  Ole Reinhardt <ole.reinhardt@embedded-it.de>
00059  *      * ipin.c: commented out igmp support as long as it does not compile
00060  *
00061  * Revision 1.9  2007/05/02 11:18:32  haraldkipp
00062  * IGMP support added. Incomplete.
00063  *
00064  * Revision 1.8  2007/03/23 12:43:50  haraldkipp
00065  * ARP method wasn't actually disabled by default. Fixed.
00066  *
00067  * Revision 1.7  2006/09/05 12:35:39  haraldkipp
00068  * DHCP servers may probe an IP/MAC relationship by sending an
00069  * ICMP request. This triggered the Nut/Net ARP method and
00070  * terminated the DHCP client, leaving the system with default
00071  * configurations of the network mask (255.255.255.0) and
00072  * default gateway (none). The rarely used ARP method is now
00073  * disabled by default.
00074  *
00075  * Revision 1.6  2006/07/10 17:46:59  haraldkipp
00076  * Now really like Jan suggested to fix it.
00077  *
00078  * Revision 1.5  2006/07/10 08:49:47  haraldkipp
00079  * Do not respond to broadcasts with unknown protocols. Many thanks to Jan.
00080  *
00081  * Revision 1.4  2005/06/05 16:48:26  haraldkipp
00082  * Additional parameter enables NutUdpInput() to avoid responding to UDP
00083  * broadcasts with ICMP unreachable messages. Fixes bug #1215192.
00084  *
00085  * Revision 1.3  2004/12/16 18:48:50  haraldkipp
00086  * Added Damian Slee's IP filter function.
00087  *
00088  * Revision 1.2  2004/02/02 18:59:25  drsung
00089  * Some more ICMP support added.
00090  *
00091  * Revision 1.1.1.1  2003/05/09 14:41:32  haraldkipp
00092  * Initial using 3.2.1
00093  *
00094  * Revision 1.16  2003/05/06 18:14:18  harald
00095  * Allow incoming DHCP telegrams, even if not broadcasted
00096  *
00097  * Revision 1.15  2003/03/31 12:26:05  harald
00098  * Accept masks with all bits set
00099  *
00100  * Revision 1.14  2003/02/04 18:14:57  harald
00101  * Version 3 released
00102  *
00103  * Revision 1.13  2002/06/26 17:29:36  harald
00104  * First pre-release with 2.4 stack
00105  *
00106  */
00107 
00108 #include <cfg/ip.h>
00109 
00110 #include <net/route.h>
00111 #include <netinet/in.h>
00112 #include <netinet/ip.h>
00113 #include <netinet/icmp.h>
00114 #include <netinet/ip_icmp.h>
00115 #include <netinet/igmp.h>
00116 #include <netinet/udp.h>
00117 #include <sys/socket.h>
00118 #include <arpa/inet.h>
00119 
00124 
00125 static NutIpFilterFunc NutIpFilter;
00126 
00140 void NutIpSetInputFilter(NutIpFilterFunc callbackFunc)
00141 {
00142     NutIpFilter = callbackFunc;
00143 }
00144 
00150 int (*ip_demux) (NUTDEVICE *, NETBUF *);
00151 
00165 void NutIpInput(NUTDEVICE * dev, NETBUF * nb)
00166 {
00167     IPHDR *ip;
00168     uint_fast8_t hdrlen;
00169     uint32_t dst;
00170     uint_fast8_t bcast;
00171     IFNET *nif;
00172 
00173     ip = nb->nb_nw.vp;
00174 
00175     /*
00176      * Silently discard datagrams of different IP version as well as
00177      * fragmented or filtered datagrams.
00178      */
00179     if (ip->ip_v != IPVERSION ||        /* Version check. */
00180         (ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK)) != 0 ||      /* Fragmentation. */
00181         (NutIpFilter && NutIpFilter(ip->ip_src))) {     /* Filter. */
00182         NutNetBufFree(nb);
00183         return;
00184     }
00185 
00186     /*
00187     ** IP header length is given in 32-bit fields. Calculate the size in
00188     ** bytes and make sure that the header we know will fit in. Check
00189     ** further, that the header length is not larger than the bytes we
00190     ** received.
00191     */
00192     hdrlen = ip->ip_hl * 4;
00193     if (hdrlen < sizeof(IPHDR) || hdrlen > nb->nb_nw.sz) {
00194         NutNetBufFree(nb);
00195         return;
00196     }
00197 
00198 #if NUT_IP_INCHKSUM
00199     /* Optional checksum calculation on incoming datagrams. */
00200 #endif
00201 
00202     /*
00203      * Check for broadcast.
00204      */
00205     dst = ip->ip_dst;
00206     nif = dev->dev_icb;
00207 
00208     if (dst == INADDR_BROADCAST || 
00209         (nif->if_local_ip && nif->if_mask != INADDR_BROADCAST && (dst | nif->if_mask) == INADDR_BROADCAST)) {
00210         bcast = 1;
00211     }
00212 
00213     /*
00214      * Check for multicast.
00215      */
00216     else if (IN_MULTICAST(dst)) {
00217         MCASTENTRY *mca;
00218 
00219         for (mca = nif->if_mcast; mca; mca = mca->mca_next) {
00220             if (dst == mca->mca_ip) {
00221                 break;
00222             }
00223         }
00224                 if (mca == NULL) {
00225             NutNetBufFree(nb);
00226                         return;
00227                 }
00228         bcast = 2;
00229     }
00230 
00231     /*
00232      * Packet is unicast.
00233      */
00234     else {
00235         bcast = 0;
00236         nb->nb_flags |= NBAF_UNICAST;
00237 
00238 #ifdef NUTIPCONF_ICMP_ARPMETHOD
00239         /*
00240          * Silently discard datagrams for other destinations.
00241          * However, if we haven't got an IP address yet, we
00242          * allow ICMP datagrams to support dynamic IP ARP method,
00243          * if this option had been enabled.
00244          */
00245         if (nif->if_local_ip == 0 && ip->ip_p == IPPROTO_ICMP && (dst & 0xff000000) != 0xff000000 && (dst & 0xff000000) != 0) {
00246             NutNetIfSetup(dev, dst, 0, 0);
00247         }
00248 #endif
00249         if (nif->if_local_ip && (dst == 0 || dst != nif->if_local_ip)) {
00250             NutNetBufFree(nb);
00251             return;
00252         }
00253     }
00254 
00255     /* Check the IP data length. */
00256     nb->nb_tp.sz = htons(ip->ip_len);
00257     if (nb->nb_tp.sz < hdrlen || nb->nb_tp.sz > nb->nb_nw.sz) {
00258         NutNetBufFree(nb);
00259         return;
00260     }
00261     nb->nb_nw.sz = hdrlen;
00262     nb->nb_tp.sz -= hdrlen;
00263     if (nb->nb_tp.sz) {
00264         nb->nb_tp.vp = ((char *) ip) + hdrlen;
00265     }
00266 
00267     if (ip_demux == NULL || (*ip_demux) (dev, nb)) {
00268         switch (ip->ip_p) {
00269         case IPPROTO_ICMP:
00270             NutIcmpInput(dev, nb);
00271             break;
00272         case IPPROTO_IGMP:
00273             NutIgmpInput(dev, nb);
00274             break;
00275         default:
00276             /* Unkown protocol, send ICMP destination (protocol)
00277             * unreachable message.
00278             */
00279             if (bcast || !NutIcmpResponse(ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 0, nb))
00280                 NutNetBufFree(nb);
00281             break;
00282         }
00283     }
00284 }
00285