LCOV - code coverage report
Current view: top level - netinet6 - icmp6.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 766 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 19 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: icmp6.c,v 1.226 2018/09/05 09:47:18 miko Exp $        */
       2             : /*      $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */
       3             : 
       4             : /*
       5             :  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
       6             :  * All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  * 1. Redistributions of source code must retain the above copyright
      12             :  *    notice, this list of conditions and the following disclaimer.
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  * 3. Neither the name of the project nor the names of its contributors
      17             :  *    may be used to endorse or promote products derived from this software
      18             :  *    without specific prior written permission.
      19             :  *
      20             :  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
      21             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      22             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      23             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
      24             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      25             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      26             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      27             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      28             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      29             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      30             :  * SUCH DAMAGE.
      31             :  */
      32             : 
      33             : /*
      34             :  * Copyright (c) 1982, 1986, 1988, 1993
      35             :  *      The Regents of the University of California.  All rights reserved.
      36             :  *
      37             :  * Redistribution and use in source and binary forms, with or without
      38             :  * modification, are permitted provided that the following conditions
      39             :  * are met:
      40             :  * 1. Redistributions of source code must retain the above copyright
      41             :  *    notice, this list of conditions and the following disclaimer.
      42             :  * 2. Redistributions in binary form must reproduce the above copyright
      43             :  *    notice, this list of conditions and the following disclaimer in the
      44             :  *    documentation and/or other materials provided with the distribution.
      45             :  * 3. Neither the name of the University nor the names of its contributors
      46             :  *    may be used to endorse or promote products derived from this software
      47             :  *    without specific prior written permission.
      48             :  *
      49             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      50             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      51             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      52             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      53             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      54             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      55             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      56             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      57             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      58             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      59             :  * SUCH DAMAGE.
      60             :  *
      61             :  *      @(#)ip_icmp.c   8.2 (Berkeley) 1/4/94
      62             :  */
      63             : 
      64             : #include "carp.h"
      65             : #include "pf.h"
      66             : 
      67             : #include <sys/param.h>
      68             : #include <sys/systm.h>
      69             : #include <sys/malloc.h>
      70             : #include <sys/mbuf.h>
      71             : #include <sys/sysctl.h>
      72             : #include <sys/protosw.h>
      73             : #include <sys/socket.h>
      74             : #include <sys/socketvar.h>
      75             : #include <sys/time.h>
      76             : #include <sys/kernel.h>
      77             : #include <sys/syslog.h>
      78             : #include <sys/domain.h>
      79             : 
      80             : #include <net/if.h>
      81             : #include <net/if_var.h>
      82             : #include <net/route.h>
      83             : #include <net/if_dl.h>
      84             : #include <net/if_types.h>
      85             : 
      86             : #include <netinet/in.h>
      87             : #include <netinet/ip.h>
      88             : #include <netinet6/in6_var.h>
      89             : #include <netinet/ip6.h>
      90             : #include <netinet6/ip6_var.h>
      91             : #include <netinet/icmp6.h>
      92             : #include <netinet6/mld6_var.h>
      93             : #include <netinet/in_pcb.h>
      94             : #include <netinet6/nd6.h>
      95             : #include <netinet6/ip6protosw.h>
      96             : 
      97             : #if NCARP > 0
      98             : #include <netinet/ip_carp.h>
      99             : #endif
     100             : 
     101             : #if NPF > 0
     102             : #include <net/pfvar.h>
     103             : #endif
     104             : 
     105             : struct cpumem *icmp6counters;
     106             : 
     107             : extern int icmp6errppslim;
     108             : static int icmp6errpps_count = 0;
     109             : static struct timeval icmp6errppslim_last;
     110             : 
     111             : /*
     112             :  * List of callbacks to notify when Path MTU changes are made.
     113             :  */
     114             : struct icmp6_mtudisc_callback {
     115             :         LIST_ENTRY(icmp6_mtudisc_callback) mc_list;
     116             :         void (*mc_func)(struct sockaddr_in6 *, u_int);
     117             : };
     118             : 
     119             : LIST_HEAD(, icmp6_mtudisc_callback) icmp6_mtudisc_callbacks =
     120             :     LIST_HEAD_INITIALIZER(icmp6_mtudisc_callbacks);
     121             : 
     122             : struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL;
     123             : 
     124             : /* XXX do these values make any sense? */
     125             : static int icmp6_mtudisc_hiwat = 1280;
     126             : static int icmp6_mtudisc_lowat = 256;
     127             : 
     128             : /*
     129             :  * keep track of # of redirect routes.
     130             :  */
     131             : static struct rttimer_queue *icmp6_redirect_timeout_q = NULL;
     132             : 
     133             : /* XXX experimental, turned off */
     134             : static int icmp6_redirect_lowat = -1;
     135             : 
     136             : void    icmp6_errcount(int, int);
     137             : int     icmp6_ratelimit(const struct in6_addr *, const int, const int);
     138             : const char *icmp6_redirect_diag(struct in6_addr *, struct in6_addr *,
     139             :             struct in6_addr *);
     140             : int     icmp6_notify_error(struct mbuf *, int, int, int);
     141             : struct rtentry *icmp6_mtudisc_clone(struct sockaddr *, u_int);
     142             : void    icmp6_mtudisc_timeout(struct rtentry *, struct rttimer *);
     143             : void    icmp6_redirect_timeout(struct rtentry *, struct rttimer *);
     144             : 
     145             : void
     146           0 : icmp6_init(void)
     147             : {
     148           0 :         mld6_init();
     149           0 :         icmp6_mtudisc_timeout_q = rt_timer_queue_create(ip6_mtudisc_timeout);
     150           0 :         icmp6_redirect_timeout_q = rt_timer_queue_create(icmp6_redirtimeout);
     151           0 :         icmp6counters = counters_alloc(icp6s_ncounters);
     152           0 : }
     153             : 
     154             : void
     155           0 : icmp6_errcount(int type, int code)
     156             : {
     157             :         enum icmp6stat_counters c = icp6s_ounknown;
     158             : 
     159           0 :         switch (type) {
     160             :         case ICMP6_DST_UNREACH:
     161           0 :                 switch (code) {
     162             :                 case ICMP6_DST_UNREACH_NOROUTE:
     163             :                         c = icp6s_odst_unreach_noroute;
     164           0 :                         break;
     165             :                 case ICMP6_DST_UNREACH_ADMIN:
     166             :                         c = icp6s_odst_unreach_admin;
     167           0 :                         break;
     168             :                 case ICMP6_DST_UNREACH_BEYONDSCOPE:
     169             :                         c = icp6s_odst_unreach_beyondscope;
     170           0 :                         break;
     171             :                 case ICMP6_DST_UNREACH_ADDR:
     172             :                         c = icp6s_odst_unreach_addr;
     173           0 :                         break;
     174             :                 case ICMP6_DST_UNREACH_NOPORT:
     175             :                         c = icp6s_odst_unreach_noport;
     176           0 :                         break;
     177             :                 }
     178             :                 break;
     179             :         case ICMP6_PACKET_TOO_BIG:
     180             :                 c = icp6s_opacket_too_big;
     181           0 :                 break;
     182             :         case ICMP6_TIME_EXCEEDED:
     183           0 :                 switch (code) {
     184             :                 case ICMP6_TIME_EXCEED_TRANSIT:
     185             :                         c = icp6s_otime_exceed_transit;
     186           0 :                         break;
     187             :                 case ICMP6_TIME_EXCEED_REASSEMBLY:
     188             :                         c = icp6s_otime_exceed_reassembly;
     189           0 :                         break;
     190             :                 }
     191             :                 break;
     192             :         case ICMP6_PARAM_PROB:
     193           0 :                 switch (code) {
     194             :                 case ICMP6_PARAMPROB_HEADER:
     195             :                         c = icp6s_oparamprob_header;
     196           0 :                         break;
     197             :                 case ICMP6_PARAMPROB_NEXTHEADER:
     198             :                         c = icp6s_oparamprob_nextheader;
     199           0 :                         break;
     200             :                 case ICMP6_PARAMPROB_OPTION:
     201             :                         c = icp6s_oparamprob_option;
     202           0 :                         break;
     203             :                 }
     204             :                 break;
     205             :         case ND_REDIRECT:
     206             :                 c = icp6s_oredirect;
     207           0 :                 break;
     208             :         }
     209             : 
     210           0 :         icmp6stat_inc(c);
     211           0 : }
     212             : 
     213             : /*
     214             :  * Register a Path MTU Discovery callback.
     215             :  */
     216             : void
     217           0 : icmp6_mtudisc_callback_register(void (*func)(struct sockaddr_in6 *, u_int))
     218             : {
     219             :         struct icmp6_mtudisc_callback *mc;
     220             : 
     221           0 :         LIST_FOREACH(mc, &icmp6_mtudisc_callbacks, mc_list) {
     222           0 :                 if (mc->mc_func == func)
     223           0 :                         return;
     224             :         }
     225             : 
     226           0 :         mc = malloc(sizeof(*mc), M_PCB, M_NOWAIT);
     227           0 :         if (mc == NULL)
     228           0 :                 panic("icmp6_mtudisc_callback_register");
     229             : 
     230           0 :         mc->mc_func = func;
     231           0 :         LIST_INSERT_HEAD(&icmp6_mtudisc_callbacks, mc, mc_list);
     232           0 : }
     233             : 
     234             : /*
     235             :  * Generate an error packet of type error in response to bad IP6 packet.
     236             :  */
     237             : void
     238           0 : icmp6_error(struct mbuf *m, int type, int code, int param)
     239             : {
     240             :         struct ip6_hdr *oip6, *nip6;
     241             :         struct icmp6_hdr *icmp6;
     242             :         u_int preplen;
     243             :         int off;
     244           0 :         int nxt;
     245             : 
     246           0 :         icmp6stat_inc(icp6s_error);
     247             : 
     248             :         /* count per-type-code statistics */
     249           0 :         icmp6_errcount(type, code);
     250             : 
     251           0 :         if (m->m_len < sizeof(struct ip6_hdr)) {
     252           0 :                 m = m_pullup(m, sizeof(struct ip6_hdr));
     253           0 :                 if (m == NULL)
     254           0 :                         return;
     255             :         }
     256           0 :         oip6 = mtod(m, struct ip6_hdr *);
     257             : 
     258             :         /*
     259             :          * If the destination address of the erroneous packet is a multicast
     260             :          * address, or the packet was sent using link-layer multicast,
     261             :          * we should basically suppress sending an error (RFC 2463, Section
     262             :          * 2.4).
     263             :          * We have two exceptions (the item e.2 in that section):
     264             :          * - the Packet Too Big message can be sent for path MTU discovery.
     265             :          * - the Parameter Problem Message that can be allowed an icmp6 error
     266             :          *   in the option type field.  This check has been done in
     267             :          *   ip6_unknown_opt(), so we can just check the type and code.
     268             :          */
     269           0 :         if ((m->m_flags & (M_BCAST|M_MCAST) ||
     270           0 :              IN6_IS_ADDR_MULTICAST(&oip6->ip6_dst)) &&
     271           0 :             (type != ICMP6_PACKET_TOO_BIG &&
     272           0 :              (type != ICMP6_PARAM_PROB ||
     273           0 :               code != ICMP6_PARAMPROB_OPTION)))
     274             :                 goto freeit;
     275             : 
     276             :         /*
     277             :          * RFC 2463, 2.4 (e.5): source address check.
     278             :          * XXX: the case of anycast source?
     279             :          */
     280           0 :         if (IN6_IS_ADDR_UNSPECIFIED(&oip6->ip6_src) ||
     281           0 :             IN6_IS_ADDR_MULTICAST(&oip6->ip6_src))
     282             :                 goto freeit;
     283             : 
     284             :         /*
     285             :          * If we are about to send ICMPv6 against ICMPv6 error/redirect,
     286             :          * don't do it.
     287             :          */
     288           0 :         nxt = -1;
     289           0 :         off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
     290           0 :         if (off >= 0 && nxt == IPPROTO_ICMPV6) {
     291             :                 struct icmp6_hdr *icp;
     292             : 
     293           0 :                 IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off,
     294             :                         sizeof(*icp));
     295           0 :                 if (icp == NULL) {
     296           0 :                         icmp6stat_inc(icp6s_tooshort);
     297           0 :                         return;
     298             :                 }
     299           0 :                 if (icp->icmp6_type < ICMP6_ECHO_REQUEST ||
     300           0 :                     icp->icmp6_type == ND_REDIRECT) {
     301             :                         /*
     302             :                          * ICMPv6 error
     303             :                          * Special case: for redirect (which is
     304             :                          * informational) we must not send icmp6 error.
     305             :                          */
     306           0 :                         icmp6stat_inc(icp6s_canterror);
     307           0 :                         goto freeit;
     308             :                 } else {
     309             :                         /* ICMPv6 informational - send the error */
     310             :                 }
     311           0 :         }
     312             :         else {
     313             :                 /* non-ICMPv6 - send the error */
     314             :         }
     315             : 
     316           0 :         oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */
     317             : 
     318             :         /* Finally, do rate limitation check. */
     319           0 :         if (icmp6_ratelimit(&oip6->ip6_src, type, code)) {
     320           0 :                 icmp6stat_inc(icp6s_toofreq);
     321           0 :                 goto freeit;
     322             :         }
     323             : 
     324             :         /*
     325             :          * OK, ICMP6 can be generated.
     326             :          */
     327             : 
     328           0 :         if (m->m_pkthdr.len >= ICMPV6_PLD_MAXLEN)
     329           0 :                 m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len);
     330             : 
     331             :         preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
     332           0 :         M_PREPEND(m, preplen, M_DONTWAIT);
     333           0 :         if (m && m->m_len < preplen)
     334           0 :                 m = m_pullup(m, preplen);
     335           0 :         if (m == NULL) {
     336           0 :                 nd6log((LOG_DEBUG, "ENOBUFS in icmp6_error %d\n", __LINE__));
     337           0 :                 return;
     338             :         }
     339             : 
     340           0 :         nip6 = mtod(m, struct ip6_hdr *);
     341           0 :         nip6->ip6_src  = oip6->ip6_src;
     342           0 :         nip6->ip6_dst  = oip6->ip6_dst;
     343             : 
     344           0 :         if (IN6_IS_SCOPE_EMBED(&oip6->ip6_src))
     345           0 :                 oip6->ip6_src.s6_addr16[1] = 0;
     346           0 :         if (IN6_IS_SCOPE_EMBED(&oip6->ip6_dst))
     347           0 :                 oip6->ip6_dst.s6_addr16[1] = 0;
     348             : 
     349           0 :         icmp6 = (struct icmp6_hdr *)(nip6 + 1);
     350           0 :         icmp6->icmp6_type = type;
     351           0 :         icmp6->icmp6_code = code;
     352           0 :         icmp6->icmp6_pptr = htonl((u_int32_t)param);
     353             : 
     354             :         /*
     355             :          * icmp6_reflect() is designed to be in the input path.
     356             :          * icmp6_error() can be called from both input and outut path,
     357             :          * and if we are in output path rcvif could contain bogus value.
     358             :          * clear m->m_pkthdr.ph_ifidx for safety, we should have enough
     359             :          * scope information in ip header (nip6).
     360             :          */
     361           0 :         m->m_pkthdr.ph_ifidx = 0;
     362             : 
     363           0 :         icmp6stat_inc(icp6s_outhist + type);
     364           0 :         icmp6_reflect(m, sizeof(struct ip6_hdr)); /* header order: IPv6 - ICMPv6 */
     365             : 
     366           0 :         return;
     367             : 
     368             :   freeit:
     369             :         /*
     370             :          * If we can't tell wheter or not we can generate ICMP6, free it.
     371             :          */
     372           0 :         m_freem(m);
     373           0 : }
     374             : 
     375             : /*
     376             :  * Process a received ICMP6 message.
     377             :  */
     378             : int
     379           0 : icmp6_input(struct mbuf **mp, int *offp, int proto, int af)
     380             : {
     381             : #if NCARP > 0
     382             :         struct ifnet *ifp;
     383             : #endif
     384           0 :         struct mbuf *m = *mp, *n;
     385             :         struct ip6_hdr *ip6, *nip6;
     386             :         struct icmp6_hdr *icmp6, *nicmp6;
     387           0 :         int off = *offp;
     388           0 :         int icmp6len = m->m_pkthdr.len - *offp;
     389             :         int code, sum, noff;
     390           0 :         char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];
     391             : 
     392             :         /*
     393             :          * Locate icmp6 structure in mbuf, and check
     394             :          * that not corrupted and of at least minimum length
     395             :          */
     396             : 
     397           0 :         ip6 = mtod(m, struct ip6_hdr *);
     398           0 :         if (icmp6len < sizeof(struct icmp6_hdr)) {
     399           0 :                 icmp6stat_inc(icp6s_tooshort);
     400           0 :                 goto freeit;
     401             :         }
     402             : 
     403             :         /*
     404             :          * calculate the checksum
     405             :          */
     406           0 :         IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
     407           0 :         if (icmp6 == NULL) {
     408           0 :                 icmp6stat_inc(icp6s_tooshort);
     409           0 :                 return IPPROTO_DONE;
     410             :         }
     411           0 :         code = icmp6->icmp6_code;
     412             : 
     413           0 :         if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) {
     414           0 :                 nd6log((LOG_ERR,
     415             :                     "ICMP6 checksum error(%d|%x) %s\n",
     416             :                     icmp6->icmp6_type, sum,
     417             :                     inet_ntop(AF_INET6, &ip6->ip6_src, src, sizeof(src))));
     418           0 :                 icmp6stat_inc(icp6s_checksum);
     419           0 :                 goto freeit;
     420             :         }
     421             : 
     422             : #if NPF > 0
     423           0 :         if (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) {
     424           0 :                 switch (icmp6->icmp6_type) {
     425             :                 /*
     426             :                  * These ICMP6 types map to other connections.  They must be
     427             :                  * delivered to pr_ctlinput() also for diverted connections.
     428             :                  */
     429             :                 case ICMP6_DST_UNREACH:
     430             :                 case ICMP6_PACKET_TOO_BIG:
     431             :                 case ICMP6_TIME_EXCEEDED:
     432             :                 case ICMP6_PARAM_PROB:
     433             :                         /*
     434             :                          * Do not use the divert-to property of the TCP or UDP
     435             :                          * rule when doing the PCB lookup for the raw socket.
     436             :                          */
     437           0 :                         m->m_pkthdr.pf.flags &=~ PF_TAG_DIVERTED;
     438             :                         break;
     439             :                 default:
     440             :                         goto raw;
     441             :                 }
     442           0 :         }
     443             : #endif /* NPF */
     444             : 
     445             : #if NCARP > 0
     446           0 :         ifp = if_get(m->m_pkthdr.ph_ifidx);
     447           0 :         if (ifp == NULL)
     448             :                 goto freeit;
     449             : 
     450           0 :         if (icmp6->icmp6_type == ICMP6_ECHO_REQUEST &&
     451           0 :             carp_lsdrop(ifp, m, AF_INET6, ip6->ip6_src.s6_addr32,
     452           0 :             ip6->ip6_dst.s6_addr32, 1)) {
     453           0 :                 if_put(ifp);
     454           0 :                 goto freeit;
     455             :         }
     456             : 
     457           0 :         if_put(ifp);
     458             : #endif
     459           0 :         icmp6stat_inc(icp6s_inhist + icmp6->icmp6_type);
     460             : 
     461           0 :         switch (icmp6->icmp6_type) {
     462             :         case ICMP6_DST_UNREACH:
     463           0 :                 switch (code) {
     464             :                 case ICMP6_DST_UNREACH_NOROUTE:
     465             :                         code = PRC_UNREACH_NET;
     466           0 :                         break;
     467             :                 case ICMP6_DST_UNREACH_ADMIN:
     468             :                         code = PRC_UNREACH_PROTOCOL; /* is this a good code? */
     469           0 :                         break;
     470             :                 case ICMP6_DST_UNREACH_ADDR:
     471             :                         code = PRC_HOSTDEAD;
     472           0 :                         break;
     473             :                 case ICMP6_DST_UNREACH_BEYONDSCOPE:
     474             :                         /* I mean "source address was incorrect." */
     475             :                         code = PRC_PARAMPROB;
     476           0 :                         break;
     477             :                 case ICMP6_DST_UNREACH_NOPORT:
     478             :                         code = PRC_UNREACH_PORT;
     479           0 :                         break;
     480             :                 default:
     481             :                         goto badcode;
     482             :                 }
     483             :                 goto deliver;
     484             : 
     485             :         case ICMP6_PACKET_TOO_BIG:
     486             :                 /* MTU is checked in icmp6_mtudisc_update. */
     487             :                 code = PRC_MSGSIZE;
     488             : 
     489             :                 /*
     490             :                  * Updating the path MTU will be done after examining
     491             :                  * intermediate extension headers.
     492             :                  */
     493           0 :                 goto deliver;
     494             : 
     495             :         case ICMP6_TIME_EXCEEDED:
     496           0 :                 switch (code) {
     497             :                 case ICMP6_TIME_EXCEED_TRANSIT:
     498             :                         code = PRC_TIMXCEED_INTRANS;
     499           0 :                         break;
     500             :                 case ICMP6_TIME_EXCEED_REASSEMBLY:
     501             :                         code = PRC_TIMXCEED_REASS;
     502           0 :                         break;
     503             :                 default:
     504             :                         goto badcode;
     505             :                 }
     506             :                 goto deliver;
     507             : 
     508             :         case ICMP6_PARAM_PROB:
     509           0 :                 switch (code) {
     510             :                 case ICMP6_PARAMPROB_NEXTHEADER:
     511             :                         code = PRC_UNREACH_PROTOCOL;
     512           0 :                         break;
     513             :                 case ICMP6_PARAMPROB_HEADER:
     514             :                 case ICMP6_PARAMPROB_OPTION:
     515             :                         code = PRC_PARAMPROB;
     516           0 :                         break;
     517             :                 default:
     518             :                         goto badcode;
     519             :                 }
     520             :                 goto deliver;
     521             : 
     522             :         case ICMP6_ECHO_REQUEST:
     523           0 :                 if (code != 0)
     524             :                         goto badcode;
     525             :                 /*
     526             :                  * Copy mbuf to send to two data paths: userland socket(s),
     527             :                  * and to the querier (echo reply).
     528             :                  * m: a copy for socket, n: a copy for querier
     529             :                  */
     530           0 :                 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
     531             :                         /* Give up local */
     532             :                         n = m;
     533           0 :                         m = *mp = NULL;
     534           0 :                         goto deliverecho;
     535             :                 }
     536             :                 /*
     537             :                  * If the first mbuf is shared, or the first mbuf is too short,
     538             :                  * copy the first part of the data into a fresh mbuf.
     539             :                  * Otherwise, we will wrongly overwrite both copies.
     540             :                  */
     541           0 :                 if ((n->m_flags & M_EXT) != 0 ||
     542           0 :                     n->m_len < off + sizeof(struct icmp6_hdr)) {
     543             :                         struct mbuf *n0 = n;
     544             :                         const int maxlen = sizeof(*nip6) + sizeof(*nicmp6);
     545             : 
     546             :                         /*
     547             :                          * Prepare an internal mbuf.  m_pullup() doesn't
     548             :                          * always copy the length we specified.
     549             :                          */
     550             :                         if (maxlen >= MCLBYTES) {
     551             :                                 /* Give up remote */
     552             :                                 m_freem(n0);
     553             :                                 break;
     554             :                         }
     555           0 :                         MGETHDR(n, M_DONTWAIT, n0->m_type);
     556             :                         if (n && maxlen >= MHLEN) {
     557             :                                 MCLGET(n, M_DONTWAIT);
     558             :                                 if ((n->m_flags & M_EXT) == 0) {
     559             :                                         m_free(n);
     560             :                                         n = NULL;
     561             :                                 }
     562             :                         }
     563           0 :                         if (n == NULL) {
     564             :                                 /* Give up local */
     565           0 :                                 m_freem(n0);
     566             :                                 n = m;
     567           0 :                                 m = *mp = NULL;
     568           0 :                                 goto deliverecho;
     569             :                         }
     570           0 :                         M_MOVE_PKTHDR(n, n0);
     571             :                         /*
     572             :                          * Copy IPv6 and ICMPv6 only.
     573             :                          */
     574           0 :                         nip6 = mtod(n, struct ip6_hdr *);
     575           0 :                         bcopy(ip6, nip6, sizeof(struct ip6_hdr));
     576           0 :                         nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
     577           0 :                         bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
     578             :                         noff = sizeof(struct ip6_hdr);
     579           0 :                         n->m_len = noff + sizeof(struct icmp6_hdr);
     580             :                         /*
     581             :                          * Adjust mbuf.  ip6_plen will be adjusted in
     582             :                          * ip6_output().
     583             :                          * n->m_pkthdr.len == n0->m_pkthdr.len at this point.
     584             :                          */
     585           0 :                         n->m_pkthdr.len += noff + sizeof(struct icmp6_hdr);
     586           0 :                         n->m_pkthdr.len -= (off + sizeof(struct icmp6_hdr));
     587           0 :                         m_adj(n0, off + sizeof(struct icmp6_hdr));
     588           0 :                         n->m_next = n0;
     589           0 :                 } else {
     590             :          deliverecho:
     591           0 :                         IP6_EXTHDR_GET(nicmp6, struct icmp6_hdr *, n, off,
     592             :                             sizeof(*nicmp6));
     593             :                         noff = off;
     594             :                 }
     595           0 :                 if (n) {
     596           0 :                         nicmp6->icmp6_type = ICMP6_ECHO_REPLY;
     597           0 :                         nicmp6->icmp6_code = 0;
     598           0 :                         icmp6stat_inc(icp6s_reflect);
     599           0 :                         icmp6stat_inc(icp6s_outhist + ICMP6_ECHO_REPLY);
     600           0 :                         icmp6_reflect(n, noff);
     601           0 :                 }
     602           0 :                 if (!m)
     603             :                         goto freeit;
     604             :                 break;
     605             : 
     606             :         case ICMP6_ECHO_REPLY:
     607           0 :                 if (code != 0)
     608             :                         goto badcode;
     609             :                 break;
     610             : 
     611             :         case MLD_LISTENER_QUERY:
     612             :         case MLD_LISTENER_REPORT:
     613           0 :                 if (icmp6len < sizeof(struct mld_hdr))
     614             :                         goto badlen;
     615           0 :                 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
     616             :                         /* give up local */
     617           0 :                         mld6_input(m, off);
     618             :                         m = NULL;
     619           0 :                         goto freeit;
     620             :                 }
     621           0 :                 mld6_input(n, off);
     622             :                 /* m stays. */
     623           0 :                 break;
     624             : 
     625             :         case MLD_LISTENER_DONE:
     626           0 :                 if (icmp6len < sizeof(struct mld_hdr))       /* necessary? */
     627             :                         goto badlen;
     628             :                 break;          /* nothing to be done in kernel */
     629             : 
     630             :         case MLD_MTRACE_RESP:
     631             :         case MLD_MTRACE:
     632             :                 /* XXX: these two are experimental.  not officially defined. */
     633             :                 /* XXX: per-interface statistics? */
     634             :                 break;          /* just pass it to applications */
     635             : 
     636             :         case ICMP6_WRUREQUEST:  /* ICMP6_FQDN_QUERY */
     637             :                 /* IPv6 Node Information Queries are not supported */
     638             :                 break;
     639             :         case ICMP6_WRUREPLY:
     640             :                 break;
     641             : 
     642             :         case ND_ROUTER_SOLICIT:
     643             :         case ND_ROUTER_ADVERT:
     644           0 :                 if (code != 0)
     645             :                         goto badcode;
     646           0 :                 if ((icmp6->icmp6_type == ND_ROUTER_SOLICIT && icmp6len <
     647           0 :                     sizeof(struct nd_router_solicit)) ||
     648           0 :                     (icmp6->icmp6_type == ND_ROUTER_ADVERT && icmp6len <
     649             :                     sizeof(struct nd_router_advert)))
     650             :                         goto badlen;
     651             : 
     652           0 :                 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
     653             :                         /* give up local */
     654           0 :                         nd6_rtr_cache(m, off, icmp6len,
     655           0 :                             icmp6->icmp6_type);
     656             :                         m = NULL;
     657           0 :                         goto freeit;
     658             :                 }
     659           0 :                 nd6_rtr_cache(n, off, icmp6len, icmp6->icmp6_type);
     660             :                 /* m stays. */
     661           0 :                 break;
     662             : 
     663             :         case ND_NEIGHBOR_SOLICIT:
     664           0 :                 if (code != 0)
     665             :                         goto badcode;
     666           0 :                 if (icmp6len < sizeof(struct nd_neighbor_solicit))
     667             :                         goto badlen;
     668           0 :                 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
     669             :                         /* give up local */
     670           0 :                         nd6_ns_input(m, off, icmp6len);
     671             :                         m = NULL;
     672           0 :                         goto freeit;
     673             :                 }
     674           0 :                 nd6_ns_input(n, off, icmp6len);
     675             :                 /* m stays. */
     676           0 :                 break;
     677             : 
     678             :         case ND_NEIGHBOR_ADVERT:
     679           0 :                 if (code != 0)
     680             :                         goto badcode;
     681           0 :                 if (icmp6len < sizeof(struct nd_neighbor_advert))
     682             :                         goto badlen;
     683           0 :                 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
     684             :                         /* give up local */
     685           0 :                         nd6_na_input(m, off, icmp6len);
     686             :                         m = NULL;
     687           0 :                         goto freeit;
     688             :                 }
     689           0 :                 nd6_na_input(n, off, icmp6len);
     690             :                 /* m stays. */
     691           0 :                 break;
     692             : 
     693             :         case ND_REDIRECT:
     694           0 :                 if (code != 0)
     695             :                         goto badcode;
     696           0 :                 if (icmp6len < sizeof(struct nd_redirect))
     697             :                         goto badlen;
     698           0 :                 if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
     699             :                         /* give up local */
     700           0 :                         icmp6_redirect_input(m, off);
     701             :                         m = NULL;
     702           0 :                         goto freeit;
     703             :                 }
     704           0 :                 icmp6_redirect_input(n, off);
     705             :                 /* m stays. */
     706           0 :                 break;
     707             : 
     708             :         case ICMP6_ROUTER_RENUMBERING:
     709           0 :                 if (code != ICMP6_ROUTER_RENUMBERING_COMMAND &&
     710           0 :                     code != ICMP6_ROUTER_RENUMBERING_RESULT)
     711             :                         goto badcode;
     712           0 :                 if (icmp6len < sizeof(struct icmp6_router_renum))
     713             :                         goto badlen;
     714             :                 break;
     715             : 
     716             :         default:
     717           0 :                 nd6log((LOG_DEBUG,
     718             :                     "icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%u)\n",
     719             :                     icmp6->icmp6_type,
     720             :                     inet_ntop(AF_INET6, &ip6->ip6_src, src, sizeof(src)),
     721             :                     inet_ntop(AF_INET6, &ip6->ip6_dst, dst, sizeof(dst)),
     722             :                     m->m_pkthdr.ph_ifidx));
     723           0 :                 if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) {
     724             :                         /* ICMPv6 error: MUST deliver it by spec... */
     725             :                         code = PRC_NCMDS;
     726             :                         /* deliver */
     727             :                 } else {
     728             :                         /* ICMPv6 informational: MUST not deliver */
     729             :                         break;
     730             :                 }
     731             : deliver:
     732           0 :                 if (icmp6_notify_error(m, off, icmp6len, code)) {
     733             :                         /* In this case, m should've been freed. */
     734           0 :                         return (IPPROTO_DONE);
     735             :                 }
     736             :                 break;
     737             : 
     738             : badcode:
     739           0 :                 icmp6stat_inc(icp6s_badcode);
     740           0 :                 break;
     741             : 
     742             : badlen:
     743           0 :                 icmp6stat_inc(icp6s_badlen);
     744           0 :                 break;
     745             :         }
     746             : 
     747             : #if NPF > 0
     748             : raw:
     749             : #endif
     750             :         /* deliver the packet to appropriate sockets */
     751           0 :         return rip6_input(mp, offp, proto, af);
     752             : 
     753             :  freeit:
     754           0 :         m_freem(m);
     755           0 :         return IPPROTO_DONE;
     756           0 : }
     757             : 
     758             : int
     759           0 : icmp6_notify_error(struct mbuf *m, int off, int icmp6len, int code)
     760             : {
     761             :         struct icmp6_hdr *icmp6;
     762             :         struct ip6_hdr *eip6;
     763           0 :         u_int32_t notifymtu;
     764           0 :         struct sockaddr_in6 icmp6src, icmp6dst;
     765             : 
     766           0 :         if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
     767           0 :                 icmp6stat_inc(icp6s_tooshort);
     768           0 :                 goto freeit;
     769             :         }
     770           0 :         IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
     771             :                        sizeof(*icmp6) + sizeof(struct ip6_hdr));
     772           0 :         if (icmp6 == NULL) {
     773           0 :                 icmp6stat_inc(icp6s_tooshort);
     774           0 :                 return (-1);
     775             :         }
     776           0 :         eip6 = (struct ip6_hdr *)(icmp6 + 1);
     777             : 
     778             :         /* Detect the upper level protocol */
     779             :         {
     780             :                 void (*ctlfunc)(int, struct sockaddr *, u_int, void *);
     781           0 :                 u_int8_t nxt = eip6->ip6_nxt;
     782           0 :                 int eoff = off + sizeof(struct icmp6_hdr) +
     783             :                         sizeof(struct ip6_hdr);
     784           0 :                 struct ip6ctlparam ip6cp;
     785             :                 struct in6_addr *finaldst = NULL;
     786           0 :                 int icmp6type = icmp6->icmp6_type;
     787             :                 struct ip6_frag *fh;
     788             :                 struct ip6_rthdr *rth;
     789             :                 struct ip6_rthdr0 *rth0;
     790             :                 int rthlen;
     791             : 
     792           0 :                 while (1) { /* XXX: should avoid infinite loop explicitly? */
     793             :                         struct ip6_ext *eh;
     794             : 
     795           0 :                         switch (nxt) {
     796             :                         case IPPROTO_HOPOPTS:
     797             :                         case IPPROTO_DSTOPTS:
     798             :                         case IPPROTO_AH:
     799           0 :                                 IP6_EXTHDR_GET(eh, struct ip6_ext *, m,
     800             :                                                eoff, sizeof(*eh));
     801           0 :                                 if (eh == NULL) {
     802           0 :                                         icmp6stat_inc(icp6s_tooshort);
     803           0 :                                         return (-1);
     804             :                                 }
     805             : 
     806           0 :                                 if (nxt == IPPROTO_AH)
     807           0 :                                         eoff += (eh->ip6e_len + 2) << 2;
     808             :                                 else
     809           0 :                                         eoff += (eh->ip6e_len + 1) << 3;
     810           0 :                                 nxt = eh->ip6e_nxt;
     811           0 :                                 break;
     812             :                         case IPPROTO_ROUTING:
     813             :                                 /*
     814             :                                  * When the erroneous packet contains a
     815             :                                  * routing header, we should examine the
     816             :                                  * header to determine the final destination.
     817             :                                  * Otherwise, we can't properly update
     818             :                                  * information that depends on the final
     819             :                                  * destination (e.g. path MTU).
     820             :                                  */
     821           0 :                                 IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m,
     822             :                                                eoff, sizeof(*rth));
     823           0 :                                 if (rth == NULL) {
     824           0 :                                         icmp6stat_inc(icp6s_tooshort);
     825           0 :                                         return (-1);
     826             :                                 }
     827           0 :                                 rthlen = (rth->ip6r_len + 1) << 3;
     828             :                                 /*
     829             :                                  * XXX: currently there is no
     830             :                                  * officially defined type other
     831             :                                  * than type-0.
     832             :                                  * Note that if the segment left field
     833             :                                  * is 0, all intermediate hops must
     834             :                                  * have been passed.
     835             :                                  */
     836           0 :                                 if (rth->ip6r_segleft &&
     837           0 :                                     rth->ip6r_type == IPV6_RTHDR_TYPE_0) {
     838             :                                         int hops;
     839             : 
     840           0 :                                         IP6_EXTHDR_GET(rth0,
     841             :                                                        struct ip6_rthdr0 *, m,
     842             :                                                        eoff, rthlen);
     843           0 :                                         if (rth0 == NULL) {
     844           0 :                                                 icmp6stat_inc(icp6s_tooshort);
     845           0 :                                                 return (-1);
     846             :                                         }
     847             :                                         /* just ignore a bogus header */
     848           0 :                                         if ((rth0->ip6r0_len % 2) == 0 &&
     849           0 :                                             (hops = rth0->ip6r0_len/2))
     850           0 :                                                 finaldst = (struct in6_addr *)(rth0 + 1) + (hops - 1);
     851           0 :                                 }
     852           0 :                                 eoff += rthlen;
     853           0 :                                 nxt = rth->ip6r_nxt;
     854           0 :                                 break;
     855             :                         case IPPROTO_FRAGMENT:
     856           0 :                                 IP6_EXTHDR_GET(fh, struct ip6_frag *, m,
     857             :                                                eoff, sizeof(*fh));
     858           0 :                                 if (fh == NULL) {
     859           0 :                                         icmp6stat_inc(icp6s_tooshort);
     860           0 :                                         return (-1);
     861             :                                 }
     862             :                                 /*
     863             :                                  * Data after a fragment header is meaningless
     864             :                                  * unless it is the first fragment, but
     865             :                                  * we'll go to the notify label for path MTU
     866             :                                  * discovery.
     867             :                                  */
     868           0 :                                 if (fh->ip6f_offlg & IP6F_OFF_MASK)
     869           0 :                                         goto notify;
     870             : 
     871           0 :                                 eoff += sizeof(struct ip6_frag);
     872           0 :                                 nxt = fh->ip6f_nxt;
     873           0 :                                 break;
     874             :                         default:
     875             :                                 /*
     876             :                                  * This case includes ESP and the No Next
     877             :                                  * Header.  In such cases going to the notify
     878             :                                  * label does not have any meaning
     879             :                                  * (i.e. ctlfunc will be NULL), but we go
     880             :                                  * anyway since we might have to update
     881             :                                  * path MTU information.
     882             :                                  */
     883           0 :                                 goto notify;
     884             :                         }
     885           0 :                 }
     886             :           notify:
     887           0 :                 IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
     888             :                                sizeof(*icmp6) + sizeof(struct ip6_hdr));
     889           0 :                 if (icmp6 == NULL) {
     890           0 :                         icmp6stat_inc(icp6s_tooshort);
     891           0 :                         return (-1);
     892             :                 }
     893             : 
     894           0 :                 eip6 = (struct ip6_hdr *)(icmp6 + 1);
     895           0 :                 bzero(&icmp6dst, sizeof(icmp6dst));
     896           0 :                 icmp6dst.sin6_len = sizeof(struct sockaddr_in6);
     897           0 :                 icmp6dst.sin6_family = AF_INET6;
     898           0 :                 if (finaldst == NULL)
     899           0 :                         icmp6dst.sin6_addr = eip6->ip6_dst;
     900             :                 else
     901           0 :                         icmp6dst.sin6_addr = *finaldst;
     902           0 :                 icmp6dst.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.ph_ifidx,
     903             :                     &icmp6dst.sin6_addr);
     904           0 :                 if (in6_embedscope(&icmp6dst.sin6_addr, &icmp6dst, NULL)) {
     905             :                         /* should be impossbile */
     906           0 :                         nd6log((LOG_DEBUG,
     907             :                             "icmp6_notify_error: in6_embedscope failed\n"));
     908           0 :                         goto freeit;
     909             :                 }
     910             : 
     911             :                 /*
     912             :                  * retrieve parameters from the inner IPv6 header, and convert
     913             :                  * them into sockaddr structures.
     914             :                  */
     915           0 :                 bzero(&icmp6src, sizeof(icmp6src));
     916           0 :                 icmp6src.sin6_len = sizeof(struct sockaddr_in6);
     917           0 :                 icmp6src.sin6_family = AF_INET6;
     918           0 :                 icmp6src.sin6_addr = eip6->ip6_src;
     919           0 :                 icmp6src.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.ph_ifidx,
     920             :                     &icmp6src.sin6_addr);
     921           0 :                 if (in6_embedscope(&icmp6src.sin6_addr, &icmp6src, NULL)) {
     922             :                         /* should be impossbile */
     923           0 :                         nd6log((LOG_DEBUG,
     924             :                             "icmp6_notify_error: in6_embedscope failed\n"));
     925           0 :                         goto freeit;
     926             :                 }
     927           0 :                 icmp6src.sin6_flowinfo =
     928           0 :                     (eip6->ip6_flow & IPV6_FLOWLABEL_MASK);
     929             : 
     930           0 :                 if (finaldst == NULL)
     931           0 :                         finaldst = &eip6->ip6_dst;
     932           0 :                 ip6cp.ip6c_m = m;
     933           0 :                 ip6cp.ip6c_icmp6 = icmp6;
     934           0 :                 ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1);
     935           0 :                 ip6cp.ip6c_off = eoff;
     936           0 :                 ip6cp.ip6c_finaldst = finaldst;
     937           0 :                 ip6cp.ip6c_src = &icmp6src;
     938           0 :                 ip6cp.ip6c_nxt = nxt;
     939             : #if NPF > 0
     940           0 :                 pf_pkt_addr_changed(m);
     941             : #endif
     942             : 
     943           0 :                 if (icmp6type == ICMP6_PACKET_TOO_BIG) {
     944           0 :                         notifymtu = ntohl(icmp6->icmp6_mtu);
     945           0 :                         ip6cp.ip6c_cmdarg = (void *)&notifymtu;
     946           0 :                 }
     947             : 
     948           0 :                 ctlfunc = inet6sw[ip6_protox[nxt]].pr_ctlinput;
     949           0 :                 if (ctlfunc)
     950           0 :                         (*ctlfunc)(code, sin6tosa(&icmp6dst),
     951           0 :                             m->m_pkthdr.ph_rtableid, &ip6cp);
     952           0 :         }
     953           0 :         return (0);
     954             : 
     955             :   freeit:
     956           0 :         m_freem(m);
     957           0 :         return (-1);
     958           0 : }
     959             : 
     960             : void
     961           0 : icmp6_mtudisc_update(struct ip6ctlparam *ip6cp, int validated)
     962             : {
     963             :         unsigned long rtcount;
     964             :         struct icmp6_mtudisc_callback *mc;
     965           0 :         struct in6_addr *dst = ip6cp->ip6c_finaldst;
     966           0 :         struct icmp6_hdr *icmp6 = ip6cp->ip6c_icmp6;
     967           0 :         struct mbuf *m = ip6cp->ip6c_m;      /* will be necessary for scope issue */
     968           0 :         u_int mtu = ntohl(icmp6->icmp6_mtu);
     969             :         struct rtentry *rt = NULL;
     970           0 :         struct sockaddr_in6 sin6;
     971             : 
     972           0 :         if (mtu < IPV6_MMTU)
     973           0 :                 return;
     974             : 
     975             :         /*
     976             :          * allow non-validated cases if memory is plenty, to make traffic
     977             :          * from non-connected pcb happy.
     978             :          */
     979           0 :         rtcount = rt_timer_queue_count(icmp6_mtudisc_timeout_q);
     980           0 :         if (validated) {
     981           0 :                 if (0 <= icmp6_mtudisc_hiwat && rtcount > icmp6_mtudisc_hiwat)
     982           0 :                         return;
     983             :                 else if (0 <= icmp6_mtudisc_lowat &&
     984             :                     rtcount > icmp6_mtudisc_lowat) {
     985             :                         /*
     986             :                          * XXX nuke a victim, install the new one.
     987             :                          */
     988             :                 }
     989             :         } else {
     990           0 :                 if (0 <= icmp6_mtudisc_lowat && rtcount > icmp6_mtudisc_lowat)
     991           0 :                         return;
     992             :         }
     993             : 
     994           0 :         bzero(&sin6, sizeof(sin6));
     995           0 :         sin6.sin6_family = PF_INET6;
     996           0 :         sin6.sin6_len = sizeof(struct sockaddr_in6);
     997           0 :         sin6.sin6_addr = *dst;
     998             :         /* XXX normally, this won't happen */
     999           0 :         if (IN6_IS_ADDR_LINKLOCAL(dst)) {
    1000           0 :                 sin6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.ph_ifidx);
    1001           0 :         }
    1002           0 :         sin6.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.ph_ifidx,
    1003             :             &sin6.sin6_addr);
    1004             : 
    1005           0 :         rt = icmp6_mtudisc_clone(sin6tosa(&sin6), m->m_pkthdr.ph_rtableid);
    1006             : 
    1007           0 :         if (rt != NULL && ISSET(rt->rt_flags, RTF_HOST) &&
    1008           0 :             !(rt->rt_locks & RTV_MTU) &&
    1009           0 :             (rt->rt_mtu > mtu || rt->rt_mtu == 0)) {
    1010             :                 struct ifnet *ifp;
    1011             : 
    1012           0 :                 ifp = if_get(rt->rt_ifidx);
    1013           0 :                 if (ifp != NULL && mtu < ifp->if_mtu) {
    1014           0 :                         icmp6stat_inc(icp6s_pmtuchg);
    1015           0 :                         rt->rt_mtu = mtu;
    1016           0 :                 }
    1017           0 :                 if_put(ifp);
    1018           0 :         }
    1019           0 :         rtfree(rt);
    1020             : 
    1021             :         /*
    1022             :          * Notify protocols that the MTU for this destination
    1023             :          * has changed.
    1024             :          */
    1025           0 :         LIST_FOREACH(mc, &icmp6_mtudisc_callbacks, mc_list)
    1026           0 :                 (*mc->mc_func)(&sin6, m->m_pkthdr.ph_rtableid);
    1027           0 : }
    1028             : 
    1029             : /*
    1030             :  * Reflect the ip6 packet back to the source.
    1031             :  * OFF points to the icmp6 header, counted from the top of the mbuf.
    1032             :  */
    1033             : void
    1034           0 : icmp6_reflect(struct mbuf *m, size_t off)
    1035             : {
    1036             :         struct rtentry *rt = NULL;
    1037             :         struct ip6_hdr *ip6;
    1038             :         struct icmp6_hdr *icmp6;
    1039           0 :         struct in6_addr t, *src = NULL;
    1040           0 :         struct sockaddr_in6 sa6_src, sa6_dst;
    1041             :         u_int rtableid;
    1042             : 
    1043             :         CTASSERT(sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) <= MHLEN);
    1044             : 
    1045             :         /* too short to reflect */
    1046           0 :         if (off < sizeof(struct ip6_hdr)) {
    1047           0 :                 nd6log((LOG_DEBUG,
    1048             :                     "sanity fail: off=%lx, sizeof(ip6)=%lx in %s:%d\n",
    1049             :                     (u_long)off, (u_long)sizeof(struct ip6_hdr),
    1050             :                     __FILE__, __LINE__));
    1051             :                 goto bad;
    1052             :         }
    1053             : 
    1054           0 :         if (m->m_pkthdr.ph_loopcnt++ >= M_MAXLOOP)
    1055             :                 goto bad;
    1056           0 :         rtableid = m->m_pkthdr.ph_rtableid;
    1057           0 :         m_resethdr(m);
    1058           0 :         m->m_pkthdr.ph_rtableid = rtableid;
    1059             : 
    1060             :         /*
    1061             :          * If there are extra headers between IPv6 and ICMPv6, strip
    1062             :          * off that header first.
    1063             :          */
    1064           0 :         if (off > sizeof(struct ip6_hdr)) {
    1065             :                 size_t l;
    1066           0 :                 struct ip6_hdr nip6;
    1067             : 
    1068           0 :                 l = off - sizeof(struct ip6_hdr);
    1069           0 :                 m_copydata(m, 0, sizeof(nip6), (caddr_t)&nip6);
    1070           0 :                 m_adj(m, l);
    1071             :                 l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
    1072           0 :                 if (m->m_len < l) {
    1073           0 :                         if ((m = m_pullup(m, l)) == NULL)
    1074           0 :                                 return;
    1075             :                 }
    1076           0 :                 memcpy(mtod(m, caddr_t), &nip6, sizeof(nip6));
    1077           0 :         } else /* off == sizeof(struct ip6_hdr) */ {
    1078             :                 size_t l;
    1079             :                 l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
    1080           0 :                 if (m->m_len < l) {
    1081           0 :                         if ((m = m_pullup(m, l)) == NULL)
    1082           0 :                                 return;
    1083             :                 }
    1084           0 :         }
    1085           0 :         ip6 = mtod(m, struct ip6_hdr *);
    1086           0 :         ip6->ip6_nxt = IPPROTO_ICMPV6;
    1087           0 :         icmp6 = (struct icmp6_hdr *)(ip6 + 1);
    1088             : 
    1089           0 :         t = ip6->ip6_dst;
    1090             :         /*
    1091             :          * ip6_input() drops a packet if its src is multicast.
    1092             :          * So, the src is never multicast.
    1093             :          */
    1094           0 :         ip6->ip6_dst = ip6->ip6_src;
    1095             : 
    1096             :         /*
    1097             :          * XXX: make sure to embed scope zone information, using
    1098             :          * already embedded IDs or the received interface (if any).
    1099             :          * Note that rcvif may be NULL.
    1100             :          * TODO: scoped routing case (XXX).
    1101             :          */
    1102           0 :         bzero(&sa6_src, sizeof(sa6_src));
    1103           0 :         sa6_src.sin6_family = AF_INET6;
    1104           0 :         sa6_src.sin6_len = sizeof(sa6_src);
    1105           0 :         sa6_src.sin6_addr = ip6->ip6_dst;
    1106           0 :         bzero(&sa6_dst, sizeof(sa6_dst));
    1107           0 :         sa6_dst.sin6_family = AF_INET6;
    1108           0 :         sa6_dst.sin6_len = sizeof(sa6_dst);
    1109           0 :         sa6_dst.sin6_addr = t;
    1110             : 
    1111             :         /*
    1112             :          * If the incoming packet was addressed directly to us (i.e. unicast),
    1113             :          * use dst as the src for the reply.
    1114             :          * The IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED case would be VERY rare,
    1115             :          * but is possible (for example) when we encounter an error while
    1116             :          * forwarding procedure destined to a duplicated address of ours.
    1117             :          */
    1118           0 :         rt = rtalloc(sin6tosa(&sa6_dst), 0, rtableid);
    1119           0 :         if (rtisvalid(rt) && ISSET(rt->rt_flags, RTF_LOCAL) &&
    1120           0 :             !ISSET(ifatoia6(rt->rt_ifa)->ia6_flags,
    1121             :             IN6_IFF_ANYCAST|IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED)) {
    1122             :                 src = &t;
    1123           0 :         }
    1124           0 :         rtfree(rt);
    1125             :         rt = NULL;
    1126             : 
    1127           0 :         if (src == NULL) {
    1128             :                 /*
    1129             :                  * This case matches to multicasts, our anycast, or unicasts
    1130             :                  * that we do not own.  Select a source address based on the
    1131             :                  * source address of the erroneous packet.
    1132             :                  */
    1133           0 :                 rt = rtalloc(sin6tosa(&sa6_src), RT_RESOLVE, rtableid);
    1134           0 :                 if (!rtisvalid(rt)) {
    1135           0 :                         char addr[INET6_ADDRSTRLEN];
    1136             : 
    1137           0 :                         nd6log((LOG_DEBUG,
    1138             :                             "%s: source can't be determined: dst=%s\n",
    1139             :                             __func__, inet_ntop(AF_INET6, &sa6_src.sin6_addr,
    1140             :                                 addr, sizeof(addr))));
    1141           0 :                         rtfree(rt);
    1142             :                         goto bad;
    1143           0 :                 }
    1144           0 :                 src = &ifatoia6(rt->rt_ifa)->ia_addr.sin6_addr;
    1145           0 :         }
    1146             : 
    1147           0 :         ip6->ip6_src = *src;
    1148           0 :         rtfree(rt);
    1149             : 
    1150           0 :         ip6->ip6_flow = 0;
    1151           0 :         ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
    1152           0 :         ip6->ip6_vfc |= IPV6_VERSION;
    1153           0 :         ip6->ip6_nxt = IPPROTO_ICMPV6;
    1154           0 :         ip6->ip6_hlim = ip6_defhlim;
    1155             : 
    1156           0 :         icmp6->icmp6_cksum = 0;
    1157           0 :         m->m_pkthdr.csum_flags = M_ICMP_CSUM_OUT;
    1158             : 
    1159             :         /*
    1160             :          * XXX option handling
    1161             :          */
    1162             : 
    1163           0 :         m->m_flags &= ~(M_BCAST|M_MCAST);
    1164             : 
    1165           0 :         ip6_send(m);
    1166           0 :         return;
    1167             : 
    1168             :  bad:
    1169           0 :         m_freem(m);
    1170           0 :         return;
    1171           0 : }
    1172             : 
    1173             : void
    1174           0 : icmp6_fasttimo(void)
    1175             : {
    1176             : 
    1177           0 :         mld6_fasttimeo();
    1178           0 : }
    1179             : 
    1180             : const char *
    1181           0 : icmp6_redirect_diag(struct in6_addr *src6, struct in6_addr *dst6,
    1182             :     struct in6_addr *tgt6)
    1183             : {
    1184             :         static char buf[1024]; /* XXX */
    1185           0 :         char src[INET6_ADDRSTRLEN];
    1186           0 :         char dst[INET6_ADDRSTRLEN];
    1187           0 :         char tgt[INET6_ADDRSTRLEN];
    1188             : 
    1189           0 :         snprintf(buf, sizeof(buf), "(src=%s dst=%s tgt=%s)",
    1190           0 :                  inet_ntop(AF_INET6, src6, src, sizeof(src)),
    1191           0 :                  inet_ntop(AF_INET6, dst6, dst, sizeof(dst)),
    1192           0 :                  inet_ntop(AF_INET6, tgt6, tgt, sizeof(tgt)));
    1193           0 :         return buf;
    1194           0 : }
    1195             : 
    1196             : void
    1197           0 : icmp6_redirect_input(struct mbuf *m, int off)
    1198             : {
    1199             :         struct ifnet *ifp;
    1200           0 :         struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
    1201             :         struct nd_redirect *nd_rd;
    1202           0 :         int icmp6len = ntohs(ip6->ip6_plen);
    1203             :         char *lladdr = NULL;
    1204             :         int lladdrlen = 0;
    1205             :         struct rtentry *rt = NULL;
    1206             :         int is_router;
    1207             :         int is_onlink;
    1208           0 :         struct in6_addr src6 = ip6->ip6_src;
    1209           0 :         struct in6_addr redtgt6;
    1210           0 :         struct in6_addr reddst6;
    1211           0 :         union nd_opts ndopts;
    1212           0 :         char addr[INET6_ADDRSTRLEN];
    1213             : 
    1214           0 :         ifp = if_get(m->m_pkthdr.ph_ifidx);
    1215           0 :         if (ifp == NULL)
    1216           0 :                 return;
    1217             : 
    1218             :         /* XXX if we are router, we don't update route by icmp6 redirect */
    1219           0 :         if (ip6_forwarding)
    1220             :                 goto freeit;
    1221           0 :         if (!(ifp->if_xflags & IFXF_AUTOCONF6))
    1222             :                 goto freeit;
    1223             : 
    1224           0 :         IP6_EXTHDR_GET(nd_rd, struct nd_redirect *, m, off, icmp6len);
    1225           0 :         if (nd_rd == NULL) {
    1226           0 :                 icmp6stat_inc(icp6s_tooshort);
    1227           0 :                 if_put(ifp);
    1228           0 :                 return;
    1229             :         }
    1230           0 :         redtgt6 = nd_rd->nd_rd_target;
    1231           0 :         reddst6 = nd_rd->nd_rd_dst;
    1232             : 
    1233           0 :         if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
    1234           0 :                 redtgt6.s6_addr16[1] = htons(ifp->if_index);
    1235           0 :         if (IN6_IS_ADDR_LINKLOCAL(&reddst6))
    1236           0 :                 reddst6.s6_addr16[1] = htons(ifp->if_index);
    1237             : 
    1238             :         /* validation */
    1239           0 :         if (!IN6_IS_ADDR_LINKLOCAL(&src6)) {
    1240           0 :                 nd6log((LOG_ERR,
    1241             :                         "ICMP6 redirect sent from %s rejected; "
    1242             :                         "must be from linklocal\n",
    1243             :                         inet_ntop(AF_INET6, &src6, addr, sizeof(addr))));
    1244             :                 goto bad;
    1245             :         }
    1246           0 :         if (ip6->ip6_hlim != 255) {
    1247           0 :                 nd6log((LOG_ERR,
    1248             :                         "ICMP6 redirect sent from %s rejected; "
    1249             :                         "hlim=%d (must be 255)\n",
    1250             :                         inet_ntop(AF_INET6, &src6, addr, sizeof(addr)),
    1251             :                         ip6->ip6_hlim));
    1252             :                 goto bad;
    1253             :         }
    1254           0 :         if (IN6_IS_ADDR_MULTICAST(&reddst6)) {
    1255           0 :                 nd6log((LOG_ERR,
    1256             :                         "ICMP6 redirect rejected; "
    1257             :                         "redirect dst must be unicast: %s\n",
    1258             :                         icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
    1259             :                 goto bad;
    1260             :         }
    1261             :     {
    1262             :         /* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */
    1263           0 :         struct sockaddr_in6 sin6;
    1264             :         struct in6_addr *gw6;
    1265             : 
    1266           0 :         bzero(&sin6, sizeof(sin6));
    1267           0 :         sin6.sin6_family = AF_INET6;
    1268           0 :         sin6.sin6_len = sizeof(struct sockaddr_in6);
    1269           0 :         memcpy(&sin6.sin6_addr, &reddst6, sizeof(reddst6));
    1270           0 :         rt = rtalloc(sin6tosa(&sin6), 0, m->m_pkthdr.ph_rtableid);
    1271           0 :         if (rt) {
    1272           0 :                 if (rt->rt_gateway == NULL ||
    1273           0 :                     rt->rt_gateway->sa_family != AF_INET6) {
    1274           0 :                         nd6log((LOG_ERR,
    1275             :                             "ICMP6 redirect rejected; no route "
    1276             :                             "with inet6 gateway found for redirect dst: %s\n",
    1277             :                             icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
    1278           0 :                         rtfree(rt);
    1279           0 :                         goto bad;
    1280             :                 }
    1281             : 
    1282           0 :                 gw6 = &(satosin6(rt->rt_gateway)->sin6_addr);
    1283           0 :                 if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) {
    1284           0 :                         nd6log((LOG_ERR,
    1285             :                                 "ICMP6 redirect rejected; "
    1286             :                                 "not equal to gw-for-src=%s (must be same): "
    1287             :                                 "%s\n",
    1288             :                                 inet_ntop(AF_INET6, gw6, addr, sizeof(addr)),
    1289             :                                 icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
    1290           0 :                         rtfree(rt);
    1291           0 :                         goto bad;
    1292             :                 }
    1293             :         } else {
    1294           0 :                 nd6log((LOG_ERR,
    1295             :                         "ICMP6 redirect rejected; "
    1296             :                         "no route found for redirect dst: %s\n",
    1297             :                         icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
    1298           0 :                 goto bad;
    1299             :         }
    1300           0 :         rtfree(rt);
    1301             :         rt = NULL;
    1302           0 :     }
    1303             : 
    1304             :         is_router = is_onlink = 0;
    1305           0 :         if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
    1306           0 :                 is_router = 1;  /* router case */
    1307           0 :         if (bcmp(&redtgt6, &reddst6, sizeof(redtgt6)) == 0)
    1308           0 :                 is_onlink = 1;  /* on-link destination case */
    1309           0 :         if (!is_router && !is_onlink) {
    1310           0 :                 nd6log((LOG_ERR,
    1311             :                         "ICMP6 redirect rejected; "
    1312             :                         "neither router case nor onlink case: %s\n",
    1313             :                         icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
    1314             :                 goto bad;
    1315             :         }
    1316             :         /* validation passed */
    1317             : 
    1318           0 :         icmp6len -= sizeof(*nd_rd);
    1319           0 :         nd6_option_init(nd_rd + 1, icmp6len, &ndopts);
    1320           0 :         if (nd6_options(&ndopts) < 0) {
    1321           0 :                 nd6log((LOG_INFO, "icmp6_redirect_input: "
    1322             :                         "invalid ND option, rejected: %s\n",
    1323             :                         icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
    1324             :                 /* nd6_options have incremented stats */
    1325             :                 goto freeit;
    1326             :         }
    1327             : 
    1328           0 :         if (ndopts.nd_opts_tgt_lladdr) {
    1329           0 :                 lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
    1330           0 :                 lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
    1331           0 :         }
    1332             : 
    1333           0 :         if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
    1334           0 :                 nd6log((LOG_INFO,
    1335             :                         "icmp6_redirect_input: lladdrlen mismatch for %s "
    1336             :                         "(if %d, icmp6 packet %d): %s\n",
    1337             :                         inet_ntop(AF_INET6, &redtgt6, addr, sizeof(addr)),
    1338             :                         ifp->if_addrlen, lladdrlen - 2,
    1339             :                         icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
    1340             :                 goto bad;
    1341             :         }
    1342             : 
    1343             :         /* RFC 2461 8.3 */
    1344           0 :         nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT,
    1345           0 :                          is_onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER);
    1346             : 
    1347           0 :         if (!is_onlink) {       /* better router case.  perform rtredirect. */
    1348             :                 /* perform rtredirect */
    1349           0 :                 struct sockaddr_in6 sdst;
    1350           0 :                 struct sockaddr_in6 sgw;
    1351           0 :                 struct sockaddr_in6 ssrc;
    1352             :                 unsigned long rtcount;
    1353           0 :                 struct rtentry *newrt = NULL;
    1354             : 
    1355             :                 /*
    1356             :                  * do not install redirect route, if the number of entries
    1357             :                  * is too much (> hiwat).  note that, the node (= host) will
    1358             :                  * work just fine even if we do not install redirect route
    1359             :                  * (there will be additional hops, though).
    1360             :                  */
    1361           0 :                 rtcount = rt_timer_queue_count(icmp6_redirect_timeout_q);
    1362           0 :                 if (0 <= ip6_maxdynroutes && rtcount >= ip6_maxdynroutes)
    1363           0 :                         goto freeit;
    1364           0 :                 else if (0 <= icmp6_redirect_lowat &&
    1365             :                     rtcount > icmp6_redirect_lowat) {
    1366             :                         /*
    1367             :                          * XXX nuke a victim, install the new one.
    1368             :                          */
    1369             :                 }
    1370             : 
    1371           0 :                 bzero(&sdst, sizeof(sdst));
    1372           0 :                 bzero(&sgw, sizeof(sgw));
    1373           0 :                 bzero(&ssrc, sizeof(ssrc));
    1374           0 :                 sdst.sin6_family = sgw.sin6_family = ssrc.sin6_family = AF_INET6;
    1375           0 :                 sdst.sin6_len = sgw.sin6_len = ssrc.sin6_len =
    1376             :                         sizeof(struct sockaddr_in6);
    1377           0 :                 memcpy(&sgw.sin6_addr, &redtgt6, sizeof(struct in6_addr));
    1378           0 :                 memcpy(&sdst.sin6_addr, &reddst6, sizeof(struct in6_addr));
    1379           0 :                 memcpy(&ssrc.sin6_addr, &src6, sizeof(struct in6_addr));
    1380           0 :                 rtredirect(sin6tosa(&sdst), sin6tosa(&sgw), sin6tosa(&ssrc),
    1381           0 :                     &newrt, m->m_pkthdr.ph_rtableid);
    1382             : 
    1383           0 :                 if (newrt) {
    1384           0 :                         (void)rt_timer_add(newrt, icmp6_redirect_timeout,
    1385           0 :                             icmp6_redirect_timeout_q, m->m_pkthdr.ph_rtableid);
    1386           0 :                         rtfree(newrt);
    1387           0 :                 }
    1388           0 :         }
    1389             :         /* finally update cached route in each socket via pfctlinput */
    1390             :         {
    1391           0 :                 struct sockaddr_in6 sdst;
    1392             : 
    1393           0 :                 bzero(&sdst, sizeof(sdst));
    1394           0 :                 sdst.sin6_family = AF_INET6;
    1395           0 :                 sdst.sin6_len = sizeof(struct sockaddr_in6);
    1396           0 :                 memcpy(&sdst.sin6_addr, &reddst6, sizeof(struct in6_addr));
    1397           0 :                 pfctlinput(PRC_REDIRECT_HOST, sin6tosa(&sdst));
    1398           0 :         }
    1399             : 
    1400             :  freeit:
    1401           0 :         if_put(ifp);
    1402           0 :         m_freem(m);
    1403           0 :         return;
    1404             : 
    1405             :  bad:
    1406           0 :         if_put(ifp);
    1407           0 :         icmp6stat_inc(icp6s_badredirect);
    1408           0 :         m_freem(m);
    1409           0 : }
    1410             : 
    1411             : void
    1412           0 : icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt)
    1413             : {
    1414             :         struct ifnet *ifp = NULL;
    1415             :         struct in6_addr *ifp_ll6;
    1416             :         struct in6_addr *nexthop;
    1417             :         struct ip6_hdr *sip6;   /* m0 as struct ip6_hdr */
    1418             :         struct mbuf *m = NULL;  /* newly allocated one */
    1419             :         struct ip6_hdr *ip6;    /* m as struct ip6_hdr */
    1420             :         struct nd_redirect *nd_rd;
    1421             :         size_t maxlen;
    1422             :         u_char *p;
    1423           0 :         struct sockaddr_in6 src_sa;
    1424             : 
    1425           0 :         icmp6_errcount(ND_REDIRECT, 0);
    1426             : 
    1427             :         /* if we are not router, we don't send icmp6 redirect */
    1428           0 :         if (!ip6_forwarding)
    1429             :                 goto fail;
    1430             : 
    1431             :         /* sanity check */
    1432           0 :         if (m0 == NULL || !rtisvalid(rt))
    1433             :                 goto fail;
    1434             : 
    1435           0 :         ifp = if_get(rt->rt_ifidx);
    1436           0 :         if (ifp == NULL)
    1437             :                 goto fail;
    1438             : 
    1439             :         /*
    1440             :          * Address check:
    1441             :          *  the source address must identify a neighbor, and
    1442             :          *  the destination address must not be a multicast address
    1443             :          *  [RFC 2461, sec 8.2]
    1444             :          */
    1445           0 :         sip6 = mtod(m0, struct ip6_hdr *);
    1446           0 :         bzero(&src_sa, sizeof(src_sa));
    1447           0 :         src_sa.sin6_family = AF_INET6;
    1448           0 :         src_sa.sin6_len = sizeof(src_sa);
    1449           0 :         src_sa.sin6_addr = sip6->ip6_src;
    1450             :         /* we don't currently use sin6_scope_id, but eventually use it */
    1451           0 :         src_sa.sin6_scope_id = in6_addr2scopeid(ifp->if_index, &sip6->ip6_src);
    1452           0 :         if (nd6_is_addr_neighbor(&src_sa, ifp) == 0)
    1453             :                 goto fail;
    1454           0 :         if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst))
    1455             :                 goto fail;      /* what should we do here? */
    1456             : 
    1457             :         /* rate limit */
    1458           0 :         if (icmp6_ratelimit(&sip6->ip6_src, ND_REDIRECT, 0))
    1459             :                 goto fail;
    1460             : 
    1461             :         /*
    1462             :          * Since we are going to append up to 1280 bytes (= IPV6_MMTU),
    1463             :          * we almost always ask for an mbuf cluster for simplicity.
    1464             :          * (MHLEN < IPV6_MMTU is almost always true)
    1465             :          */
    1466             : #if IPV6_MMTU >= MCLBYTES
    1467             : # error assumption failed about IPV6_MMTU and MCLBYTES
    1468             : #endif
    1469           0 :         MGETHDR(m, M_DONTWAIT, MT_HEADER);
    1470           0 :         if (m && IPV6_MMTU >= MHLEN)
    1471           0 :                 MCLGET(m, M_DONTWAIT);
    1472           0 :         if (!m)
    1473             :                 goto fail;
    1474           0 :         m->m_pkthdr.ph_ifidx = 0;
    1475           0 :         m->m_len = 0;
    1476           0 :         maxlen = M_TRAILINGSPACE(m);
    1477           0 :         maxlen = min(IPV6_MMTU, maxlen);
    1478             :         /* just for safety */
    1479           0 :         if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) +
    1480           0 :             ((sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7)) {
    1481             :                 goto fail;
    1482             :         }
    1483             : 
    1484             :         {
    1485             :                 /* get ip6 linklocal address for ifp(my outgoing interface). */
    1486             :                 struct in6_ifaddr *ia6;
    1487           0 :                 if ((ia6 = in6ifa_ifpforlinklocal(ifp, IN6_IFF_TENTATIVE|
    1488           0 :                     IN6_IFF_DUPLICATED|IN6_IFF_ANYCAST)) == NULL)
    1489           0 :                         goto fail;
    1490           0 :                 ifp_ll6 = &ia6->ia_addr.sin6_addr;
    1491           0 :         }
    1492             : 
    1493             :         /* get ip6 linklocal address for the router. */
    1494           0 :         if (rt->rt_gateway && (rt->rt_flags & RTF_GATEWAY)) {
    1495             :                 struct sockaddr_in6 *sin6;
    1496           0 :                 sin6 = satosin6(rt->rt_gateway);
    1497           0 :                 nexthop = &sin6->sin6_addr;
    1498           0 :                 if (!IN6_IS_ADDR_LINKLOCAL(nexthop))
    1499           0 :                         nexthop = NULL;
    1500           0 :         } else
    1501             :                 nexthop = NULL;
    1502             : 
    1503             :         /* ip6 */
    1504           0 :         ip6 = mtod(m, struct ip6_hdr *);
    1505           0 :         ip6->ip6_flow = 0;
    1506           0 :         ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
    1507           0 :         ip6->ip6_vfc |= IPV6_VERSION;
    1508             :         /* ip6->ip6_plen will be set later */
    1509           0 :         ip6->ip6_nxt = IPPROTO_ICMPV6;
    1510           0 :         ip6->ip6_hlim = 255;
    1511             :         /* ip6->ip6_src must be linklocal addr for my outgoing if. */
    1512           0 :         bcopy(ifp_ll6, &ip6->ip6_src, sizeof(struct in6_addr));
    1513           0 :         bcopy(&sip6->ip6_src, &ip6->ip6_dst, sizeof(struct in6_addr));
    1514             : 
    1515             :         /* ND Redirect */
    1516           0 :         nd_rd = (struct nd_redirect *)(ip6 + 1);
    1517           0 :         nd_rd->nd_rd_type = ND_REDIRECT;
    1518           0 :         nd_rd->nd_rd_code = 0;
    1519           0 :         nd_rd->nd_rd_reserved = 0;
    1520           0 :         if (rt->rt_flags & RTF_GATEWAY) {
    1521             :                 /*
    1522             :                  * nd_rd->nd_rd_target must be a link-local address in
    1523             :                  * better router cases.
    1524             :                  */
    1525           0 :                 if (!nexthop)
    1526             :                         goto fail;
    1527           0 :                 bcopy(nexthop, &nd_rd->nd_rd_target,
    1528             :                       sizeof(nd_rd->nd_rd_target));
    1529           0 :                 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
    1530             :                       sizeof(nd_rd->nd_rd_dst));
    1531           0 :         } else {
    1532             :                 /* make sure redtgt == reddst */
    1533             :                 nexthop = &sip6->ip6_dst;
    1534           0 :                 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_target,
    1535             :                       sizeof(nd_rd->nd_rd_target));
    1536           0 :                 bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
    1537             :                       sizeof(nd_rd->nd_rd_dst));
    1538             :         }
    1539             : 
    1540           0 :         p = (u_char *)(nd_rd + 1);
    1541             : 
    1542             :         {
    1543             :                 /* target lladdr option */
    1544             :                 struct rtentry *nrt;
    1545             :                 int len;
    1546             :                 struct sockaddr_dl *sdl;
    1547             :                 struct nd_opt_hdr *nd_opt;
    1548             :                 char *lladdr;
    1549             : 
    1550           0 :                 len = sizeof(*nd_opt) + ifp->if_addrlen;
    1551           0 :                 len = (len + 7) & ~7;       /* round by 8 */
    1552             :                 /* safety check */
    1553           0 :                 if (len + (p - (u_char *)ip6) > maxlen)
    1554           0 :                         goto nolladdropt;
    1555           0 :                 nrt = nd6_lookup(nexthop, 0, ifp, ifp->if_rdomain);
    1556           0 :                 if ((nrt != NULL) &&
    1557           0 :                     (nrt->rt_flags & (RTF_GATEWAY|RTF_LLINFO)) == RTF_LLINFO &&
    1558           0 :                     (nrt->rt_gateway->sa_family == AF_LINK) &&
    1559           0 :                     (sdl = satosdl(nrt->rt_gateway)) &&
    1560           0 :                     sdl->sdl_alen) {
    1561           0 :                         nd_opt = (struct nd_opt_hdr *)p;
    1562           0 :                         nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
    1563           0 :                         nd_opt->nd_opt_len = len >> 3;
    1564           0 :                         lladdr = (char *)(nd_opt + 1);
    1565           0 :                         bcopy(LLADDR(sdl), lladdr, ifp->if_addrlen);
    1566           0 :                         p += len;
    1567           0 :                 }
    1568           0 :                 rtfree(nrt);
    1569           0 :         }
    1570             :   nolladdropt:;
    1571             : 
    1572           0 :         m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
    1573             : 
    1574             :         /* just to be safe */
    1575           0 :         if (p - (u_char *)ip6 > maxlen)
    1576             :                 goto noredhdropt;
    1577             : 
    1578             :         {
    1579             :                 /* redirected header option */
    1580             :                 int len;
    1581             :                 struct nd_opt_rd_hdr *nd_opt_rh;
    1582             : 
    1583             :                 /*
    1584             :                  * compute the maximum size for icmp6 redirect header option.
    1585             :                  * XXX room for auth header?
    1586             :                  */
    1587           0 :                 len = maxlen - (p - (u_char *)ip6);
    1588           0 :                 len &= ~7;
    1589             : 
    1590             :                 /*
    1591             :                  * Redirected header option spec (RFC2461 4.6.3) talks nothing
    1592             :                  * about padding/truncate rule for the original IP packet.
    1593             :                  * From the discussion on IPv6imp in Feb 1999,
    1594             :                  * the consensus was:
    1595             :                  * - "attach as much as possible" is the goal
    1596             :                  * - pad if not aligned (original size can be guessed by
    1597             :                  *   original ip6 header)
    1598             :                  * Following code adds the padding if it is simple enough,
    1599             :                  * and truncates if not.
    1600             :                  */
    1601           0 :                 if (len - sizeof(*nd_opt_rh) < m0->m_pkthdr.len) {
    1602             :                         /* not enough room, truncate */
    1603           0 :                         m_adj(m0, (len - sizeof(*nd_opt_rh)) -
    1604             :                             m0->m_pkthdr.len);
    1605           0 :                 } else {
    1606             :                         /*
    1607             :                          * enough room, truncate if not aligned.
    1608             :                          * we don't pad here for simplicity.
    1609             :                          */
    1610             :                         size_t extra;
    1611             : 
    1612           0 :                         extra = m0->m_pkthdr.len % 8;
    1613           0 :                         if (extra) {
    1614             :                                 /* truncate */
    1615           0 :                                 m_adj(m0, -extra);
    1616           0 :                         }
    1617           0 :                         len = m0->m_pkthdr.len + sizeof(*nd_opt_rh);
    1618             :                 }
    1619             : 
    1620           0 :                 nd_opt_rh = (struct nd_opt_rd_hdr *)p;
    1621           0 :                 bzero(nd_opt_rh, sizeof(*nd_opt_rh));
    1622           0 :                 nd_opt_rh->nd_opt_rh_type = ND_OPT_REDIRECTED_HEADER;
    1623           0 :                 nd_opt_rh->nd_opt_rh_len = len >> 3;
    1624           0 :                 p += sizeof(*nd_opt_rh);
    1625           0 :                 m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
    1626             : 
    1627             :                 /* connect m0 to m */
    1628           0 :                 m->m_pkthdr.len += m0->m_pkthdr.len;
    1629           0 :                 m_cat(m, m0);
    1630             :                 m0 = NULL;
    1631           0 :         }
    1632             : noredhdropt:
    1633           0 :         m_freem(m0);
    1634             :         m0 = NULL;
    1635             : 
    1636           0 :         sip6 = mtod(m, struct ip6_hdr *);
    1637           0 :         if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_src))
    1638           0 :                 sip6->ip6_src.s6_addr16[1] = 0;
    1639           0 :         if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_dst))
    1640           0 :                 sip6->ip6_dst.s6_addr16[1] = 0;
    1641             : #if 0
    1642             :         if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src))
    1643             :                 ip6->ip6_src.s6_addr16[1] = 0;
    1644             :         if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst))
    1645             :                 ip6->ip6_dst.s6_addr16[1] = 0;
    1646             : #endif
    1647           0 :         if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_target))
    1648           0 :                 nd_rd->nd_rd_target.s6_addr16[1] = 0;
    1649           0 :         if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_dst))
    1650           0 :                 nd_rd->nd_rd_dst.s6_addr16[1] = 0;
    1651             : 
    1652           0 :         ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
    1653             : 
    1654           0 :         nd_rd->nd_rd_cksum = 0;
    1655           0 :         m->m_pkthdr.csum_flags = M_ICMP_CSUM_OUT;
    1656             : 
    1657             :         /* send the packet to outside... */
    1658           0 :         ip6_output(m, NULL, NULL, 0, NULL, NULL);
    1659             : 
    1660           0 :         icmp6stat_inc(icp6s_outhist + ND_REDIRECT);
    1661             : 
    1662           0 :         if_put(ifp);
    1663           0 :         return;
    1664             : 
    1665             : fail:
    1666           0 :         if_put(ifp);
    1667           0 :         m_freem(m);
    1668           0 :         m_freem(m0);
    1669           0 : }
    1670             : 
    1671             : /*
    1672             :  * ICMPv6 socket option processing.
    1673             :  */
    1674             : int
    1675           0 : icmp6_ctloutput(int op, struct socket *so, int level, int optname,
    1676             :     struct mbuf *m)
    1677             : {
    1678             :         int error = 0;
    1679           0 :         struct inpcb *in6p = sotoinpcb(so);
    1680             : 
    1681           0 :         if (level != IPPROTO_ICMPV6)
    1682           0 :                 return EINVAL;
    1683             : 
    1684           0 :         switch (op) {
    1685             :         case PRCO_SETOPT:
    1686           0 :                 switch (optname) {
    1687             :                 case ICMP6_FILTER:
    1688             :                     {
    1689             :                         struct icmp6_filter *p;
    1690             : 
    1691           0 :                         if (m == NULL || m->m_len != sizeof(*p)) {
    1692             :                                 error = EMSGSIZE;
    1693           0 :                                 break;
    1694             :                         }
    1695           0 :                         p = mtod(m, struct icmp6_filter *);
    1696           0 :                         if (!p || !in6p->inp_icmp6filt) {
    1697             :                                 error = EINVAL;
    1698           0 :                                 break;
    1699             :                         }
    1700           0 :                         bcopy(p, in6p->inp_icmp6filt,
    1701             :                                 sizeof(struct icmp6_filter));
    1702             :                         error = 0;
    1703           0 :                         break;
    1704             :                     }
    1705             : 
    1706             :                 default:
    1707             :                         error = ENOPROTOOPT;
    1708           0 :                         break;
    1709             :                 }
    1710             :                 break;
    1711             : 
    1712             :         case PRCO_GETOPT:
    1713           0 :                 switch (optname) {
    1714             :                 case ICMP6_FILTER:
    1715             :                     {
    1716             :                         struct icmp6_filter *p;
    1717             : 
    1718           0 :                         if (!in6p->inp_icmp6filt) {
    1719             :                                 error = EINVAL;
    1720           0 :                                 break;
    1721             :                         }
    1722           0 :                         m->m_len = sizeof(struct icmp6_filter);
    1723           0 :                         p = mtod(m, struct icmp6_filter *);
    1724           0 :                         bcopy(in6p->inp_icmp6filt, p,
    1725             :                                 sizeof(struct icmp6_filter));
    1726             :                         error = 0;
    1727           0 :                         break;
    1728             :                     }
    1729             : 
    1730             :                 default:
    1731             :                         error = ENOPROTOOPT;
    1732           0 :                         break;
    1733             :                 }
    1734             :                 break;
    1735             :         }
    1736             : 
    1737           0 :         return (error);
    1738           0 : }
    1739             : 
    1740             : /*
    1741             :  * Perform rate limit check.
    1742             :  * Returns 0 if it is okay to send the icmp6 packet.
    1743             :  * Returns 1 if the router SHOULD NOT send this icmp6 packet due to rate
    1744             :  * limitation.
    1745             :  *
    1746             :  * XXX per-destination/type check necessary?
    1747             :  *
    1748             :  * dst - not used at this moment
    1749             :  * type - not used at this moment
    1750             :  * code - not used at this moment
    1751             :  */
    1752             : int
    1753           0 : icmp6_ratelimit(const struct in6_addr *dst, const int type, const int code)
    1754             : {
    1755             :         /* PPS limit */
    1756           0 :         if (!ppsratecheck(&icmp6errppslim_last, &icmp6errpps_count,
    1757           0 :             icmp6errppslim))
    1758           0 :                 return 1;       /* The packet is subject to rate limit */
    1759           0 :         return 0;               /* okay to send */
    1760           0 : }
    1761             : 
    1762             : struct rtentry *
    1763           0 : icmp6_mtudisc_clone(struct sockaddr *dst, u_int rtableid)
    1764             : {
    1765             :         struct rtentry *rt;
    1766             :         int    error;
    1767             : 
    1768           0 :         rt = rtalloc(dst, RT_RESOLVE, rtableid);
    1769             : 
    1770             :         /* Check if the route is actually usable */
    1771           0 :         if (!rtisvalid(rt) || (rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)))
    1772             :                 goto bad;
    1773             : 
    1774             :         /*
    1775             :          * No PMTU for local routes and permanent neighbors,
    1776             :          * ARP and NDP use the same expire timer as the route.
    1777             :          */
    1778           0 :         if (ISSET(rt->rt_flags, RTF_LOCAL) ||
    1779           0 :             (ISSET(rt->rt_flags, RTF_LLINFO) && rt->rt_expire == 0))
    1780             :                 goto bad;
    1781             : 
    1782             :         /* If we didn't get a host route, allocate one */
    1783           0 :         if ((rt->rt_flags & RTF_HOST) == 0) {
    1784           0 :                 struct rtentry *nrt;
    1785           0 :                 struct rt_addrinfo info;
    1786           0 :                 struct sockaddr_rtlabel sa_rl;
    1787             : 
    1788           0 :                 memset(&info, 0, sizeof(info));
    1789           0 :                 info.rti_ifa = rt->rt_ifa;
    1790           0 :                 info.rti_flags = RTF_GATEWAY | RTF_HOST | RTF_DYNAMIC;
    1791           0 :                 info.rti_info[RTAX_DST] = dst;
    1792           0 :                 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
    1793           0 :                 info.rti_info[RTAX_LABEL] =
    1794           0 :                     rtlabel_id2sa(rt->rt_labelid, &sa_rl);
    1795             : 
    1796           0 :                 error = rtrequest(RTM_ADD, &info, rt->rt_priority, &nrt,
    1797             :                     rtableid);
    1798           0 :                 if (error)
    1799           0 :                         goto bad;
    1800           0 :                 nrt->rt_rmx = rt->rt_rmx;
    1801           0 :                 rtfree(rt);
    1802           0 :                 rt = nrt;
    1803           0 :                 rtm_send(rt, RTM_ADD, 0, rtableid);
    1804           0 :         }
    1805           0 :         error = rt_timer_add(rt, icmp6_mtudisc_timeout, icmp6_mtudisc_timeout_q,
    1806             :             rtableid);
    1807           0 :         if (error)
    1808             :                 goto bad;
    1809             : 
    1810           0 :         return (rt);
    1811             : bad:
    1812           0 :         rtfree(rt);
    1813           0 :         return (NULL);
    1814           0 : }
    1815             : 
    1816             : void
    1817           0 : icmp6_mtudisc_timeout(struct rtentry *rt, struct rttimer *r)
    1818             : {
    1819             :         struct ifnet *ifp;
    1820             : 
    1821           0 :         NET_ASSERT_LOCKED();
    1822             : 
    1823           0 :         ifp = if_get(rt->rt_ifidx);
    1824           0 :         if (ifp == NULL)
    1825           0 :                 return;
    1826             : 
    1827           0 :         if ((rt->rt_flags & (RTF_DYNAMIC|RTF_HOST)) == (RTF_DYNAMIC|RTF_HOST)) {
    1828           0 :                 rtdeletemsg(rt, ifp, r->rtt_tableid);
    1829           0 :         } else {
    1830           0 :                 if (!(rt->rt_locks & RTV_MTU))
    1831           0 :                         rt->rt_mtu = 0;
    1832             :         }
    1833             : 
    1834           0 :         if_put(ifp);
    1835           0 : }
    1836             : 
    1837             : void
    1838           0 : icmp6_redirect_timeout(struct rtentry *rt, struct rttimer *r)
    1839             : {
    1840             :         struct ifnet *ifp;
    1841             : 
    1842           0 :         NET_ASSERT_LOCKED();
    1843             : 
    1844           0 :         ifp = if_get(rt->rt_ifidx);
    1845           0 :         if (ifp == NULL)
    1846           0 :                 return;
    1847             : 
    1848           0 :         if ((rt->rt_flags & (RTF_DYNAMIC|RTF_HOST)) == (RTF_DYNAMIC|RTF_HOST)) {
    1849           0 :                 rtdeletemsg(rt, ifp, r->rtt_tableid);
    1850           0 :         }
    1851             : 
    1852           0 :         if_put(ifp);
    1853           0 : }
    1854             : 
    1855             : int *icmpv6ctl_vars[ICMPV6CTL_MAXID] = ICMPV6CTL_VARS;
    1856             : 
    1857             : int
    1858           0 : icmp6_sysctl_icmp6stat(void *oldp, size_t *oldlenp, void *newp)
    1859             : {
    1860             :         struct icmp6stat *icmp6stat;
    1861             :         int ret;
    1862             : 
    1863             :         CTASSERT(sizeof(*icmp6stat) == icp6s_ncounters * sizeof(uint64_t));
    1864           0 :         icmp6stat = malloc(sizeof(*icmp6stat), M_TEMP, M_WAITOK|M_ZERO);
    1865           0 :         counters_read(icmp6counters, (uint64_t *)icmp6stat, icp6s_ncounters);
    1866           0 :         ret = sysctl_rdstruct(oldp, oldlenp, newp,
    1867             :             icmp6stat, sizeof(*icmp6stat));
    1868           0 :         free(icmp6stat, M_TEMP, sizeof(*icmp6stat));
    1869             : 
    1870           0 :         return (ret);
    1871             : }
    1872             : 
    1873             : int
    1874           0 : icmp6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
    1875             :     void *newp, size_t newlen)
    1876             : {
    1877             :         int error;
    1878             : 
    1879             :         /* All sysctl names at this level are terminal. */
    1880           0 :         if (namelen != 1)
    1881           0 :                 return ENOTDIR;
    1882             : 
    1883           0 :         switch (name[0]) {
    1884             : 
    1885             :         case ICMPV6CTL_STATS:
    1886           0 :                 return icmp6_sysctl_icmp6stat(oldp, oldlenp, newp);
    1887             :         default:
    1888           0 :                 if (name[0] < ICMPV6CTL_MAXID) {
    1889           0 :                         NET_LOCK();
    1890           0 :                         error = sysctl_int_arr(icmpv6ctl_vars, name, namelen,
    1891             :                             oldp, oldlenp, newp, newlen);
    1892           0 :                         NET_UNLOCK();
    1893           0 :                         return (error);
    1894             :                 }
    1895           0 :                 return ENOPROTOOPT;
    1896             :         }
    1897             :         /* NOTREACHED */
    1898           0 : }

Generated by: LCOV version 1.13