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 /*
    2  * Copyright (c) 1982, 1986, 1988, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by the University of
   16  *      California, Berkeley and its contributors.
   17  * 4. Neither the name of the University nor the names of its contributors
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  *
   33  *      @(#)ip_icmp.c   8.2 (Berkeley) 1/4/94
   34  * $FreeBSD: src/sys/netinet/ip_icmp.c,v 1.22.2.6 2000/06/26 20:49:21 alfred Exp $
   35  */
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/malloc.h>
   40 #include <sys/mbuf.h>
   41 #include <sys/protosw.h>
   42 #include <sys/socket.h>
   43 #include <sys/time.h>
   44 #include <sys/kernel.h>
   45 #include <sys/socket.h>
   46 #include <sys/sysctl.h>
   47 
   48 #include <net/if.h>
   49 #include <net/route.h>
   50 
   51 #define _IP_VHL
   52 #include <netinet/in.h>
   53 #include <netinet/in_systm.h>
   54 #include <netinet/in_var.h>
   55 #include <netinet/ip.h>
   56 #include <netinet/ip_icmp.h>
   57 #include <netinet/ip_var.h>
   58 #include <netinet/icmp_var.h>
   59 
   60 /*
   61  * ICMP routines: error generation, receive packet processing, and
   62  * routines to turnaround packets back to the originator, and
   63  * host table maintenance routines.
   64  */
   65 
   66 static struct   icmpstat icmpstat;
   67 SYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RD,
   68         &icmpstat, icmpstat, "");
   69 
   70 static int      icmpmaskrepl = 0;
   71 SYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW,
   72         &icmpmaskrepl, 0, "");
   73 
   74 static int      icmpbmcastecho = 1;
   75 SYSCTL_INT(_net_inet_icmp, OID_AUTO, bmcastecho, CTLFLAG_RW, &icmpbmcastecho,
   76            0, "");
   77 
   78 #ifdef ICMPPRINTFS
   79 int     icmpprintfs = 0;
   80 #endif
   81 
   82 static void     icmp_reflect __P((struct mbuf *));
   83 static void     icmp_send __P((struct mbuf *, struct mbuf *));
   84 static int      ip_next_mtu __P((int, int));
   85 
   86 extern  struct protosw inetsw[];
   87 
   88 /*
   89  * Generate an error packet of type error
   90  * in response to bad packet ip.
   91  */
   92 void
   93 icmp_error(n, type, code, dest, destifp)
   94         struct mbuf *n;
   95         int type, code;
   96         n_long dest;
   97         struct ifnet *destifp;
   98 {
   99         register struct ip *oip = mtod(n, struct ip *), *nip;
  100         register unsigned oiplen = IP_VHL_HL(oip->ip_vhl) << 2;
  101         register struct icmp *icp;
  102         register struct mbuf *m;
  103         unsigned icmplen;
  104 
  105 #ifdef ICMPPRINTFS
  106         if (icmpprintfs)
  107                 printf("icmp_error(%p, %x, %d)\n", oip, type, code);
  108 #endif
  109         if (type != ICMP_REDIRECT)
  110                 icmpstat.icps_error++;
  111         /*
  112          * Don't send error if not the first fragment of message.
  113          * Don't error if the old packet protocol was ICMP
  114          * error message, only known informational types.
  115          */
  116         if (oip->ip_off &~ (IP_MF|IP_DF))
  117                 goto freeit;
  118         if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
  119           n->m_len >= oiplen + ICMP_MINLEN &&
  120           !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
  121                 icmpstat.icps_oldicmp++;
  122                 goto freeit;
  123         }
  124         /* Don't send error in response to a multicast or broadcast packet */
  125         if (n->m_flags & (M_BCAST|M_MCAST))
  126                 goto freeit;
  127         /*
  128          * First, formulate icmp message
  129          */
  130         m = m_gethdr(M_DONTWAIT, MT_HEADER);
  131         if (m == NULL)
  132                 goto freeit;
  133         icmplen = oiplen + min(8, oip->ip_len);
  134         m->m_len = icmplen + ICMP_MINLEN;
  135         MH_ALIGN(m, m->m_len);
  136         icp = mtod(m, struct icmp *);
  137         if ((u_int)type > ICMP_MAXTYPE)
  138                 panic("icmp_error");
  139         icmpstat.icps_outhist[type]++;
  140         icp->icmp_type = type;
  141         if (type == ICMP_REDIRECT)
  142                 icp->icmp_gwaddr.s_addr = dest;
  143         else {
  144                 icp->icmp_void = 0;
  145                 /*
  146                  * The following assignments assume an overlay with the
  147                  * zeroed icmp_void field.
  148                  */
  149                 if (type == ICMP_PARAMPROB) {
  150                         icp->icmp_pptr = code;
  151                         code = 0;
  152                 } else if (type == ICMP_UNREACH &&
  153                         code == ICMP_UNREACH_NEEDFRAG && destifp) {
  154                         icp->icmp_nextmtu = htons(destifp->if_mtu);
  155                 }
  156         }
  157 
  158         icp->icmp_code = code;
  159         bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
  160         nip = &icp->icmp_ip;
  161         nip->ip_len = htons((u_short)(nip->ip_len + oiplen));
  162 
  163         /*
  164          * Now, copy old ip header (without options)
  165          * in front of icmp message.
  166          */
  167         if (m->m_data - sizeof(struct ip) < m->m_pktdat)
  168                 panic("icmp len");
  169         m->m_data -= sizeof(struct ip);
  170         m->m_len += sizeof(struct ip);
  171         m->m_pkthdr.len = m->m_len;
  172         m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
  173         nip = mtod(m, struct ip *);
  174         bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip));
  175         nip->ip_len = m->m_len;
  176         nip->ip_vhl = IP_VHL_BORING;
  177         nip->ip_p = IPPROTO_ICMP;
  178         nip->ip_tos = 0;
  179         icmp_reflect(m);
  180 
  181 freeit:
  182         m_freem(n);
  183 }
  184 
  185 static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
  186 static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
  187 static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
  188 
  189 /*
  190  * Process a received ICMP message.
  191  */
  192 void
  193 icmp_input(m, hlen)
  194         register struct mbuf *m;
  195         int hlen;
  196 {
  197         register struct icmp *icp;
  198         register struct ip *ip = mtod(m, struct ip *);
  199         int icmplen = ip->ip_len;
  200         register int i;
  201         struct in_ifaddr *ia;
  202         void (*ctlfunc) __P((int, struct sockaddr *, void *));
  203         int code;
  204 
  205         /*
  206          * Locate icmp structure in mbuf, and check
  207          * that not corrupted and of at least minimum length.
  208          */
  209 #ifdef ICMPPRINTFS
  210         if (icmpprintfs) {
  211                 char buf[4 * sizeof "123"];
  212                 strcpy(buf, inet_ntoa(ip->ip_src));
  213                 printf("icmp_input from %s to %s, len %d\n",
  214                        buf, inet_ntoa(ip->ip_dst), icmplen);
  215         }
  216 #endif
  217         if (icmplen < ICMP_MINLEN) {
  218                 icmpstat.icps_tooshort++;
  219                 goto freeit;
  220         }
  221         i = hlen + min(icmplen, ICMP_ADVLENMIN);
  222         if (m->m_len < i && (m = m_pullup(m, i)) == 0)  {
  223                 icmpstat.icps_tooshort++;
  224                 return;
  225         }
  226         ip = mtod(m, struct ip *);
  227         m->m_len -= hlen;
  228         m->m_data += hlen;
  229         icp = mtod(m, struct icmp *);
  230         if (in_cksum(m, icmplen)) {
  231                 icmpstat.icps_checksum++;
  232                 goto freeit;
  233         }
  234         m->m_len += hlen;
  235         m->m_data -= hlen;
  236 
  237 #ifdef ICMPPRINTFS
  238         if (icmpprintfs)
  239                 printf("icmp_input, type %d code %d\n", icp->icmp_type,
  240                     icp->icmp_code);
  241 #endif
  242 
  243         /*
  244          * Message type specific processing.
  245          */
  246         if (icp->icmp_type > ICMP_MAXTYPE)
  247                 goto raw;
  248         icmpstat.icps_inhist[icp->icmp_type]++;
  249         code = icp->icmp_code;
  250         switch (icp->icmp_type) {
  251 
  252         case ICMP_UNREACH:
  253                 switch (code) {
  254                         case ICMP_UNREACH_NET:
  255                         case ICMP_UNREACH_HOST:
  256                         case ICMP_UNREACH_PROTOCOL:
  257                         case ICMP_UNREACH_PORT:
  258                         case ICMP_UNREACH_SRCFAIL:
  259                                 code += PRC_UNREACH_NET;
  260                                 break;
  261 
  262                         case ICMP_UNREACH_NEEDFRAG:
  263                                 code = PRC_MSGSIZE;
  264                                 break;
  265 
  266                         case ICMP_UNREACH_NET_UNKNOWN:
  267                         case ICMP_UNREACH_NET_PROHIB:
  268                         case ICMP_UNREACH_TOSNET:
  269                                 code = PRC_UNREACH_NET;
  270                                 break;
  271 
  272                         case ICMP_UNREACH_HOST_UNKNOWN:
  273                         case ICMP_UNREACH_ISOLATED:
  274                         case ICMP_UNREACH_HOST_PROHIB:
  275                         case ICMP_UNREACH_TOSHOST:
  276                                 code = PRC_UNREACH_HOST;
  277                                 break;
  278 
  279                         case ICMP_UNREACH_FILTER_PROHIB:
  280                         case ICMP_UNREACH_HOST_PRECEDENCE:
  281                         case ICMP_UNREACH_PRECEDENCE_CUTOFF:
  282                                 code = PRC_UNREACH_PORT;
  283                                 break;
  284 
  285                         default:
  286                                 goto badcode;
  287                 }
  288                 goto deliver;
  289 
  290         case ICMP_TIMXCEED:
  291                 if (code > 1)
  292                         goto badcode;
  293                 code += PRC_TIMXCEED_INTRANS;
  294                 goto deliver;
  295 
  296         case ICMP_PARAMPROB:
  297                 if (code > 1)
  298                         goto badcode;
  299                 code = PRC_PARAMPROB;
  300                 goto deliver;
  301 
  302         case ICMP_SOURCEQUENCH:
  303                 if (code)
  304                         goto badcode;
  305                 code = PRC_QUENCH;
  306         deliver:
  307                 /*
  308                  * Problem with datagram; advise higher level routines.
  309                  */
  310                 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
  311                     IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) {
  312                         icmpstat.icps_badlen++;
  313                         goto freeit;
  314                 }
  315                 NTOHS(icp->icmp_ip.ip_len);
  316                 /* Discard ICMP's in response to multicast packets */
  317                 if (IN_MULTICAST(ntohl(icp->icmp_ip.ip_dst.s_addr)))
  318                         goto badcode;
  319 #ifdef ICMPPRINTFS
  320                 if (icmpprintfs)
  321                         printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
  322 #endif
  323                 icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
  324 #if 1
  325                 /*
  326                  * MTU discovery:
  327                  * If we got a needfrag and there is a host route to the
  328                  * original destination, and the MTU is not locked, then
  329                  * set the MTU in the route to the suggested new value
  330                  * (if given) and then notify as usual.  The ULPs will
  331                  * notice that the MTU has changed and adapt accordingly.
  332                  * If no new MTU was suggested, then we guess a new one
  333                  * less than the current value.  If the new MTU is 
  334                  * unreasonably small (arbitrarily set at 296), then
  335                  * we reset the MTU to the interface value and enable the
  336                  * lock bit, indicating that we are no longer doing MTU
  337                  * discovery.
  338                  */
  339                 if (code == PRC_MSGSIZE) {
  340                         struct rtentry *rt;
  341                         int mtu;
  342 
  343                         rt = rtalloc1((struct sockaddr *)&icmpsrc, 0,
  344                                       RTF_CLONING | RTF_PRCLONING);
  345                         if (rt && (rt->rt_flags & RTF_HOST)
  346                             && !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
  347                                 mtu = ntohs(icp->icmp_nextmtu);
  348                                 if (!mtu)
  349                                         mtu = ip_next_mtu(rt->rt_rmx.rmx_mtu,
  350                                                           1);
  351 #ifdef DEBUG_MTUDISC
  352                                 printf("MTU for %s reduced to %d\n",
  353                                         inet_ntoa(icmpsrc.sin_addr), mtu);
  354 #endif
  355                                 if (mtu < 296) {
  356                                         /* rt->rt_rmx.rmx_mtu =
  357                                                 rt->rt_ifp->if_mtu; */
  358                                         rt->rt_rmx.rmx_locks |= RTV_MTU;
  359                                 } else if (rt->rt_rmx.rmx_mtu > mtu) {
  360                                         rt->rt_rmx.rmx_mtu = mtu;
  361                                 }
  362                         }
  363                         if (rt)
  364                                 RTFREE(rt);
  365                 }
  366 
  367 #endif
  368                 ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput;
  369                 if (ctlfunc)
  370                         (*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
  371                                    (void *)&icp->icmp_ip);
  372                 break;
  373 
  374         badcode:
  375                 icmpstat.icps_badcode++;
  376                 break;
  377 
  378         case ICMP_ECHO:
  379                 if (!icmpbmcastecho
  380                     && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
  381                         icmpstat.icps_bmcastecho++;
  382                         break;
  383                 }
  384                 icp->icmp_type = ICMP_ECHOREPLY;
  385                 goto reflect;
  386 
  387         case ICMP_TSTAMP:
  388                 if (!icmpbmcastecho
  389                     && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
  390                         icmpstat.icps_bmcasttstamp++;
  391                         break;
  392                 }
  393                 if (icmplen < ICMP_TSLEN) {
  394                         icmpstat.icps_badlen++;
  395                         break;
  396                 }
  397                 icp->icmp_type = ICMP_TSTAMPREPLY;
  398                 icp->icmp_rtime = iptime();
  399                 icp->icmp_ttime = icp->icmp_rtime;      /* bogus, do later! */
  400                 goto reflect;
  401 
  402         case ICMP_MASKREQ:
  403 #define satosin(sa)     ((struct sockaddr_in *)(sa))
  404                 if (icmpmaskrepl == 0)
  405                         break;
  406                 /*
  407                  * We are not able to respond with all ones broadcast
  408                  * unless we receive it over a point-to-point interface.
  409                  */
  410                 if (icmplen < ICMP_MASKLEN)
  411                         break;
  412                 switch (ip->ip_dst.s_addr) {
  413 
  414                 case INADDR_BROADCAST:
  415                 case INADDR_ANY:
  416                         icmpdst.sin_addr = ip->ip_src;
  417                         break;
  418 
  419                 default:
  420                         icmpdst.sin_addr = ip->ip_dst;
  421                 }
  422                 ia = (struct in_ifaddr *)ifaof_ifpforaddr(
  423                             (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
  424                 if (ia == 0)
  425                         break;
  426                 if (ia->ia_ifp == 0)
  427                         break;
  428                 icp->icmp_type = ICMP_MASKREPLY;
  429                 icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
  430                 if (ip->ip_src.s_addr == 0) {
  431                         if (ia->ia_ifp->if_flags & IFF_BROADCAST)
  432                             ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
  433                         else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
  434                             ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
  435                 }
  436 reflect:
  437                 ip->ip_len += hlen;     /* since ip_input deducts this */
  438                 icmpstat.icps_reflect++;
  439                 icmpstat.icps_outhist[icp->icmp_type]++;
  440                 icmp_reflect(m);
  441                 return;
  442 
  443         case ICMP_REDIRECT:
  444                 if (code > 3)
  445                         goto badcode;
  446                 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
  447                     IP_VHL_HL(icp->icmp_ip.ip_vhl) < (sizeof(struct ip) >> 2)) {
  448                         icmpstat.icps_badlen++;
  449                         break;
  450                 }
  451                 /*
  452                  * Short circuit routing redirects to force
  453                  * immediate change in the kernel's routing
  454                  * tables.  The message is also handed to anyone
  455                  * listening on a raw socket (e.g. the routing
  456                  * daemon for use in updating its tables).
  457                  */
  458                 icmpgw.sin_addr = ip->ip_src;
  459                 icmpdst.sin_addr = icp->icmp_gwaddr;
  460 #ifdef  ICMPPRINTFS
  461                 if (icmpprintfs) {
  462                         char buf[4 * sizeof "123"];
  463                         strcpy(buf, inet_ntoa(icp->icmp_ip.ip_dst));
  464 
  465                         printf("redirect dst %s to %s\n",
  466                                buf, inet_ntoa(icp->icmp_gwaddr));
  467                 }
  468 #endif
  469                 icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
  470                 rtredirect((struct sockaddr *)&icmpsrc,
  471                   (struct sockaddr *)&icmpdst,
  472                   (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
  473                   (struct sockaddr *)&icmpgw, (struct rtentry **)0);
  474                 pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc);
  475                 break;
  476 
  477         /*
  478          * No kernel processing for the following;
  479          * just fall through to send to raw listener.
  480          */
  481         case ICMP_ECHOREPLY:
  482         case ICMP_ROUTERADVERT:
  483         case ICMP_ROUTERSOLICIT:
  484         case ICMP_TSTAMPREPLY:
  485         case ICMP_IREQREPLY:
  486         case ICMP_MASKREPLY:
  487         default:
  488                 break;
  489         }
  490 
  491 raw:
  492         rip_input(m, hlen);
  493         return;
  494 
  495 freeit:
  496         m_freem(m);
  497 }
  498 
  499 /*
  500  * Reflect the ip packet back to the source
  501  */
  502 static void
  503 icmp_reflect(m)
  504         struct mbuf *m;
  505 {
  506         register struct ip *ip = mtod(m, struct ip *);
  507         register struct in_ifaddr *ia;
  508         struct in_addr t;
  509         struct mbuf *opts = 0;
  510         int optlen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof(struct ip);
  511 
  512         if (!in_canforward(ip->ip_src) &&
  513             ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) !=
  514              (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) {
  515                 m_freem(m);     /* Bad return address */
  516                 goto done;      /* Ip_output() will check for broadcast */
  517         }
  518         t = ip->ip_dst;
  519         ip->ip_dst = ip->ip_src;
  520         /*
  521          * If the incoming packet was addressed directly to us,
  522          * use dst as the src for the reply.  Otherwise (broadcast
  523          * or anonymous), use the address which corresponds
  524          * to the incoming interface.
  525          */
  526         for (ia = in_ifaddr; ia; ia = ia->ia_next) {
  527                 if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
  528                         break;
  529                 if (ia->ia_ifp && (ia->ia_ifp->if_flags & IFF_BROADCAST) &&
  530                     t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
  531                         break;
  532         }
  533         icmpdst.sin_addr = t;
  534         if ((ia == (struct in_ifaddr *)0) && m->m_pkthdr.rcvif)
  535                 ia = (struct in_ifaddr *)ifaof_ifpforaddr(
  536                         (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
  537         /*
  538          * The following happens if the packet was not addressed to us,
  539          * and was received on an interface with no IP address.
  540          */
  541         if (ia == (struct in_ifaddr *)0)
  542                 ia = in_ifaddr;
  543         t = IA_SIN(ia)->sin_addr;
  544         ip->ip_src = t;
  545         ip->ip_ttl = MAXTTL;
  546 
  547         if (optlen > 0) {
  548                 register u_char *cp;
  549                 int opt, cnt;
  550                 u_int len;
  551 
  552                 /*
  553                  * Retrieve any source routing from the incoming packet;
  554                  * add on any record-route or timestamp options.
  555                  */
  556                 cp = (u_char *) (ip + 1);
  557                 if ((opts = ip_srcroute()) == 0 &&
  558                     (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
  559                         opts->m_len = sizeof(struct in_addr);
  560                         mtod(opts, struct in_addr *)->s_addr = 0;
  561                 }
  562                 if (opts) {
  563 #ifdef ICMPPRINTFS
  564                     if (icmpprintfs)
  565                             printf("icmp_reflect optlen %d rt %d => ",
  566                                 optlen, opts->m_len);
  567 #endif
  568                     for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
  569                             opt = cp[IPOPT_OPTVAL];
  570                             if (opt == IPOPT_EOL)
  571                                     break;
  572                             if (opt == IPOPT_NOP)
  573                                     len = 1;
  574                             else {
  575                                     if (cnt < IPOPT_OLEN + sizeof(*cp))
  576                                             break;
  577                                     len = cp[IPOPT_OLEN];
  578                                     if (len < IPOPT_OLEN + sizeof(*cp) ||
  579                                         len > cnt)
  580                                             break;
  581                             }
  582                             /*
  583                              * Should check for overflow, but it "can't happen"
  584                              */
  585                             if (opt == IPOPT_RR || opt == IPOPT_TS ||
  586                                 opt == IPOPT_SECURITY) {
  587                                     bcopy((caddr_t)cp,
  588                                         mtod(opts, caddr_t) + opts->m_len, len);
  589                                     opts->m_len += len;
  590                             }
  591                     }
  592                     /* Terminate & pad, if necessary */
  593                     cnt = opts->m_len % 4;
  594                     if (cnt) {
  595                             for (; cnt < 4; cnt++) {
  596                                     *(mtod(opts, caddr_t) + opts->m_len) =
  597                                         IPOPT_EOL;
  598                                     opts->m_len++;
  599                             }
  600                     }
  601 #ifdef ICMPPRINTFS
  602                     if (icmpprintfs)
  603                             printf("%d\n", opts->m_len);
  604 #endif
  605                 }
  606                 /*
  607                  * Now strip out original options by copying rest of first
  608                  * mbuf's data back, and adjust the IP length.
  609                  */
  610                 ip->ip_len -= optlen;
  611                 ip->ip_vhl = IP_VHL_BORING;
  612                 m->m_len -= optlen;
  613                 if (m->m_flags & M_PKTHDR)
  614                         m->m_pkthdr.len -= optlen;
  615                 optlen += sizeof(struct ip);
  616                 bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
  617                          (unsigned)(m->m_len - sizeof(struct ip)));
  618         }
  619         m->m_flags &= ~(M_BCAST|M_MCAST);
  620         icmp_send(m, opts);
  621 done:
  622         if (opts)
  623                 (void)m_free(opts);
  624 }
  625 
  626 /*
  627  * Send an icmp packet back to the ip level,
  628  * after supplying a checksum.
  629  */
  630 static void
  631 icmp_send(m, opts)
  632         register struct mbuf *m;
  633         struct mbuf *opts;
  634 {
  635         register struct ip *ip = mtod(m, struct ip *);
  636         register int hlen;
  637         register struct icmp *icp;
  638         struct route ro;
  639 
  640         hlen = IP_VHL_HL(ip->ip_vhl) << 2;
  641         m->m_data += hlen;
  642         m->m_len -= hlen;
  643         icp = mtod(m, struct icmp *);
  644         icp->icmp_cksum = 0;
  645         icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
  646         m->m_data -= hlen;
  647         m->m_len += hlen;
  648         m->m_pkthdr.rcvif = (struct ifnet *)0;
  649 #ifdef ICMPPRINTFS
  650         if (icmpprintfs) {
  651                 char buf[4 * sizeof "123"];
  652                 strcpy(buf, inet_ntoa(ip->ip_dst));
  653                 printf("icmp_send dst %s src %s\n",
  654                        buf, inet_ntoa(ip->ip_src));
  655         }
  656 #endif
  657         bzero(&ro, sizeof ro);
  658         (void) ip_output(m, opts, &ro, 0, NULL);
  659         if (ro.ro_rt)
  660                 RTFREE(ro.ro_rt);
  661 }
  662 
  663 n_time
  664 iptime()
  665 {
  666         struct timeval atv;
  667         u_long t;
  668 
  669         microtime(&atv);
  670         t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
  671         return (htonl(t));
  672 }
  673 
  674 #if 1
  675 /*
  676  * Return the next larger or smaller MTU plateau (table from RFC 1191)
  677  * given current value MTU.  If DIR is less than zero, a larger plateau
  678  * is returned; otherwise, a smaller value is returned.
  679  */
  680 static int
  681 ip_next_mtu(mtu, dir)
  682         int mtu;
  683         int dir;
  684 {
  685         static int mtutab[] = {
  686                 65535, 32000, 17914, 8166, 4352, 2002, 1492, 1006, 508, 296,
  687                 68, 0
  688         };
  689         int i;
  690 
  691         for (i = 0; i < (sizeof mtutab) / (sizeof mtutab[0]); i++) {
  692                 if (mtu >= mtutab[i])
  693                         break;
  694         }
  695 
  696         if (dir < 0) {
  697                 if (i == 0) {
  698                         return 0;
  699                 } else {
  700                         return mtutab[i - 1];
  701                 }
  702         } else {
  703                 if (mtutab[i] == 0) {
  704                         return 0;
  705                 } else if(mtu > mtutab[i]) {
  706                         return mtutab[i];
  707                 } else {
  708                         return mtutab[i + 1];
  709                 }
  710         }
  711 }
  712 #endif

Cache object: 0c765845ca7f2985914a635d16669ade


[ 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.