The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/ip_icmp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: ip_icmp.c,v 1.82.2.2 2004/08/03 22:37:09 jmc Exp $     */
    2 
    3 /*
    4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the project nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  */
   31 
   32 /*-
   33  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
   34  * All rights reserved.
   35  *
   36  * This code is derived from software contributed to The NetBSD Foundation
   37  * by Public Access Networks Corporation ("Panix").  It was developed under
   38  * contract to Panix by Eric Haszlakiewicz and Thor Lancelot Simon.
   39  *
   40  * This code is derived from software contributed to The NetBSD Foundation
   41  * by Jason R. Thorpe of Zembu Labs, Inc.
   42  *
   43  * Redistribution and use in source and binary forms, with or without
   44  * modification, are permitted provided that the following conditions
   45  * are met:
   46  * 1. Redistributions of source code must retain the above copyright
   47  *    notice, this list of conditions and the following disclaimer.
   48  * 2. Redistributions in binary form must reproduce the above copyright
   49  *    notice, this list of conditions and the following disclaimer in the
   50  *    documentation and/or other materials provided with the distribution.
   51  * 3. All advertising materials mentioning features or use of this software
   52  *    must display the following acknowledgement:
   53  *      This product includes software developed by the NetBSD
   54  *      Foundation, Inc. and its contributors.
   55  * 4. Neither the name of The NetBSD Foundation nor the names of its
   56  *    contributors may be used to endorse or promote products derived
   57  *    from this software without specific prior written permission.
   58  *
   59  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   60  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   61  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   62  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   63  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   64  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   65  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   66  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   67  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   68  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   69  * POSSIBILITY OF SUCH DAMAGE.
   70  */
   71 
   72 /*
   73  * Copyright (c) 1982, 1986, 1988, 1993
   74  *      The Regents of the University of California.  All rights reserved.
   75  *
   76  * Redistribution and use in source and binary forms, with or without
   77  * modification, are permitted provided that the following conditions
   78  * are met:
   79  * 1. Redistributions of source code must retain the above copyright
   80  *    notice, this list of conditions and the following disclaimer.
   81  * 2. Redistributions in binary form must reproduce the above copyright
   82  *    notice, this list of conditions and the following disclaimer in the
   83  *    documentation and/or other materials provided with the distribution.
   84  * 3. Neither the name of the University nor the names of its contributors
   85  *    may be used to endorse or promote products derived from this software
   86  *    without specific prior written permission.
   87  *
   88  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   89  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   90  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   91  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   92  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   93  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   94  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   95  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   96  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   97  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   98  * SUCH DAMAGE.
   99  *
  100  *      @(#)ip_icmp.c   8.2 (Berkeley) 1/4/94
  101  */
  102 
  103 #include <sys/cdefs.h>
  104 __KERNEL_RCSID(0, "$NetBSD: ip_icmp.c,v 1.82.2.2 2004/08/03 22:37:09 jmc Exp $");
  105 
  106 #include "opt_ipsec.h"
  107 
  108 #include <sys/param.h>
  109 #include <sys/systm.h>
  110 #include <sys/malloc.h>
  111 #include <sys/mbuf.h>
  112 #include <sys/protosw.h>
  113 #include <sys/socket.h>
  114 #include <sys/time.h>
  115 #include <sys/kernel.h>
  116 #include <sys/syslog.h>
  117 #include <sys/sysctl.h>
  118 
  119 #include <net/if.h>
  120 #include <net/route.h>
  121 
  122 #include <netinet/in.h>
  123 #include <netinet/in_systm.h>
  124 #include <netinet/in_var.h>
  125 #include <netinet/ip.h>
  126 #include <netinet/ip_icmp.h>
  127 #include <netinet/ip_var.h>
  128 #include <netinet/in_pcb.h>
  129 #include <netinet/icmp_var.h>
  130 
  131 #ifdef IPSEC
  132 #include <netinet6/ipsec.h>
  133 #include <netkey/key.h>
  134 #endif
  135 
  136 #ifdef FAST_IPSEC
  137 #include <netipsec/ipsec.h>
  138 #include <netipsec/key.h>
  139 #endif  /* FAST_IPSEC*/
  140 
  141 #include <machine/stdarg.h>
  142 
  143 /*
  144  * ICMP routines: error generation, receive packet processing, and
  145  * routines to turnaround packets back to the originator, and
  146  * host table maintenance routines.
  147  */
  148 
  149 int     icmpmaskrepl = 0;
  150 #ifdef ICMPPRINTFS
  151 int     icmpprintfs = 0;
  152 #endif
  153 int     icmpreturndatabytes = 8;
  154 
  155 struct icmpstat icmpstat;
  156 
  157 /*
  158  * List of callbacks to notify when Path MTU changes are made.
  159  */
  160 struct icmp_mtudisc_callback {
  161         LIST_ENTRY(icmp_mtudisc_callback) mc_list;
  162         void (*mc_func) __P((struct in_addr));
  163 };
  164 
  165 LIST_HEAD(, icmp_mtudisc_callback) icmp_mtudisc_callbacks =
  166     LIST_HEAD_INITIALIZER(&icmp_mtudisc_callbacks);
  167 
  168 #if 0
  169 static int      ip_next_mtu __P((int, int));
  170 #else
  171 /*static*/ int  ip_next_mtu __P((int, int));
  172 #endif
  173 
  174 extern int icmperrppslim;
  175 static int icmperrpps_count = 0;
  176 static struct timeval icmperrppslim_last;
  177 static int icmp_rediraccept = 1;
  178 static int icmp_redirtimeout = 600;
  179 static struct rttimer_queue *icmp_redirect_timeout_q = NULL;
  180 
  181 static void icmp_mtudisc_timeout __P((struct rtentry *, struct rttimer *));
  182 static void icmp_redirect_timeout __P((struct rtentry *, struct rttimer *));
  183 
  184 static int icmp_ratelimit __P((const struct in_addr *, const int, const int));
  185 
  186 
  187 void
  188 icmp_init()
  189 {
  190         /*
  191          * This is only useful if the user initializes redirtimeout to
  192          * something other than zero.
  193          */
  194         if (icmp_redirtimeout != 0) {
  195                 icmp_redirect_timeout_q =
  196                         rt_timer_queue_create(icmp_redirtimeout);
  197         }
  198 }
  199 
  200 /*
  201  * Register a Path MTU Discovery callback.
  202  */
  203 void
  204 icmp_mtudisc_callback_register(func)
  205         void (*func) __P((struct in_addr));
  206 {
  207         struct icmp_mtudisc_callback *mc;
  208 
  209         for (mc = LIST_FIRST(&icmp_mtudisc_callbacks); mc != NULL;
  210              mc = LIST_NEXT(mc, mc_list)) {
  211                 if (mc->mc_func == func)
  212                         return;
  213         }
  214 
  215         mc = malloc(sizeof(*mc), M_PCB, M_NOWAIT);
  216         if (mc == NULL)
  217                 panic("icmp_mtudisc_callback_register");
  218 
  219         mc->mc_func = func;
  220         LIST_INSERT_HEAD(&icmp_mtudisc_callbacks, mc, mc_list);
  221 }
  222 
  223 /*
  224  * Generate an error packet of type error
  225  * in response to bad packet ip.
  226  */
  227 void
  228 icmp_error(n, type, code, dest, destifp)
  229         struct mbuf *n;
  230         int type, code;
  231         n_long dest;
  232         struct ifnet *destifp;
  233 {
  234         struct ip *oip = mtod(n, struct ip *), *nip;
  235         unsigned oiplen = oip->ip_hl << 2;
  236         struct icmp *icp;
  237         struct mbuf *m;
  238         unsigned icmplen, mblen;
  239 
  240 #ifdef ICMPPRINTFS
  241         if (icmpprintfs)
  242                 printf("icmp_error(%x, %d, %d)\n", oip, type, code);
  243 #endif
  244         if (type != ICMP_REDIRECT)
  245                 icmpstat.icps_error++;
  246         /*
  247          * Don't send error if the original packet was encrypted.
  248          * Don't send error if not the first fragment of message.
  249          * Don't error if the old packet protocol was ICMP
  250          * error message, only known informational types.
  251          */
  252         if (n->m_flags & M_DECRYPTED)
  253                 goto freeit;
  254         if (oip->ip_off &~ htons(IP_MF|IP_DF))
  255                 goto freeit;
  256         if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
  257           n->m_len >= oiplen + ICMP_MINLEN &&
  258           !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
  259                 icmpstat.icps_oldicmp++;
  260                 goto freeit;
  261         }
  262         /* Don't send error in response to a multicast or broadcast packet */
  263         if (n->m_flags & (M_BCAST|M_MCAST))
  264                 goto freeit;
  265 
  266         /*
  267          * First, do a rate limitation check.
  268          */
  269         if (icmp_ratelimit(&oip->ip_src, type, code)) {
  270                 /* XXX stat */
  271                 goto freeit;
  272         }
  273 
  274         /*
  275          * Now, formulate icmp message
  276          */
  277         icmplen = oiplen + min(icmpreturndatabytes,
  278             ntohs(oip->ip_len) - oiplen);
  279         /*
  280          * Defend against mbuf chains shorter than oip->ip_len - oiplen:
  281          */
  282         mblen = 0;
  283         for (m = n; m && (mblen < icmplen); m = m->m_next)
  284                 mblen += m->m_len;
  285         icmplen = min(mblen, icmplen);
  286 
  287         /*
  288          * As we are not required to return everything we have,
  289          * we return whatever we can return at ease.
  290          *
  291          * Note that ICMP datagrams longer than 576 octets are out of spec
  292          * according to RFC1812; the limit on icmpreturndatabytes below in
  293          * icmp_sysctl will keep things below that limit.
  294          */
  295 
  296         KASSERT(ICMP_MINLEN <= MCLBYTES);
  297 
  298         if (icmplen + ICMP_MINLEN > MCLBYTES)
  299                 icmplen = MCLBYTES - ICMP_MINLEN;
  300 
  301         m = m_gethdr(M_DONTWAIT, MT_HEADER);
  302         if (m && (icmplen + ICMP_MINLEN > MHLEN)) {
  303                 MCLGET(m, M_DONTWAIT);
  304                 if ((m->m_flags & M_EXT) == 0) {
  305                         m_freem(m);
  306                         m = NULL;
  307                 }
  308         }
  309         if (m == NULL)
  310                 goto freeit;
  311         MCLAIM(m, n->m_owner);
  312         m->m_len = icmplen + ICMP_MINLEN;
  313         if ((m->m_flags & M_EXT) == 0)
  314                 MH_ALIGN(m, m->m_len);
  315         icp = mtod(m, struct icmp *);
  316         if ((u_int)type > ICMP_MAXTYPE)
  317                 panic("icmp_error");
  318         icmpstat.icps_outhist[type]++;
  319         icp->icmp_type = type;
  320         if (type == ICMP_REDIRECT)
  321                 icp->icmp_gwaddr.s_addr = dest;
  322         else {
  323                 icp->icmp_void = 0;
  324                 /*
  325                  * The following assignments assume an overlay with the
  326                  * zeroed icmp_void field.
  327                  */
  328                 if (type == ICMP_PARAMPROB) {
  329                         icp->icmp_pptr = code;
  330                         code = 0;
  331                 } else if (type == ICMP_UNREACH &&
  332                     code == ICMP_UNREACH_NEEDFRAG && destifp)
  333                         icp->icmp_nextmtu = htons(destifp->if_mtu);
  334         }
  335 
  336         icp->icmp_code = code;
  337         m_copydata(n, 0, icmplen, (caddr_t)&icp->icmp_ip);
  338         nip = &icp->icmp_ip;
  339 
  340         /*
  341          * Now, copy old ip header (without options)
  342          * in front of icmp message.
  343          */
  344         if (m->m_data - sizeof(struct ip) < m->m_pktdat)
  345                 panic("icmp len");
  346         m->m_data -= sizeof(struct ip);
  347         m->m_len += sizeof(struct ip);
  348         m->m_pkthdr.len = m->m_len;
  349         m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
  350         nip = mtod(m, struct ip *);
  351         /* ip_v set in ip_output */
  352         nip->ip_hl = sizeof(struct ip) >> 2;
  353         nip->ip_tos = 0;
  354         nip->ip_len = htons(m->m_len);
  355         /* ip_id set in ip_output */
  356         nip->ip_off = htons(0);
  357         /* ip_ttl set in icmp_reflect */
  358         nip->ip_p = IPPROTO_ICMP;
  359         nip->ip_src = oip->ip_src;
  360         nip->ip_dst = oip->ip_dst;
  361         icmp_reflect(m);
  362 
  363 freeit:
  364         m_freem(n);
  365 }
  366 
  367 static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
  368 static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
  369 static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
  370 struct sockaddr_in icmpmask = { 8, 0 };
  371 
  372 /*
  373  * Process a received ICMP message.
  374  */
  375 void
  376 #if __STDC__
  377 icmp_input(struct mbuf *m, ...)
  378 #else
  379 icmp_input(m, va_alist)
  380         struct mbuf *m;
  381         va_dcl
  382 #endif
  383 {
  384         int proto;
  385         struct icmp *icp;
  386         struct ip *ip = mtod(m, struct ip *);
  387         int icmplen;
  388         int i;
  389         struct in_ifaddr *ia;
  390         void *(*ctlfunc) __P((int, struct sockaddr *, void *));
  391         int code;
  392         int hlen;
  393         va_list ap;
  394         struct rtentry *rt;
  395 
  396         va_start(ap, m);
  397         hlen = va_arg(ap, int);
  398         proto = va_arg(ap, int);
  399         va_end(ap);
  400 
  401         /*
  402          * Locate icmp structure in mbuf, and check
  403          * that not corrupted and of at least minimum length.
  404          */
  405         icmplen = ntohs(ip->ip_len) - hlen;
  406 #ifdef ICMPPRINTFS
  407         if (icmpprintfs)
  408                 printf("icmp_input from %x to %x, len %d\n",
  409                     ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr),
  410                     icmplen);
  411 #endif
  412         if (icmplen < ICMP_MINLEN) {
  413                 icmpstat.icps_tooshort++;
  414                 goto freeit;
  415         }
  416         i = hlen + min(icmplen, ICMP_ADVLENMIN);
  417         if (m->m_len < i && (m = m_pullup(m, i)) == 0) {
  418                 icmpstat.icps_tooshort++;
  419                 return;
  420         }
  421         ip = mtod(m, struct ip *);
  422         m->m_len -= hlen;
  423         m->m_data += hlen;
  424         icp = mtod(m, struct icmp *);
  425         /* Don't need to assert alignment, here. */
  426         if (in_cksum(m, icmplen)) {
  427                 icmpstat.icps_checksum++;
  428                 goto freeit;
  429         }
  430         m->m_len += hlen;
  431         m->m_data -= hlen;
  432 
  433 #ifdef ICMPPRINTFS
  434         /*
  435          * Message type specific processing.
  436          */
  437         if (icmpprintfs)
  438                 printf("icmp_input, type %d code %d\n", icp->icmp_type,
  439                     icp->icmp_code);
  440 #endif
  441         if (icp->icmp_type > ICMP_MAXTYPE)
  442                 goto raw;
  443         icmpstat.icps_inhist[icp->icmp_type]++;
  444         code = icp->icmp_code;
  445         switch (icp->icmp_type) {
  446 
  447         case ICMP_UNREACH:
  448                 switch (code) {
  449                         case ICMP_UNREACH_NET:
  450                         case ICMP_UNREACH_HOST:
  451                         case ICMP_UNREACH_PROTOCOL:
  452                         case ICMP_UNREACH_PORT:
  453                         case ICMP_UNREACH_SRCFAIL:
  454                                 code += PRC_UNREACH_NET;
  455                                 break;
  456 
  457                         case ICMP_UNREACH_NEEDFRAG:
  458                                 code = PRC_MSGSIZE;
  459                                 break;
  460 
  461                         case ICMP_UNREACH_NET_UNKNOWN:
  462                         case ICMP_UNREACH_NET_PROHIB:
  463                         case ICMP_UNREACH_TOSNET:
  464                                 code = PRC_UNREACH_NET;
  465                                 break;
  466 
  467                         case ICMP_UNREACH_HOST_UNKNOWN:
  468                         case ICMP_UNREACH_ISOLATED:
  469                         case ICMP_UNREACH_HOST_PROHIB:
  470                         case ICMP_UNREACH_TOSHOST:
  471                                 code = PRC_UNREACH_HOST;
  472                                 break;
  473 
  474                         default:
  475                                 goto badcode;
  476                 }
  477                 goto deliver;
  478 
  479         case ICMP_TIMXCEED:
  480                 if (code > 1)
  481                         goto badcode;
  482                 code += PRC_TIMXCEED_INTRANS;
  483                 goto deliver;
  484 
  485         case ICMP_PARAMPROB:
  486                 if (code > 1)
  487                         goto badcode;
  488                 code = PRC_PARAMPROB;
  489                 goto deliver;
  490 
  491         case ICMP_SOURCEQUENCH:
  492                 if (code)
  493                         goto badcode;
  494                 code = PRC_QUENCH;
  495                 goto deliver;
  496 
  497         deliver:
  498                 /*
  499                  * Problem with datagram; advise higher level routines.
  500                  */
  501                 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
  502                     icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
  503                         icmpstat.icps_badlen++;
  504                         goto freeit;
  505                 }
  506                 if (IN_MULTICAST(icp->icmp_ip.ip_dst.s_addr))
  507                         goto badcode;
  508 #ifdef ICMPPRINTFS
  509                 if (icmpprintfs)
  510                         printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
  511 #endif
  512                 icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
  513                 ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput;
  514                 if (ctlfunc)
  515                         (void) (*ctlfunc)(code, sintosa(&icmpsrc),
  516                             &icp->icmp_ip);
  517                 break;
  518 
  519         badcode:
  520                 icmpstat.icps_badcode++;
  521                 break;
  522 
  523         case ICMP_ECHO:
  524                 icp->icmp_type = ICMP_ECHOREPLY;
  525                 goto reflect;
  526 
  527         case ICMP_TSTAMP:
  528                 if (icmplen < ICMP_TSLEN) {
  529                         icmpstat.icps_badlen++;
  530                         break;
  531                 }
  532                 icp->icmp_type = ICMP_TSTAMPREPLY;
  533                 icp->icmp_rtime = iptime();
  534                 icp->icmp_ttime = icp->icmp_rtime;      /* bogus, do later! */
  535                 goto reflect;
  536 
  537         case ICMP_MASKREQ:
  538                 if (icmpmaskrepl == 0)
  539                         break;
  540                 /*
  541                  * We are not able to respond with all ones broadcast
  542                  * unless we receive it over a point-to-point interface.
  543                  */
  544                 if (icmplen < ICMP_MASKLEN) {
  545                         icmpstat.icps_badlen++;
  546                         break;
  547                 }
  548                 if (ip->ip_dst.s_addr == INADDR_BROADCAST ||
  549                     in_nullhost(ip->ip_dst))
  550                         icmpdst.sin_addr = ip->ip_src;
  551                 else
  552                         icmpdst.sin_addr = ip->ip_dst;
  553                 ia = ifatoia(ifaof_ifpforaddr(sintosa(&icmpdst),
  554                     m->m_pkthdr.rcvif));
  555                 if (ia == 0)
  556                         break;
  557                 icp->icmp_type = ICMP_MASKREPLY;
  558                 icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
  559                 if (in_nullhost(ip->ip_src)) {
  560                         if (ia->ia_ifp->if_flags & IFF_BROADCAST)
  561                                 ip->ip_src = ia->ia_broadaddr.sin_addr;
  562                         else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
  563                                 ip->ip_src = ia->ia_dstaddr.sin_addr;
  564                 }
  565 reflect:
  566                 icmpstat.icps_reflect++;
  567                 icmpstat.icps_outhist[icp->icmp_type]++;
  568                 icmp_reflect(m);
  569                 return;
  570 
  571         case ICMP_REDIRECT:
  572                 if (code > 3)
  573                         goto badcode;
  574                 if (icmp_rediraccept == 0)
  575                         goto freeit;
  576                 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
  577                     icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
  578                         icmpstat.icps_badlen++;
  579                         break;
  580                 }
  581                 /*
  582                  * Short circuit routing redirects to force
  583                  * immediate change in the kernel's routing
  584                  * tables.  The message is also handed to anyone
  585                  * listening on a raw socket (e.g. the routing
  586                  * daemon for use in updating its tables).
  587                  */
  588                 icmpgw.sin_addr = ip->ip_src;
  589                 icmpdst.sin_addr = icp->icmp_gwaddr;
  590 #ifdef  ICMPPRINTFS
  591                 if (icmpprintfs)
  592                         printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst,
  593                             icp->icmp_gwaddr);
  594 #endif
  595                 icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
  596                 rt = NULL;
  597                 rtredirect(sintosa(&icmpsrc), sintosa(&icmpdst),
  598                     (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
  599                     sintosa(&icmpgw), (struct rtentry **)&rt);
  600                 if (rt != NULL && icmp_redirtimeout != 0) {
  601                         i = rt_timer_add(rt, icmp_redirect_timeout,
  602                                          icmp_redirect_timeout_q);
  603                         if (i)
  604                                 log(LOG_ERR, "ICMP:  redirect failed to "
  605                                     "register timeout for route to %x, "
  606                                     "code %d\n",
  607                                     icp->icmp_ip.ip_dst.s_addr, i);
  608                 }
  609                 if (rt != NULL)
  610                         rtfree(rt);
  611 
  612                 pfctlinput(PRC_REDIRECT_HOST, sintosa(&icmpsrc));
  613 #if defined(IPSEC) || defined(FAST_IPSEC)
  614                 key_sa_routechange((struct sockaddr *)&icmpsrc);
  615 #endif
  616                 break;
  617 
  618         /*
  619          * No kernel processing for the following;
  620          * just fall through to send to raw listener.
  621          */
  622         case ICMP_ECHOREPLY:
  623         case ICMP_ROUTERADVERT:
  624         case ICMP_ROUTERSOLICIT:
  625         case ICMP_TSTAMPREPLY:
  626         case ICMP_IREQREPLY:
  627         case ICMP_MASKREPLY:
  628         default:
  629                 break;
  630         }
  631 
  632 raw:
  633         rip_input(m, hlen, proto);
  634         return;
  635 
  636 freeit:
  637         m_freem(m);
  638         return;
  639 }
  640 
  641 /*
  642  * Reflect the ip packet back to the source
  643  */
  644 void
  645 icmp_reflect(m)
  646         struct mbuf *m;
  647 {
  648         struct ip *ip = mtod(m, struct ip *);
  649         struct in_ifaddr *ia;
  650         struct ifaddr *ifa;
  651         struct sockaddr_in *sin = 0;
  652         struct in_addr t;
  653         struct mbuf *opts = 0;
  654         int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
  655 
  656         if (!in_canforward(ip->ip_src) &&
  657             ((ip->ip_src.s_addr & IN_CLASSA_NET) !=
  658              htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) {
  659                 m_freem(m);     /* Bad return address */
  660                 goto done;      /* ip_output() will check for broadcast */
  661         }
  662         t = ip->ip_dst;
  663         ip->ip_dst = ip->ip_src;
  664         /*
  665          * If the incoming packet was addressed directly to us, use
  666          * dst as the src for the reply.  Otherwise (broadcast or
  667          * anonymous), use an address which corresponds to the
  668          * incoming interface, with a preference for the address which
  669          * corresponds to the route to the destination of the ICMP.
  670          */
  671 
  672         /* Look for packet addressed to us */
  673         INADDR_TO_IA(t, ia);
  674 
  675         /* look for packet sent to broadcast address */
  676         if (ia == NULL && m->m_pkthdr.rcvif &&
  677             (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST)) {
  678                 TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrlist, ifa_list) {
  679                         if (ifa->ifa_addr->sa_family != AF_INET)
  680                                 continue;
  681                         if (in_hosteq(t,ifatoia(ifa)->ia_broadaddr.sin_addr)) {
  682                                 ia = ifatoia(ifa);
  683                                 break;
  684                         }
  685                 }
  686         }
  687 
  688         if (ia)
  689                 sin = &ia->ia_addr;
  690 
  691         icmpdst.sin_addr = t;
  692 
  693         /*
  694          * if the packet is addressed somewhere else, compute the
  695          * source address for packets routed back to the source, and
  696          * use that, if it's an address on the interface which
  697          * received the packet
  698          */
  699         if (sin == (struct sockaddr_in *)0 && m->m_pkthdr.rcvif) {
  700                 struct sockaddr_in sin_dst;
  701                 struct route icmproute;
  702                 int errornum;
  703 
  704                 sin_dst.sin_family = AF_INET;
  705                 sin_dst.sin_len = sizeof(struct sockaddr_in);
  706                 sin_dst.sin_addr = ip->ip_dst;
  707                 bzero(&icmproute, sizeof(icmproute));
  708                 errornum = 0;
  709                 sin = in_selectsrc(&sin_dst, &icmproute, 0, NULL, &errornum);
  710                 /* errornum is never used */
  711                 if (icmproute.ro_rt)
  712                         RTFREE(icmproute.ro_rt);
  713                 /* check to make sure sin is a source address on rcvif */
  714                 if (sin) {
  715                         t = sin->sin_addr;
  716                         sin = (struct sockaddr_in *)0;
  717                         INADDR_TO_IA(t, ia);
  718                         while (ia) {
  719                                 if (ia->ia_ifp == m->m_pkthdr.rcvif) {
  720                                         sin = &ia->ia_addr;
  721                                         break;
  722                                 }
  723                                 NEXT_IA_WITH_SAME_ADDR(ia);
  724                         }
  725                 }
  726         }
  727 
  728         /*
  729          * if it was not addressed to us, but the route doesn't go out
  730          * the source interface, pick an address on the source
  731          * interface.  This can happen when routing is asymmetric, or
  732          * when the incoming packet was encapsulated
  733          */
  734         if (sin == (struct sockaddr_in *)0 && m->m_pkthdr.rcvif) {
  735                 TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrlist, ifa_list) {
  736                         if (ifa->ifa_addr->sa_family != AF_INET)
  737                                 continue;
  738                         sin = &(ifatoia(ifa)->ia_addr);
  739                         break;
  740                 }
  741         }
  742 
  743         /*
  744          * The following happens if the packet was not addressed to us,
  745          * and was received on an interface with no IP address:
  746          * We find the first AF_INET address on the first non-loopback
  747          * interface.
  748          */
  749         if (sin == (struct sockaddr_in *)0)
  750                 TAILQ_FOREACH(ia, &in_ifaddrhead, ia_list) {
  751                         if (ia->ia_ifp->if_flags & IFF_LOOPBACK)
  752                                 continue;
  753                         sin = &ia->ia_addr;
  754                         break;
  755                 }
  756 
  757         /*
  758          * If we still didn't find an address, punt.  We could have an
  759          * interface up (and receiving packets) with no address.
  760          */
  761         if (sin == (struct sockaddr_in *)0) {
  762                 m_freem(m);
  763                 goto done;
  764         }
  765 
  766         ip->ip_src = sin->sin_addr;
  767         ip->ip_ttl = MAXTTL;
  768 
  769         if (optlen > 0) {
  770                 u_char *cp;
  771                 int opt, cnt;
  772                 u_int len;
  773 
  774                 /*
  775                  * Retrieve any source routing from the incoming packet;
  776                  * add on any record-route or timestamp options.
  777                  */
  778                 cp = (u_char *) (ip + 1);
  779                 if ((opts = ip_srcroute()) == 0 &&
  780                     (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
  781                         MCLAIM(opts, m->m_owner);
  782                         opts->m_len = sizeof(struct in_addr);
  783                         *mtod(opts, struct in_addr *) = zeroin_addr;
  784                 }
  785                 if (opts) {
  786 #ifdef ICMPPRINTFS
  787                     if (icmpprintfs)
  788                             printf("icmp_reflect optlen %d rt %d => ",
  789                                 optlen, opts->m_len);
  790 #endif
  791                     for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
  792                             opt = cp[IPOPT_OPTVAL];
  793                             if (opt == IPOPT_EOL)
  794                                     break;
  795                             if (opt == IPOPT_NOP)
  796                                     len = 1;
  797                             else {
  798                                     if (cnt < IPOPT_OLEN + sizeof(*cp))
  799                                             break;
  800                                     len = cp[IPOPT_OLEN];
  801                                     if (len < IPOPT_OLEN + sizeof(*cp) ||
  802                                         len > cnt)
  803                                             break;
  804                             }
  805                             /*
  806                              * Should check for overflow, but it "can't happen"
  807                              */
  808                             if (opt == IPOPT_RR || opt == IPOPT_TS ||
  809                                 opt == IPOPT_SECURITY) {
  810                                     bcopy((caddr_t)cp,
  811                                         mtod(opts, caddr_t) + opts->m_len, len);
  812                                     opts->m_len += len;
  813                             }
  814                     }
  815                     /* Terminate & pad, if necessary */
  816                     if ((cnt = opts->m_len % 4) != 0) {
  817                             for (; cnt < 4; cnt++) {
  818                                     *(mtod(opts, caddr_t) + opts->m_len) =
  819                                         IPOPT_EOL;
  820                                     opts->m_len++;
  821                             }
  822                     }
  823 #ifdef ICMPPRINTFS
  824                     if (icmpprintfs)
  825                             printf("%d\n", opts->m_len);
  826 #endif
  827                 }
  828                 /*
  829                  * Now strip out original options by copying rest of first
  830                  * mbuf's data back, and adjust the IP length.
  831                  */
  832                 ip->ip_len = htons(ntohs(ip->ip_len) - optlen);
  833                 ip->ip_hl = sizeof(struct ip) >> 2;
  834                 m->m_len -= optlen;
  835                 if (m->m_flags & M_PKTHDR)
  836                         m->m_pkthdr.len -= optlen;
  837                 optlen += sizeof(struct ip);
  838                 bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
  839                          (unsigned)(m->m_len - sizeof(struct ip)));
  840         }
  841         m_tag_delete_nonpersistent(m);
  842         m->m_flags &= ~(M_BCAST|M_MCAST);
  843 
  844         /*      
  845          * Clear any in-bound checksum flags for this packet.
  846          */
  847         if (m->m_flags & M_PKTHDR)
  848                 m->m_pkthdr.csum_flags = 0;
  849 
  850         icmp_send(m, opts);
  851 done:
  852         if (opts)
  853                 (void)m_free(opts);
  854 }
  855 
  856 /*
  857  * Send an icmp packet back to the ip level,
  858  * after supplying a checksum.
  859  */
  860 void
  861 icmp_send(m, opts)
  862         struct mbuf *m;
  863         struct mbuf *opts;
  864 {
  865         struct ip *ip = mtod(m, struct ip *);
  866         int hlen;
  867         struct icmp *icp;
  868 
  869         hlen = ip->ip_hl << 2;
  870         m->m_data += hlen;
  871         m->m_len -= hlen;
  872         icp = mtod(m, struct icmp *);
  873         icp->icmp_cksum = 0;
  874         icp->icmp_cksum = in_cksum(m, ntohs(ip->ip_len) - hlen);
  875         m->m_data -= hlen;
  876         m->m_len += hlen;
  877 #ifdef ICMPPRINTFS
  878         if (icmpprintfs)
  879                 printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
  880 #endif
  881         (void) ip_output(m, opts, NULL, 0, 
  882             (struct ip_moptions *)NULL, (struct socket *)NULL);
  883 }
  884 
  885 n_time
  886 iptime()
  887 {
  888         struct timeval atv;
  889         u_long t;
  890 
  891         microtime(&atv);
  892         t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
  893         return (htonl(t));
  894 }
  895 
  896 /*
  897  * sysctl helper routine for net.inet.icmp.returndatabytes.  ensures
  898  * that the new value is in the correct range.
  899  */
  900 static int
  901 sysctl_net_inet_icmp_returndatabytes(SYSCTLFN_ARGS)
  902 {
  903         int error, t;
  904         struct sysctlnode node;
  905 
  906         node = *rnode;
  907         node.sysctl_data = &t;
  908         t = icmpreturndatabytes;
  909         error = sysctl_lookup(SYSCTLFN_CALL(&node));
  910         if (error || newp == NULL)
  911                 return (error);
  912 
  913         if (t < 8 || t > 512)
  914                 return (EINVAL);
  915         icmpreturndatabytes = t;
  916 
  917         return (0);
  918 }
  919 
  920 /*
  921  * sysctl helper routine for net.inet.icmp.redirtimeout.  ensures that
  922  * the given value is not less than zero and then resets the timeout
  923  * queue.
  924  */
  925 static int
  926 sysctl_net_inet_icmp_redirtimeout(SYSCTLFN_ARGS)
  927 {
  928         int error, tmp;
  929         struct sysctlnode node;
  930 
  931         node = *rnode;
  932         node.sysctl_data = &tmp;
  933         tmp = icmp_redirtimeout;
  934         error = sysctl_lookup(SYSCTLFN_CALL(&node));
  935         if (error || newp == NULL)
  936                 return (error);
  937         if (tmp < 0)
  938                 return (EINVAL);
  939         icmp_redirtimeout = tmp;
  940 
  941         /*
  942          * was it a *defined* side-effect that anyone even *reading*
  943          * this value causes these things to happen?
  944          */
  945         if (icmp_redirect_timeout_q != NULL) {
  946                 if (icmp_redirtimeout == 0) {
  947                         rt_timer_queue_destroy(icmp_redirect_timeout_q,
  948                             TRUE);
  949                         icmp_redirect_timeout_q = NULL;
  950                 } else {
  951                         rt_timer_queue_change(icmp_redirect_timeout_q,
  952                             icmp_redirtimeout);
  953                 }
  954         } else if (icmp_redirtimeout > 0) {
  955                 icmp_redirect_timeout_q =
  956                     rt_timer_queue_create(icmp_redirtimeout);
  957         }
  958         
  959         return (0);
  960 }
  961 
  962 SYSCTL_SETUP(sysctl_net_inet_icmp_setup, "sysctl net.inet.icmp subtree setup")
  963 {
  964 
  965         sysctl_createv(clog, 0, NULL, NULL,
  966                        CTLFLAG_PERMANENT,
  967                        CTLTYPE_NODE, "net", NULL,
  968                        NULL, 0, NULL, 0,
  969                        CTL_NET, CTL_EOL);
  970         sysctl_createv(clog, 0, NULL, NULL,
  971                        CTLFLAG_PERMANENT,
  972                        CTLTYPE_NODE, "inet", NULL,
  973                        NULL, 0, NULL, 0,
  974                        CTL_NET, PF_INET, CTL_EOL);
  975         sysctl_createv(clog, 0, NULL, NULL,
  976                        CTLFLAG_PERMANENT,
  977                        CTLTYPE_NODE, "icmp",
  978                        SYSCTL_DESCR("ICMPv4 related settings"),
  979                        NULL, 0, NULL, 0,
  980                        CTL_NET, PF_INET, IPPROTO_ICMP, CTL_EOL);
  981 
  982         sysctl_createv(clog, 0, NULL, NULL,
  983                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  984                        CTLTYPE_INT, "maskrepl",
  985                        SYSCTL_DESCR("Respond to ICMP_MASKREQ messages"),
  986                        NULL, 0, &icmpmaskrepl, 0,
  987                        CTL_NET, PF_INET, IPPROTO_ICMP,
  988                        ICMPCTL_MASKREPL, CTL_EOL);
  989         sysctl_createv(clog, 0, NULL, NULL,
  990                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  991                        CTLTYPE_INT, "returndatabytes",
  992                        SYSCTL_DESCR("Number of bytes to return in an ICMP "
  993                                     "error message"),
  994                        sysctl_net_inet_icmp_returndatabytes, 0,
  995                        &icmpreturndatabytes, 0,
  996                        CTL_NET, PF_INET, IPPROTO_ICMP,
  997                        ICMPCTL_RETURNDATABYTES, CTL_EOL);
  998         sysctl_createv(clog, 0, NULL, NULL,
  999                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
 1000                        CTLTYPE_INT, "errppslimit",
 1001                        SYSCTL_DESCR("Maximum number of outgoing ICMP error "
 1002                                     "messages per second"),
 1003                        NULL, 0, &icmperrppslim, 0,
 1004                        CTL_NET, PF_INET, IPPROTO_ICMP,
 1005                        ICMPCTL_ERRPPSLIMIT, CTL_EOL);
 1006         sysctl_createv(clog, 0, NULL, NULL,
 1007                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
 1008                        CTLTYPE_INT, "rediraccept",
 1009                        SYSCTL_DESCR("Accept ICMP_REDIRECT messages"),
 1010                        NULL, 0, &icmp_rediraccept, 0,
 1011                        CTL_NET, PF_INET, IPPROTO_ICMP,
 1012                        ICMPCTL_REDIRACCEPT, CTL_EOL);
 1013         sysctl_createv(clog, 0, NULL, NULL,
 1014                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
 1015                        CTLTYPE_INT, "redirtimeout",
 1016                        SYSCTL_DESCR("Lifetime of ICMP_REDIRECT generated "
 1017                                     "routes"),
 1018                        sysctl_net_inet_icmp_redirtimeout, 0,
 1019                        &icmp_redirtimeout, 0,
 1020                        CTL_NET, PF_INET, IPPROTO_ICMP,
 1021                        ICMPCTL_REDIRTIMEOUT, CTL_EOL);
 1022 }
 1023 
 1024 /* Table of common MTUs: */
 1025 
 1026 static const u_int mtu_table[] = {
 1027         65535, 65280, 32000, 17914, 9180, 8166,
 1028         4352, 2002, 1492, 1006, 508, 296, 68, 0
 1029 };
 1030 
 1031 void
 1032 icmp_mtudisc(icp, faddr)
 1033         struct icmp *icp;
 1034         struct in_addr faddr;
 1035 {
 1036         struct icmp_mtudisc_callback *mc;
 1037         struct sockaddr *dst = sintosa(&icmpsrc);
 1038         struct rtentry *rt;
 1039         u_long mtu = ntohs(icp->icmp_nextmtu);  /* Why a long?  IPv6 */
 1040         int    error;
 1041 
 1042         rt = rtalloc1(dst, 1);
 1043         if (rt == 0)
 1044                 return;
 1045 
 1046         /* If we didn't get a host route, allocate one */
 1047 
 1048         if ((rt->rt_flags & RTF_HOST) == 0) {
 1049                 struct rtentry *nrt;
 1050 
 1051                 error = rtrequest((int) RTM_ADD, dst,
 1052                     (struct sockaddr *) rt->rt_gateway,
 1053                     (struct sockaddr *) 0,
 1054                     RTF_GATEWAY | RTF_HOST | RTF_DYNAMIC, &nrt);
 1055                 if (error) {
 1056                         rtfree(rt);
 1057                         return;
 1058                 }
 1059                 nrt->rt_rmx = rt->rt_rmx;
 1060                 rtfree(rt);
 1061                 rt = nrt;
 1062         }
 1063         error = rt_timer_add(rt, icmp_mtudisc_timeout, ip_mtudisc_timeout_q);
 1064         if (error) {
 1065                 rtfree(rt);
 1066                 return;
 1067         }
 1068 
 1069         if (mtu == 0) {
 1070                 int i = 0;
 1071 
 1072                 mtu = ntohs(icp->icmp_ip.ip_len);
 1073                 /* Some 4.2BSD-based routers incorrectly adjust the ip_len */
 1074                 if (mtu > rt->rt_rmx.rmx_mtu && rt->rt_rmx.rmx_mtu != 0)
 1075                         mtu -= (icp->icmp_ip.ip_hl << 2);
 1076 
 1077                 /* If we still can't guess a value, try the route */
 1078 
 1079                 if (mtu == 0) {
 1080                         mtu = rt->rt_rmx.rmx_mtu;
 1081 
 1082                         /* If no route mtu, default to the interface mtu */
 1083 
 1084                         if (mtu == 0)
 1085                                 mtu = rt->rt_ifp->if_mtu;
 1086                 }
 1087 
 1088                 for (i = 0; i < sizeof(mtu_table) / sizeof(mtu_table[0]); i++)
 1089                         if (mtu > mtu_table[i]) {
 1090                                 mtu = mtu_table[i];
 1091                                 break;
 1092                         }
 1093         }
 1094 
 1095         /*
 1096          * XXX:   RTV_MTU is overloaded, since the admin can set it
 1097          *        to turn off PMTU for a route, and the kernel can
 1098          *        set it to indicate a serious problem with PMTU
 1099          *        on a route.  We should be using a separate flag
 1100          *        for the kernel to indicate this.
 1101          */
 1102 
 1103         if ((rt->rt_rmx.rmx_locks & RTV_MTU) == 0) {
 1104                 if (mtu < 296 || mtu > rt->rt_ifp->if_mtu)
 1105                         rt->rt_rmx.rmx_locks |= RTV_MTU;
 1106                 else if (rt->rt_rmx.rmx_mtu > mtu ||
 1107                          rt->rt_rmx.rmx_mtu == 0) {
 1108                         icmpstat.icps_pmtuchg++;
 1109                         rt->rt_rmx.rmx_mtu = mtu;
 1110                 }
 1111         }
 1112 
 1113         if (rt)
 1114                 rtfree(rt);
 1115 
 1116         /*
 1117          * Notify protocols that the MTU for this destination
 1118          * has changed.
 1119          */
 1120         for (mc = LIST_FIRST(&icmp_mtudisc_callbacks); mc != NULL;
 1121              mc = LIST_NEXT(mc, mc_list))
 1122                 (*mc->mc_func)(faddr);
 1123 }
 1124 
 1125 /*
 1126  * Return the next larger or smaller MTU plateau (table from RFC 1191)
 1127  * given current value MTU.  If DIR is less than zero, a larger plateau
 1128  * is returned; otherwise, a smaller value is returned.
 1129  */
 1130 int
 1131 ip_next_mtu(mtu, dir)   /* XXX */
 1132         int mtu;
 1133         int dir;
 1134 {
 1135         int i;
 1136 
 1137         for (i = 0; i < (sizeof mtu_table) / (sizeof mtu_table[0]); i++) {
 1138                 if (mtu >= mtu_table[i])
 1139                         break;
 1140         }
 1141 
 1142         if (dir < 0) {
 1143                 if (i == 0) {
 1144                         return 0;
 1145                 } else {
 1146                         return mtu_table[i - 1];
 1147                 }
 1148         } else {
 1149                 if (mtu_table[i] == 0) {
 1150                         return 0;
 1151                 } else if (mtu > mtu_table[i]) {
 1152                         return mtu_table[i];
 1153                 } else {
 1154                         return mtu_table[i + 1];
 1155                 }
 1156         }
 1157 }
 1158 
 1159 static void
 1160 icmp_mtudisc_timeout(rt, r)
 1161         struct rtentry *rt;
 1162         struct rttimer *r;
 1163 {
 1164         if (rt == NULL)
 1165                 panic("icmp_mtudisc_timeout:  bad route to timeout");
 1166         if ((rt->rt_flags & (RTF_DYNAMIC | RTF_HOST)) ==
 1167             (RTF_DYNAMIC | RTF_HOST)) {
 1168                 rtrequest((int) RTM_DELETE, (struct sockaddr *)rt_key(rt),
 1169                     rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
 1170         } else {
 1171                 if ((rt->rt_rmx.rmx_locks & RTV_MTU) == 0) {
 1172                         rt->rt_rmx.rmx_mtu = 0;
 1173                 }
 1174         }
 1175 }
 1176 
 1177 static void
 1178 icmp_redirect_timeout(rt, r)
 1179         struct rtentry *rt;
 1180         struct rttimer *r;
 1181 {
 1182         if (rt == NULL)
 1183                 panic("icmp_redirect_timeout:  bad route to timeout");
 1184         if ((rt->rt_flags & (RTF_DYNAMIC | RTF_HOST)) ==
 1185             (RTF_DYNAMIC | RTF_HOST)) {
 1186                 rtrequest((int) RTM_DELETE, (struct sockaddr *)rt_key(rt),
 1187                     rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
 1188         }
 1189 }
 1190 
 1191 /*
 1192  * Perform rate limit check.
 1193  * Returns 0 if it is okay to send the icmp packet.
 1194  * Returns 1 if the router SHOULD NOT send this icmp packet due to rate
 1195  * limitation.
 1196  *
 1197  * XXX per-destination/type check necessary?
 1198  */
 1199 static int
 1200 icmp_ratelimit(dst, type, code)
 1201         const struct in_addr *dst;
 1202         const int type;                 /* not used at this moment */
 1203         const int code;                 /* not used at this moment */
 1204 {
 1205 
 1206         /* PPS limit */
 1207         if (!ppsratecheck(&icmperrppslim_last, &icmperrpps_count,
 1208             icmperrppslim)) {
 1209                 /* The packet is subject to rate limit */
 1210                 return 1;
 1211         }
 1212 
 1213         /*okay to send*/
 1214         return 0;
 1215 }

Cache object: 16f08f49cacd1e250c91d135cdd4f396


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.