[BACK]Return to icmp6.c CVS log [TXT][DIR] Up to [local] / sys / netinet6

Annotation of sys/netinet6/icmp6.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: icmp6.c,v 1.94 2007/06/01 00:52:38 henning 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 "faith.h"
        !            65: #include "carp.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/protosw.h>
        !            72: #include <sys/socket.h>
        !            73: #include <sys/socketvar.h>
        !            74: #include <sys/time.h>
        !            75: #include <sys/kernel.h>
        !            76: #include <sys/syslog.h>
        !            77: #include <sys/domain.h>
        !            78:
        !            79: #include <net/if.h>
        !            80: #include <net/route.h>
        !            81: #include <net/if_dl.h>
        !            82: #include <net/if_types.h>
        !            83:
        !            84: #include <netinet/in.h>
        !            85: #include <netinet/in_var.h>
        !            86: #include <netinet/in_systm.h>
        !            87: #include <netinet/ip.h>
        !            88: #include <netinet/ip6.h>
        !            89: #include <netinet6/ip6_var.h>
        !            90: #include <netinet/icmp6.h>
        !            91: #include <netinet6/mld6_var.h>
        !            92: #include <netinet/in_pcb.h>
        !            93: #include <netinet6/nd6.h>
        !            94: #include <netinet6/in6_ifattach.h>
        !            95: #include <netinet6/ip6protosw.h>
        !            96:
        !            97: #if NCARP > 0
        !            98: #include <netinet/ip_carp.h>
        !            99: #endif
        !           100:
        !           101: /* inpcb members */
        !           102: #define in6pcb         inpcb
        !           103: #define in6p_laddr     inp_laddr6
        !           104: #define in6p_faddr     inp_faddr6
        !           105: #define in6p_icmp6filt inp_icmp6filt
        !           106: #define in6p_route     inp_route
        !           107: #define in6p_socket    inp_socket
        !           108: #define in6p_flags     inp_flags
        !           109: #define in6p_moptions  inp_moptions6
        !           110: #define in6p_outputopts        inp_outputopts6
        !           111: #define in6p_ip6       inp_ipv6
        !           112: #define in6p_flowinfo  inp_flowinfo
        !           113: #define in6p_sp                inp_sp
        !           114: #define in6p_next      inp_next
        !           115: #define in6p_prev      inp_prev
        !           116: /* macro names */
        !           117: #define sotoin6pcb     sotoinpcb
        !           118: /* function names */
        !           119: #define in6_pcbdetach  in_pcbdetach
        !           120: #define in6_rtchange   in_rtchange
        !           121:
        !           122: /*
        !           123:  * for KAME src sync over BSD*'s.  XXX: FreeBSD (>=3) are VERY different from
        !           124:  * others...
        !           125:  */
        !           126: #define in6p_ip6_nxt   inp_ipv6.ip6_nxt
        !           127:
        !           128: extern struct domain inet6domain;
        !           129: extern struct ip6protosw inet6sw[];
        !           130: extern u_char ip6_protox[];
        !           131:
        !           132: struct icmp6stat icmp6stat;
        !           133:
        !           134: extern struct inpcbtable rawin6pcbtable;
        !           135: extern int icmp6errppslim;
        !           136: static int icmp6errpps_count = 0;
        !           137: static struct timeval icmp6errppslim_last;
        !           138: extern int icmp6_nodeinfo;
        !           139:
        !           140: /*
        !           141:  * List of callbacks to notify when Path MTU changes are made.
        !           142:  */
        !           143: struct icmp6_mtudisc_callback {
        !           144:        LIST_ENTRY(icmp6_mtudisc_callback) mc_list;
        !           145:        void (*mc_func)(struct in6_addr *);
        !           146: };
        !           147:
        !           148: LIST_HEAD(, icmp6_mtudisc_callback) icmp6_mtudisc_callbacks =
        !           149:     LIST_HEAD_INITIALIZER(&icmp6_mtudisc_callbacks);
        !           150:
        !           151: static struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL;
        !           152: extern int pmtu_expire;
        !           153:
        !           154: /* XXX do these values make any sense? */
        !           155: static int icmp6_mtudisc_hiwat = 1280;
        !           156: static int icmp6_mtudisc_lowat = 256;
        !           157:
        !           158: /*
        !           159:  * keep track of # of redirect routes.
        !           160:  */
        !           161: static struct rttimer_queue *icmp6_redirect_timeout_q = NULL;
        !           162:
        !           163: /* XXX experimental, turned off */
        !           164: static int icmp6_redirect_hiwat = -1;
        !           165: static int icmp6_redirect_lowat = -1;
        !           166:
        !           167: static void icmp6_errcount(struct icmp6errstat *, int, int);
        !           168: static int icmp6_rip6_input(struct mbuf **, int);
        !           169: static int icmp6_ratelimit(const struct in6_addr *, const int, const int);
        !           170: static const char *icmp6_redirect_diag(struct in6_addr *,
        !           171:        struct in6_addr *, struct in6_addr *);
        !           172: static struct mbuf *ni6_input(struct mbuf *, int);
        !           173: static struct mbuf *ni6_nametodns(const char *, int, int);
        !           174: static int ni6_dnsmatch(const char *, int, const char *, int);
        !           175: static int ni6_addrs(struct icmp6_nodeinfo *, struct mbuf *,
        !           176:                          struct ifnet **, char *);
        !           177: static int ni6_store_addrs(struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
        !           178:                                struct ifnet *, int);
        !           179: static int icmp6_notify_error(struct mbuf *, int, int, int);
        !           180: static struct rtentry *icmp6_mtudisc_clone(struct sockaddr *);
        !           181: static void icmp6_mtudisc_timeout(struct rtentry *, struct rttimer *);
        !           182: static void icmp6_redirect_timeout(struct rtentry *, struct rttimer *);
        !           183:
        !           184: void
        !           185: icmp6_init()
        !           186: {
        !           187:        mld6_init();
        !           188:        icmp6_mtudisc_timeout_q = rt_timer_queue_create(pmtu_expire);
        !           189:        icmp6_redirect_timeout_q = rt_timer_queue_create(icmp6_redirtimeout);
        !           190: }
        !           191:
        !           192: static void
        !           193: icmp6_errcount(stat, type, code)
        !           194:        struct icmp6errstat *stat;
        !           195:        int type, code;
        !           196: {
        !           197:        switch (type) {
        !           198:        case ICMP6_DST_UNREACH:
        !           199:                switch (code) {
        !           200:                case ICMP6_DST_UNREACH_NOROUTE:
        !           201:                        stat->icp6errs_dst_unreach_noroute++;
        !           202:                        return;
        !           203:                case ICMP6_DST_UNREACH_ADMIN:
        !           204:                        stat->icp6errs_dst_unreach_admin++;
        !           205:                        return;
        !           206:                case ICMP6_DST_UNREACH_BEYONDSCOPE:
        !           207:                        stat->icp6errs_dst_unreach_beyondscope++;
        !           208:                        return;
        !           209:                case ICMP6_DST_UNREACH_ADDR:
        !           210:                        stat->icp6errs_dst_unreach_addr++;
        !           211:                        return;
        !           212:                case ICMP6_DST_UNREACH_NOPORT:
        !           213:                        stat->icp6errs_dst_unreach_noport++;
        !           214:                        return;
        !           215:                }
        !           216:                break;
        !           217:        case ICMP6_PACKET_TOO_BIG:
        !           218:                stat->icp6errs_packet_too_big++;
        !           219:                return;
        !           220:        case ICMP6_TIME_EXCEEDED:
        !           221:                switch (code) {
        !           222:                case ICMP6_TIME_EXCEED_TRANSIT:
        !           223:                        stat->icp6errs_time_exceed_transit++;
        !           224:                        return;
        !           225:                case ICMP6_TIME_EXCEED_REASSEMBLY:
        !           226:                        stat->icp6errs_time_exceed_reassembly++;
        !           227:                        return;
        !           228:                }
        !           229:                break;
        !           230:        case ICMP6_PARAM_PROB:
        !           231:                switch (code) {
        !           232:                case ICMP6_PARAMPROB_HEADER:
        !           233:                        stat->icp6errs_paramprob_header++;
        !           234:                        return;
        !           235:                case ICMP6_PARAMPROB_NEXTHEADER:
        !           236:                        stat->icp6errs_paramprob_nextheader++;
        !           237:                        return;
        !           238:                case ICMP6_PARAMPROB_OPTION:
        !           239:                        stat->icp6errs_paramprob_option++;
        !           240:                        return;
        !           241:                }
        !           242:                break;
        !           243:        case ND_REDIRECT:
        !           244:                stat->icp6errs_redirect++;
        !           245:                return;
        !           246:        }
        !           247:        stat->icp6errs_unknown++;
        !           248: }
        !           249:
        !           250: /*
        !           251:  * Register a Path MTU Discovery callback.
        !           252:  */
        !           253: void
        !           254: icmp6_mtudisc_callback_register(func)
        !           255:        void (*func)(struct in6_addr *);
        !           256: {
        !           257:        struct icmp6_mtudisc_callback *mc;
        !           258:
        !           259:        for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL;
        !           260:             mc = LIST_NEXT(mc, mc_list)) {
        !           261:                if (mc->mc_func == func)
        !           262:                        return;
        !           263:        }
        !           264:
        !           265:        mc = malloc(sizeof(*mc), M_PCB, M_NOWAIT);
        !           266:        if (mc == NULL)
        !           267:                panic("icmp6_mtudisc_callback_register");
        !           268:
        !           269:        mc->mc_func = func;
        !           270:        LIST_INSERT_HEAD(&icmp6_mtudisc_callbacks, mc, mc_list);
        !           271: }
        !           272:
        !           273: /*
        !           274:  * Generate an error packet of type error in response to bad IP6 packet.
        !           275:  */
        !           276: void
        !           277: icmp6_error(m, type, code, param)
        !           278:        struct mbuf *m;
        !           279:        int type, code, param;
        !           280: {
        !           281:        struct ip6_hdr *oip6, *nip6;
        !           282:        struct icmp6_hdr *icmp6;
        !           283:        u_int preplen;
        !           284:        int off;
        !           285:        int nxt;
        !           286:
        !           287:        icmp6stat.icp6s_error++;
        !           288:
        !           289:        /* count per-type-code statistics */
        !           290:        icmp6_errcount(&icmp6stat.icp6s_outerrhist, type, code);
        !           291:
        !           292:        if (m->m_len < sizeof(struct ip6_hdr)) {
        !           293:                m = m_pullup(m, sizeof(struct ip6_hdr));
        !           294:                if (m == NULL)
        !           295:                        return;
        !           296:        }
        !           297:        oip6 = mtod(m, struct ip6_hdr *);
        !           298:
        !           299:        /*
        !           300:         * If the destination address of the erroneous packet is a multicast
        !           301:         * address, or the packet was sent using link-layer multicast,
        !           302:         * we should basically suppress sending an error (RFC 2463, Section
        !           303:         * 2.4).
        !           304:         * We have two exceptions (the item e.2 in that section):
        !           305:         * - the Pakcet Too Big message can be sent for path MTU discovery.
        !           306:         * - the Parameter Problem Message that can be allowed an icmp6 error
        !           307:         *   in the option type field.  This check has been done in
        !           308:         *   ip6_unknown_opt(), so we can just check the type and code.
        !           309:         */
        !           310:        if ((m->m_flags & (M_BCAST|M_MCAST) ||
        !           311:             IN6_IS_ADDR_MULTICAST(&oip6->ip6_dst)) &&
        !           312:            (type != ICMP6_PACKET_TOO_BIG &&
        !           313:             (type != ICMP6_PARAM_PROB ||
        !           314:              code != ICMP6_PARAMPROB_OPTION)))
        !           315:                goto freeit;
        !           316:
        !           317:        /*
        !           318:         * RFC 2463, 2.4 (e.5): source address check.
        !           319:         * XXX: the case of anycast source?
        !           320:         */
        !           321:        if (IN6_IS_ADDR_UNSPECIFIED(&oip6->ip6_src) ||
        !           322:            IN6_IS_ADDR_MULTICAST(&oip6->ip6_src))
        !           323:                goto freeit;
        !           324:
        !           325:        /*
        !           326:         * If we are about to send ICMPv6 against ICMPv6 error/redirect,
        !           327:         * don't do it.
        !           328:         */
        !           329:        nxt = -1;
        !           330:        off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
        !           331:        if (off >= 0 && nxt == IPPROTO_ICMPV6) {
        !           332:                struct icmp6_hdr *icp;
        !           333:
        !           334:                IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off,
        !           335:                        sizeof(*icp));
        !           336:                if (icp == NULL) {
        !           337:                        icmp6stat.icp6s_tooshort++;
        !           338:                        return;
        !           339:                }
        !           340:                if (icp->icmp6_type < ICMP6_ECHO_REQUEST ||
        !           341:                    icp->icmp6_type == ND_REDIRECT) {
        !           342:                        /*
        !           343:                         * ICMPv6 error
        !           344:                         * Special case: for redirect (which is
        !           345:                         * informational) we must not send icmp6 error.
        !           346:                         */
        !           347:                        icmp6stat.icp6s_canterror++;
        !           348:                        goto freeit;
        !           349:                } else {
        !           350:                        /* ICMPv6 informational - send the error */
        !           351:                }
        !           352:        }
        !           353:        else {
        !           354:                /* non-ICMPv6 - send the error */
        !           355:        }
        !           356:
        !           357:        oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */
        !           358:
        !           359:        /* Finally, do rate limitation check. */
        !           360:        if (icmp6_ratelimit(&oip6->ip6_src, type, code)) {
        !           361:                icmp6stat.icp6s_toofreq++;
        !           362:                goto freeit;
        !           363:        }
        !           364:
        !           365:        /*
        !           366:         * OK, ICMP6 can be generated.
        !           367:         */
        !           368:
        !           369:        if (m->m_pkthdr.len >= ICMPV6_PLD_MAXLEN)
        !           370:                m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len);
        !           371:
        !           372:        preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
        !           373:        M_PREPEND(m, preplen, M_DONTWAIT);
        !           374:        if (m && m->m_len < preplen)
        !           375:                m = m_pullup(m, preplen);
        !           376:        if (m == NULL) {
        !           377:                nd6log((LOG_DEBUG, "ENOBUFS in icmp6_error %d\n", __LINE__));
        !           378:                return;
        !           379:        }
        !           380:
        !           381:        nip6 = mtod(m, struct ip6_hdr *);
        !           382:        nip6->ip6_src  = oip6->ip6_src;
        !           383:        nip6->ip6_dst  = oip6->ip6_dst;
        !           384:
        !           385:        if (IN6_IS_SCOPE_EMBED(&oip6->ip6_src))
        !           386:                oip6->ip6_src.s6_addr16[1] = 0;
        !           387:        if (IN6_IS_SCOPE_EMBED(&oip6->ip6_dst))
        !           388:                oip6->ip6_dst.s6_addr16[1] = 0;
        !           389:
        !           390:        icmp6 = (struct icmp6_hdr *)(nip6 + 1);
        !           391:        icmp6->icmp6_type = type;
        !           392:        icmp6->icmp6_code = code;
        !           393:        icmp6->icmp6_pptr = htonl((u_int32_t)param);
        !           394:
        !           395:        /*
        !           396:         * icmp6_reflect() is designed to be in the input path.
        !           397:         * icmp6_error() can be called from both input and outut path,
        !           398:         * and if we are in output path rcvif could contain bogus value.
        !           399:         * clear m->m_pkthdr.rcvif for safety, we should have enough scope
        !           400:         * information in ip header (nip6).
        !           401:         */
        !           402:        m->m_pkthdr.rcvif = NULL;
        !           403:
        !           404:        icmp6stat.icp6s_outhist[type]++;
        !           405:        icmp6_reflect(m, sizeof(struct ip6_hdr)); /* header order: IPv6 - ICMPv6 */
        !           406:
        !           407:        return;
        !           408:
        !           409:   freeit:
        !           410:        /*
        !           411:         * If we can't tell wheter or not we can generate ICMP6, free it.
        !           412:         */
        !           413:        m_freem(m);
        !           414: }
        !           415:
        !           416: /*
        !           417:  * Process a received ICMP6 message.
        !           418:  */
        !           419: int
        !           420: icmp6_input(mp, offp, proto)
        !           421:        struct mbuf **mp;
        !           422:        int *offp, proto;
        !           423: {
        !           424:        struct mbuf *m = *mp, *n;
        !           425:        struct ip6_hdr *ip6, *nip6;
        !           426:        struct icmp6_hdr *icmp6, *nicmp6;
        !           427:        int off = *offp;
        !           428:        int icmp6len = m->m_pkthdr.len - *offp;
        !           429:        int code, sum, noff;
        !           430:
        !           431:        icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_msg);
        !           432:
        !           433:        /*
        !           434:         * Locate icmp6 structure in mbuf, and check
        !           435:         * that not corrupted and of at least minimum length
        !           436:         */
        !           437:
        !           438:        ip6 = mtod(m, struct ip6_hdr *);
        !           439:        if (icmp6len < sizeof(struct icmp6_hdr)) {
        !           440:                icmp6stat.icp6s_tooshort++;
        !           441:                icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error);
        !           442:                goto freeit;
        !           443:        }
        !           444:
        !           445:        /*
        !           446:         * calculate the checksum
        !           447:         */
        !           448:        IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
        !           449:        if (icmp6 == NULL) {
        !           450:                icmp6stat.icp6s_tooshort++;
        !           451:                return IPPROTO_DONE;
        !           452:        }
        !           453:        code = icmp6->icmp6_code;
        !           454:
        !           455:        if ((sum = in6_cksum(m, IPPROTO_ICMPV6, off, icmp6len)) != 0) {
        !           456:                nd6log((LOG_ERR,
        !           457:                    "ICMP6 checksum error(%d|%x) %s\n",
        !           458:                    icmp6->icmp6_type, sum, ip6_sprintf(&ip6->ip6_src)));
        !           459:                icmp6stat.icp6s_checksum++;
        !           460:                icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_error);
        !           461:                goto freeit;
        !           462:        }
        !           463:
        !           464: #if defined(NFAITH) && 0 < NFAITH
        !           465:        if (m->m_pkthdr.rcvif && m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
        !           466:                /*
        !           467:                 * Deliver very specific ICMP6 type only.
        !           468:                 * This is important to deliver TOOBIG.  Otherwise PMTUD
        !           469:                 * will not work.
        !           470:                 */
        !           471:                switch (icmp6->icmp6_type) {
        !           472:                case ICMP6_DST_UNREACH:
        !           473:                case ICMP6_PACKET_TOO_BIG:
        !           474:                case ICMP6_TIME_EXCEEDED:
        !           475:                        break;
        !           476:                default:
        !           477:                        goto freeit;
        !           478:                }
        !           479:        }
        !           480: #endif
        !           481:
        !           482: #if NCARP > 0
        !           483:        if (m->m_pkthdr.rcvif->if_type == IFT_CARP &&
        !           484:            m->m_pkthdr.rcvif->if_flags & IFF_LINK0 &&
        !           485:            icmp6->icmp6_type == ICMP6_ECHO_REQUEST &&
        !           486:            carp_lsdrop(m, AF_INET6, ip6->ip6_src.s6_addr32,
        !           487:            ip6->ip6_dst.s6_addr32))
        !           488:                goto freeit;
        !           489: #endif
        !           490:        icmp6stat.icp6s_inhist[icmp6->icmp6_type]++;
        !           491:
        !           492:        switch (icmp6->icmp6_type) {
        !           493:        case ICMP6_DST_UNREACH:
        !           494:                icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_dstunreach);
        !           495:                switch (code) {
        !           496:                case ICMP6_DST_UNREACH_NOROUTE:
        !           497:                        code = PRC_UNREACH_NET;
        !           498:                        break;
        !           499:                case ICMP6_DST_UNREACH_ADMIN:
        !           500:                        icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_adminprohib);
        !           501:                        code = PRC_UNREACH_PROTOCOL; /* is this a good code? */
        !           502:                        break;
        !           503:                case ICMP6_DST_UNREACH_ADDR:
        !           504:                        code = PRC_HOSTDEAD;
        !           505:                        break;
        !           506: #ifdef COMPAT_RFC1885
        !           507:                case ICMP6_DST_UNREACH_NOTNEIGHBOR:
        !           508:                        code = PRC_UNREACH_SRCFAIL;
        !           509:                        break;
        !           510: #else
        !           511:                case ICMP6_DST_UNREACH_BEYONDSCOPE:
        !           512:                        /* I mean "source address was incorrect." */
        !           513:                        code = PRC_PARAMPROB;
        !           514:                        break;
        !           515: #endif
        !           516:                case ICMP6_DST_UNREACH_NOPORT:
        !           517:                        code = PRC_UNREACH_PORT;
        !           518:                        break;
        !           519:                default:
        !           520:                        goto badcode;
        !           521:                }
        !           522:                goto deliver;
        !           523:
        !           524:        case ICMP6_PACKET_TOO_BIG:
        !           525:                icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_pkttoobig);
        !           526:
        !           527:                code = PRC_MSGSIZE;
        !           528:
        !           529:                /*
        !           530:                 * Updating the path MTU will be done after examining
        !           531:                 * intermediate extension headers.
        !           532:                 */
        !           533:                goto deliver;
        !           534:
        !           535:        case ICMP6_TIME_EXCEEDED:
        !           536:                icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_timeexceed);
        !           537:                switch (code) {
        !           538:                case ICMP6_TIME_EXCEED_TRANSIT:
        !           539:                        code = PRC_TIMXCEED_INTRANS;
        !           540:                        break;
        !           541:                case ICMP6_TIME_EXCEED_REASSEMBLY:
        !           542:                        code = PRC_TIMXCEED_REASS;
        !           543:                        break;
        !           544:                default:
        !           545:                        goto badcode;
        !           546:                }
        !           547:                goto deliver;
        !           548:
        !           549:        case ICMP6_PARAM_PROB:
        !           550:                icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_paramprob);
        !           551:                switch (code) {
        !           552:                case ICMP6_PARAMPROB_NEXTHEADER:
        !           553:                        code = PRC_UNREACH_PROTOCOL;
        !           554:                        break;
        !           555:                case ICMP6_PARAMPROB_HEADER:
        !           556:                case ICMP6_PARAMPROB_OPTION:
        !           557:                        code = PRC_PARAMPROB;
        !           558:                        break;
        !           559:                default:
        !           560:                        goto badcode;
        !           561:                }
        !           562:                goto deliver;
        !           563:
        !           564:        case ICMP6_ECHO_REQUEST:
        !           565:                icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echo);
        !           566:                if (code != 0)
        !           567:                        goto badcode;
        !           568:                /*
        !           569:                 * Copy mbuf to send to two data paths: userland socket(s),
        !           570:                 * and to the querier (echo reply).
        !           571:                 * m: a copy for socket, n: a copy for querier
        !           572:                 */
        !           573:                if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
        !           574:                        /* Give up local */
        !           575:                        n = m;
        !           576:                        m = NULL;
        !           577:                        goto deliverecho;
        !           578:                }
        !           579:                /*
        !           580:                 * If the first mbuf is shared, or the first mbuf is too short,
        !           581:                 * copy the first part of the data into a fresh mbuf.
        !           582:                 * Otherwise, we will wrongly overwrite both copies.
        !           583:                 */
        !           584:                if ((n->m_flags & M_EXT) != 0 ||
        !           585:                    n->m_len < off + sizeof(struct icmp6_hdr)) {
        !           586:                        struct mbuf *n0 = n;
        !           587:                        const int maxlen = sizeof(*nip6) + sizeof(*nicmp6);
        !           588:
        !           589:                        /*
        !           590:                         * Prepare an internal mbuf.  m_pullup() doesn't
        !           591:                         * always copy the length we specified.
        !           592:                         */
        !           593:                        if (maxlen >= MCLBYTES) {
        !           594:                                /* Give up remote */
        !           595:                                m_freem(n0);
        !           596:                                break;
        !           597:                        }
        !           598:                        MGETHDR(n, M_DONTWAIT, n0->m_type);
        !           599:                        if (n && maxlen >= MHLEN) {
        !           600:                                MCLGET(n, M_DONTWAIT);
        !           601:                                if ((n->m_flags & M_EXT) == 0) {
        !           602:                                        m_free(n);
        !           603:                                        n = NULL;
        !           604:                                }
        !           605:                        }
        !           606:                        if (n == NULL) {
        !           607:                                /* Give up local */
        !           608:                                m_freem(n0);
        !           609:                                n = m;
        !           610:                                m = NULL;
        !           611:                                goto deliverecho;
        !           612:                        }
        !           613:                        M_MOVE_PKTHDR(n, n0);
        !           614:                        /*
        !           615:                         * Copy IPv6 and ICMPv6 only.
        !           616:                         */
        !           617:                        nip6 = mtod(n, struct ip6_hdr *);
        !           618:                        bcopy(ip6, nip6, sizeof(struct ip6_hdr));
        !           619:                        nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
        !           620:                        bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
        !           621:                        noff = sizeof(struct ip6_hdr);
        !           622:                        n->m_len = noff + sizeof(struct icmp6_hdr);
        !           623:                        /*
        !           624:                         * Adjust mbuf.  ip6_plen will be adjusted in
        !           625:                         * ip6_output().
        !           626:                         * n->m_pkthdr.len == n0->m_pkthdr.len at this point.
        !           627:                         */
        !           628:                        n->m_pkthdr.len += noff + sizeof(struct icmp6_hdr);
        !           629:                        n->m_pkthdr.len -= (off + sizeof(struct icmp6_hdr));
        !           630:                        m_adj(n0, off + sizeof(struct icmp6_hdr));
        !           631:                        n->m_next = n0;
        !           632:                } else {
        !           633:         deliverecho:
        !           634:                        nip6 = mtod(n, struct ip6_hdr *);
        !           635:                        IP6_EXTHDR_GET(nicmp6, struct icmp6_hdr *, n, off,
        !           636:                            sizeof(*nicmp6));
        !           637:                        noff = off;
        !           638:                }
        !           639:                nicmp6->icmp6_type = ICMP6_ECHO_REPLY;
        !           640:                nicmp6->icmp6_code = 0;
        !           641:                if (n) {
        !           642:                        icmp6stat.icp6s_reflect++;
        !           643:                        icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]++;
        !           644:                        icmp6_reflect(n, noff);
        !           645:                }
        !           646:                if (!m)
        !           647:                        goto freeit;
        !           648:                break;
        !           649:
        !           650:        case ICMP6_ECHO_REPLY:
        !           651:                icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_echoreply);
        !           652:                if (code != 0)
        !           653:                        goto badcode;
        !           654:                break;
        !           655:
        !           656:        case MLD_LISTENER_QUERY:
        !           657:        case MLD_LISTENER_REPORT:
        !           658:                if (icmp6len < sizeof(struct mld_hdr))
        !           659:                        goto badlen;
        !           660:                if (icmp6->icmp6_type == MLD_LISTENER_QUERY) /* XXX: ugly... */
        !           661:                        icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldquery);
        !           662:                else
        !           663:                        icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mldreport);
        !           664:                if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
        !           665:                        /* give up local */
        !           666:                        mld6_input(m, off);
        !           667:                        m = NULL;
        !           668:                        goto freeit;
        !           669:                }
        !           670:                mld6_input(n, off);
        !           671:                /* m stays. */
        !           672:                break;
        !           673:
        !           674:        case MLD_LISTENER_DONE:
        !           675:                icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_mlddone);
        !           676:                if (icmp6len < sizeof(struct mld_hdr))  /* necessary? */
        !           677:                        goto badlen;
        !           678:                break;          /* nothing to be done in kernel */
        !           679:
        !           680:        case MLD_MTRACE_RESP:
        !           681:        case MLD_MTRACE:
        !           682:                /* XXX: these two are experimental.  not officially defined. */
        !           683:                /* XXX: per-interface statistics? */
        !           684:                break;          /* just pass it to applications */
        !           685:
        !           686:        case ICMP6_WRUREQUEST:  /* ICMP6_FQDN_QUERY */
        !           687:            {
        !           688:                enum { WRU, FQDN } mode;
        !           689:
        !           690:                if (!icmp6_nodeinfo)
        !           691:                        break;
        !           692:
        !           693:                if (icmp6len == sizeof(struct icmp6_hdr) + 4)
        !           694:                        mode = WRU;
        !           695:                else if (icmp6len >= sizeof(struct icmp6_nodeinfo))
        !           696:                        mode = FQDN;
        !           697:                else
        !           698:                        goto badlen;
        !           699:
        !           700:                if (mode == FQDN) {
        !           701:                        n = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
        !           702:                        if (n)
        !           703:                                n = ni6_input(n, off);
        !           704:                        /* XXX meaningless if n == NULL */
        !           705:                        noff = sizeof(struct ip6_hdr);
        !           706:                } else {
        !           707:                        u_char *p;
        !           708:                        int maxlen, maxhlen;
        !           709:
        !           710:                        if ((icmp6_nodeinfo & 1) == 0)
        !           711:                                break;
        !           712:
        !           713:                        if (code != 0)
        !           714:                                goto badcode;
        !           715:                        maxlen = sizeof(*nip6) + sizeof(*nicmp6) + 4;
        !           716:                        if (maxlen >= MCLBYTES) {
        !           717:                                /* Give up remote */
        !           718:                                break;
        !           719:                        }
        !           720:                        MGETHDR(n, M_DONTWAIT, m->m_type);
        !           721:                        if (n && maxlen > MHLEN) {
        !           722:                                MCLGET(n, M_DONTWAIT);
        !           723:                                if ((n->m_flags & M_EXT) == 0) {
        !           724:                                        m_free(n);
        !           725:                                        n = NULL;
        !           726:                                }
        !           727:                        }
        !           728:                        if (n == NULL) {
        !           729:                                /* Give up remote */
        !           730:                                break;
        !           731:                        }
        !           732:                        n->m_pkthdr.rcvif = NULL;
        !           733:                        n->m_len = 0;
        !           734:                        maxhlen = M_TRAILINGSPACE(n) - maxlen;
        !           735:                        if (maxhlen > hostnamelen)
        !           736:                                maxhlen = hostnamelen;
        !           737:                        /*
        !           738:                         * Copy IPv6 and ICMPv6 only.
        !           739:                         */
        !           740:                        nip6 = mtod(n, struct ip6_hdr *);
        !           741:                        bcopy(ip6, nip6, sizeof(struct ip6_hdr));
        !           742:                        nicmp6 = (struct icmp6_hdr *)(nip6 + 1);
        !           743:                        bcopy(icmp6, nicmp6, sizeof(struct icmp6_hdr));
        !           744:                        p = (u_char *)(nicmp6 + 1);
        !           745:                        bzero(p, 4);
        !           746:                        bcopy(hostname, p + 4, maxhlen); /* meaningless TTL */
        !           747:                        noff = sizeof(struct ip6_hdr);
        !           748:                        M_DUP_PKTHDR(n, m); /* just for rcvif */
        !           749:                        n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
        !           750:                                sizeof(struct icmp6_hdr) + 4 + maxhlen;
        !           751:                        nicmp6->icmp6_type = ICMP6_WRUREPLY;
        !           752:                        nicmp6->icmp6_code = 0;
        !           753:                }
        !           754: #undef hostnamelen
        !           755:                if (n) {
        !           756:                        icmp6stat.icp6s_reflect++;
        !           757:                        icmp6stat.icp6s_outhist[ICMP6_WRUREPLY]++;
        !           758:                        icmp6_reflect(n, noff);
        !           759:                }
        !           760:                break;
        !           761:            }
        !           762:
        !           763:        case ICMP6_WRUREPLY:
        !           764:                if (code != 0)
        !           765:                        goto badcode;
        !           766:                break;
        !           767:
        !           768:        case ND_ROUTER_SOLICIT:
        !           769:                icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routersolicit);
        !           770:                if (code != 0)
        !           771:                        goto badcode;
        !           772:                if (icmp6len < sizeof(struct nd_router_solicit))
        !           773:                        goto badlen;
        !           774:                if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
        !           775:                        /* give up local */
        !           776:                        nd6_rs_input(m, off, icmp6len);
        !           777:                        m = NULL;
        !           778:                        goto freeit;
        !           779:                }
        !           780:                nd6_rs_input(n, off, icmp6len);
        !           781:                /* m stays. */
        !           782:                break;
        !           783:
        !           784:        case ND_ROUTER_ADVERT:
        !           785:                icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_routeradvert);
        !           786:                if (code != 0)
        !           787:                        goto badcode;
        !           788:                if (icmp6len < sizeof(struct nd_router_advert))
        !           789:                        goto badlen;
        !           790:                if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
        !           791:                        /* give up local */
        !           792:                        nd6_ra_input(m, off, icmp6len);
        !           793:                        m = NULL;
        !           794:                        goto freeit;
        !           795:                }
        !           796:                nd6_ra_input(n, off, icmp6len);
        !           797:                /* m stays. */
        !           798:                break;
        !           799:
        !           800:        case ND_NEIGHBOR_SOLICIT:
        !           801:                icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighborsolicit);
        !           802:                if (code != 0)
        !           803:                        goto badcode;
        !           804:                if (icmp6len < sizeof(struct nd_neighbor_solicit))
        !           805:                        goto badlen;
        !           806:                if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
        !           807:                        /* give up local */
        !           808:                        nd6_ns_input(m, off, icmp6len);
        !           809:                        m = NULL;
        !           810:                        goto freeit;
        !           811:                }
        !           812:                nd6_ns_input(n, off, icmp6len);
        !           813:                /* m stays. */
        !           814:                break;
        !           815:
        !           816:        case ND_NEIGHBOR_ADVERT:
        !           817:                icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_neighboradvert);
        !           818:                if (code != 0)
        !           819:                        goto badcode;
        !           820:                if (icmp6len < sizeof(struct nd_neighbor_advert))
        !           821:                        goto badlen;
        !           822:                if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
        !           823:                        /* give up local */
        !           824:                        nd6_na_input(m, off, icmp6len);
        !           825:                        m = NULL;
        !           826:                        goto freeit;
        !           827:                }
        !           828:                nd6_na_input(n, off, icmp6len);
        !           829:                /* m stays. */
        !           830:                break;
        !           831:
        !           832:        case ND_REDIRECT:
        !           833:                icmp6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_redirect);
        !           834:                if (code != 0)
        !           835:                        goto badcode;
        !           836:                if (icmp6len < sizeof(struct nd_redirect))
        !           837:                        goto badlen;
        !           838:                if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) {
        !           839:                        /* give up local */
        !           840:                        icmp6_redirect_input(m, off);
        !           841:                        m = NULL;
        !           842:                        goto freeit;
        !           843:                }
        !           844:                icmp6_redirect_input(n, off);
        !           845:                /* m stays. */
        !           846:                break;
        !           847:
        !           848:        case ICMP6_ROUTER_RENUMBERING:
        !           849:                if (code != ICMP6_ROUTER_RENUMBERING_COMMAND &&
        !           850:                    code != ICMP6_ROUTER_RENUMBERING_RESULT)
        !           851:                        goto badcode;
        !           852:                if (icmp6len < sizeof(struct icmp6_router_renum))
        !           853:                        goto badlen;
        !           854:                break;
        !           855:
        !           856:        default:
        !           857:                nd6log((LOG_DEBUG,
        !           858:                    "icmp6_input: unknown type %d(src=%s, dst=%s, ifid=%d)\n",
        !           859:                    icmp6->icmp6_type, ip6_sprintf(&ip6->ip6_src),
        !           860:                    ip6_sprintf(&ip6->ip6_dst),
        !           861:                    m->m_pkthdr.rcvif ? m->m_pkthdr.rcvif->if_index : 0));
        !           862:                if (icmp6->icmp6_type < ICMP6_ECHO_REQUEST) {
        !           863:                        /* ICMPv6 error: MUST deliver it by spec... */
        !           864:                        code = PRC_NCMDS;
        !           865:                        /* deliver */
        !           866:                } else {
        !           867:                        /* ICMPv6 informational: MUST not deliver */
        !           868:                        break;
        !           869:                }
        !           870:        deliver:
        !           871:                if (icmp6_notify_error(m, off, icmp6len, code)) {
        !           872:                        /* In this case, m should've been freed. */
        !           873:                        return (IPPROTO_DONE);
        !           874:                }
        !           875:                break;
        !           876:
        !           877:        badcode:
        !           878:                icmp6stat.icp6s_badcode++;
        !           879:                break;
        !           880:
        !           881:        badlen:
        !           882:                icmp6stat.icp6s_badlen++;
        !           883:                break;
        !           884:        }
        !           885:
        !           886:        /* deliver the packet to appropriate sockets */
        !           887:        icmp6_rip6_input(&m, *offp);
        !           888:
        !           889:        return IPPROTO_DONE;
        !           890:
        !           891:  freeit:
        !           892:        m_freem(m);
        !           893:        return IPPROTO_DONE;
        !           894: }
        !           895:
        !           896: static int
        !           897: icmp6_notify_error(m, off, icmp6len, code)
        !           898:        struct mbuf *m;
        !           899:        int off, icmp6len, code;
        !           900: {
        !           901:        struct icmp6_hdr *icmp6;
        !           902:        struct ip6_hdr *eip6;
        !           903:        u_int32_t notifymtu;
        !           904:        struct sockaddr_in6 icmp6src, icmp6dst;
        !           905:
        !           906:        if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
        !           907:                icmp6stat.icp6s_tooshort++;
        !           908:                goto freeit;
        !           909:        }
        !           910:        IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
        !           911:                       sizeof(*icmp6) + sizeof(struct ip6_hdr));
        !           912:        if (icmp6 == NULL) {
        !           913:                icmp6stat.icp6s_tooshort++;
        !           914:                return (-1);
        !           915:        }
        !           916:        eip6 = (struct ip6_hdr *)(icmp6 + 1);
        !           917:
        !           918:        /* Detect the upper level protocol */
        !           919:        {
        !           920:                void (*ctlfunc)(int, struct sockaddr *, void *);
        !           921:                u_int8_t nxt = eip6->ip6_nxt;
        !           922:                int eoff = off + sizeof(struct icmp6_hdr) +
        !           923:                        sizeof(struct ip6_hdr);
        !           924:                struct ip6ctlparam ip6cp;
        !           925:                struct in6_addr *finaldst = NULL;
        !           926:                int icmp6type = icmp6->icmp6_type;
        !           927:                struct ip6_frag *fh;
        !           928:                struct ip6_rthdr *rth;
        !           929:                struct ip6_rthdr0 *rth0;
        !           930:                int rthlen;
        !           931:
        !           932:                while (1) { /* XXX: should avoid infinite loop explicitly? */
        !           933:                        struct ip6_ext *eh;
        !           934:
        !           935:                        switch (nxt) {
        !           936:                        case IPPROTO_HOPOPTS:
        !           937:                        case IPPROTO_DSTOPTS:
        !           938:                        case IPPROTO_AH:
        !           939:                                IP6_EXTHDR_GET(eh, struct ip6_ext *, m,
        !           940:                                               eoff, sizeof(*eh));
        !           941:                                if (eh == NULL) {
        !           942:                                        icmp6stat.icp6s_tooshort++;
        !           943:                                        return (-1);
        !           944:                                }
        !           945:
        !           946:                                if (nxt == IPPROTO_AH)
        !           947:                                        eoff += (eh->ip6e_len + 2) << 2;
        !           948:                                else
        !           949:                                        eoff += (eh->ip6e_len + 1) << 3;
        !           950:                                nxt = eh->ip6e_nxt;
        !           951:                                break;
        !           952:                        case IPPROTO_ROUTING:
        !           953:                                /*
        !           954:                                 * When the erroneous packet contains a
        !           955:                                 * routing header, we should examine the
        !           956:                                 * header to determine the final destination.
        !           957:                                 * Otherwise, we can't properly update
        !           958:                                 * information that depends on the final
        !           959:                                 * destination (e.g. path MTU).
        !           960:                                 */
        !           961:                                IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m,
        !           962:                                               eoff, sizeof(*rth));
        !           963:                                if (rth == NULL) {
        !           964:                                        icmp6stat.icp6s_tooshort++;
        !           965:                                        return (-1);
        !           966:                                }
        !           967:                                rthlen = (rth->ip6r_len + 1) << 3;
        !           968:                                /*
        !           969:                                 * XXX: currently there is no
        !           970:                                 * officially defined type other
        !           971:                                 * than type-0.
        !           972:                                 * Note that if the segment left field
        !           973:                                 * is 0, all intermediate hops must
        !           974:                                 * have been passed.
        !           975:                                 */
        !           976:                                if (rth->ip6r_segleft &&
        !           977:                                    rth->ip6r_type == IPV6_RTHDR_TYPE_0) {
        !           978:                                        int hops;
        !           979:
        !           980:                                        IP6_EXTHDR_GET(rth0,
        !           981:                                                       struct ip6_rthdr0 *, m,
        !           982:                                                       eoff, rthlen);
        !           983:                                        if (rth0 == NULL) {
        !           984:                                                icmp6stat.icp6s_tooshort++;
        !           985:                                                return (-1);
        !           986:                                        }
        !           987:                                        /* just ignore a bogus header */
        !           988:                                        if ((rth0->ip6r0_len % 2) == 0 &&
        !           989:                                            (hops = rth0->ip6r0_len/2))
        !           990:                                                finaldst = (struct in6_addr *)(rth0 + 1) + (hops - 1);
        !           991:                                }
        !           992:                                eoff += rthlen;
        !           993:                                nxt = rth->ip6r_nxt;
        !           994:                                break;
        !           995:                        case IPPROTO_FRAGMENT:
        !           996:                                IP6_EXTHDR_GET(fh, struct ip6_frag *, m,
        !           997:                                               eoff, sizeof(*fh));
        !           998:                                if (fh == NULL) {
        !           999:                                        icmp6stat.icp6s_tooshort++;
        !          1000:                                        return (-1);
        !          1001:                                }
        !          1002:                                /*
        !          1003:                                 * Data after a fragment header is meaningless
        !          1004:                                 * unless it is the first fragment, but
        !          1005:                                 * we'll go to the notify label for path MTU
        !          1006:                                 * discovery.
        !          1007:                                 */
        !          1008:                                if (fh->ip6f_offlg & IP6F_OFF_MASK)
        !          1009:                                        goto notify;
        !          1010:
        !          1011:                                eoff += sizeof(struct ip6_frag);
        !          1012:                                nxt = fh->ip6f_nxt;
        !          1013:                                break;
        !          1014:                        default:
        !          1015:                                /*
        !          1016:                                 * This case includes ESP and the No Next
        !          1017:                                 * Header.  In such cases going to the notify
        !          1018:                                 * label does not have any meaning
        !          1019:                                 * (i.e. ctlfunc will be NULL), but we go
        !          1020:                                 * anyway since we might have to update
        !          1021:                                 * path MTU information.
        !          1022:                                 */
        !          1023:                                goto notify;
        !          1024:                        }
        !          1025:                }
        !          1026:          notify:
        !          1027:                IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
        !          1028:                               sizeof(*icmp6) + sizeof(struct ip6_hdr));
        !          1029:                if (icmp6 == NULL) {
        !          1030:                        icmp6stat.icp6s_tooshort++;
        !          1031:                        return (-1);
        !          1032:                }
        !          1033:
        !          1034:                eip6 = (struct ip6_hdr *)(icmp6 + 1);
        !          1035:                bzero(&icmp6dst, sizeof(icmp6dst));
        !          1036:                icmp6dst.sin6_len = sizeof(struct sockaddr_in6);
        !          1037:                icmp6dst.sin6_family = AF_INET6;
        !          1038:                if (finaldst == NULL)
        !          1039:                        icmp6dst.sin6_addr = eip6->ip6_dst;
        !          1040:                else
        !          1041:                        icmp6dst.sin6_addr = *finaldst;
        !          1042:                icmp6dst.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
        !          1043:                                                          &icmp6dst.sin6_addr);
        !          1044:                if (in6_embedscope(&icmp6dst.sin6_addr, &icmp6dst,
        !          1045:                                   NULL, NULL)) {
        !          1046:                        /* should be impossbile */
        !          1047:                        nd6log((LOG_DEBUG,
        !          1048:                            "icmp6_notify_error: in6_embedscope failed\n"));
        !          1049:                        goto freeit;
        !          1050:                }
        !          1051:
        !          1052:                /*
        !          1053:                 * retrieve parameters from the inner IPv6 header, and convert
        !          1054:                 * them into sockaddr structures.
        !          1055:                 */
        !          1056:                bzero(&icmp6src, sizeof(icmp6src));
        !          1057:                icmp6src.sin6_len = sizeof(struct sockaddr_in6);
        !          1058:                icmp6src.sin6_family = AF_INET6;
        !          1059:                icmp6src.sin6_addr = eip6->ip6_src;
        !          1060:                icmp6src.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.rcvif,
        !          1061:                                                          &icmp6src.sin6_addr);
        !          1062:                if (in6_embedscope(&icmp6src.sin6_addr, &icmp6src,
        !          1063:                                   NULL, NULL)) {
        !          1064:                        /* should be impossbile */
        !          1065:                        nd6log((LOG_DEBUG,
        !          1066:                            "icmp6_notify_error: in6_embedscope failed\n"));
        !          1067:                        goto freeit;
        !          1068:                }
        !          1069:                icmp6src.sin6_flowinfo =
        !          1070:                    (eip6->ip6_flow & IPV6_FLOWLABEL_MASK);
        !          1071:
        !          1072:                if (finaldst == NULL)
        !          1073:                        finaldst = &eip6->ip6_dst;
        !          1074:                ip6cp.ip6c_m = m;
        !          1075:                ip6cp.ip6c_icmp6 = icmp6;
        !          1076:                ip6cp.ip6c_ip6 = (struct ip6_hdr *)(icmp6 + 1);
        !          1077:                ip6cp.ip6c_off = eoff;
        !          1078:                ip6cp.ip6c_finaldst = finaldst;
        !          1079:                ip6cp.ip6c_src = &icmp6src;
        !          1080:                ip6cp.ip6c_nxt = nxt;
        !          1081:
        !          1082:                if (icmp6type == ICMP6_PACKET_TOO_BIG) {
        !          1083:                        notifymtu = ntohl(icmp6->icmp6_mtu);
        !          1084:                        ip6cp.ip6c_cmdarg = (void *)&notifymtu;
        !          1085:                }
        !          1086:
        !          1087:                ctlfunc = (void (*)(int, struct sockaddr *, void *))
        !          1088:                        (inet6sw[ip6_protox[nxt]].pr_ctlinput);
        !          1089:                if (ctlfunc) {
        !          1090:                        (void) (*ctlfunc)(code, (struct sockaddr *)&icmp6dst,
        !          1091:                                          &ip6cp);
        !          1092:                }
        !          1093:        }
        !          1094:        return (0);
        !          1095:
        !          1096:   freeit:
        !          1097:        m_freem(m);
        !          1098:        return (-1);
        !          1099: }
        !          1100:
        !          1101: void
        !          1102: icmp6_mtudisc_update(ip6cp, validated)
        !          1103:        struct ip6ctlparam *ip6cp;
        !          1104:        int validated;
        !          1105: {
        !          1106:        unsigned long rtcount;
        !          1107:        struct icmp6_mtudisc_callback *mc;
        !          1108:        struct in6_addr *dst = ip6cp->ip6c_finaldst;
        !          1109:        struct icmp6_hdr *icmp6 = ip6cp->ip6c_icmp6;
        !          1110:        struct mbuf *m = ip6cp->ip6c_m; /* will be necessary for scope issue */
        !          1111:        u_int mtu = ntohl(icmp6->icmp6_mtu);
        !          1112:        struct rtentry *rt = NULL;
        !          1113:        struct sockaddr_in6 sin6;
        !          1114:
        !          1115:        /*
        !          1116:         * allow non-validated cases if memory is plenty, to make traffic
        !          1117:         * from non-connected pcb happy.
        !          1118:         */
        !          1119:        rtcount = rt_timer_count(icmp6_mtudisc_timeout_q);
        !          1120:        if (validated) {
        !          1121:                if (0 <= icmp6_mtudisc_hiwat && rtcount > icmp6_mtudisc_hiwat)
        !          1122:                        return;
        !          1123:                else if (0 <= icmp6_mtudisc_lowat &&
        !          1124:                    rtcount > icmp6_mtudisc_lowat) {
        !          1125:                        /*
        !          1126:                         * XXX nuke a victim, install the new one.
        !          1127:                         */
        !          1128:                }
        !          1129:        } else {
        !          1130:                if (0 <= icmp6_mtudisc_lowat && rtcount > icmp6_mtudisc_lowat)
        !          1131:                        return;
        !          1132:        }
        !          1133:
        !          1134:        bzero(&sin6, sizeof(sin6));
        !          1135:        sin6.sin6_family = PF_INET6;
        !          1136:        sin6.sin6_len = sizeof(struct sockaddr_in6);
        !          1137:        sin6.sin6_addr = *dst;
        !          1138:        /* XXX normally, this won't happen */
        !          1139:        if (IN6_IS_ADDR_LINKLOCAL(dst)) {
        !          1140:                sin6.sin6_addr.s6_addr16[1] =
        !          1141:                    htons(m->m_pkthdr.rcvif->if_index);
        !          1142:        }
        !          1143:        /* sin6.sin6_scope_id = XXX: should be set if DST is a scoped addr */
        !          1144:        rt = icmp6_mtudisc_clone((struct sockaddr *)&sin6);
        !          1145:
        !          1146:        if (rt && (rt->rt_flags & RTF_HOST) &&
        !          1147:            !(rt->rt_rmx.rmx_locks & RTV_MTU) &&
        !          1148:            (rt->rt_rmx.rmx_mtu > mtu || rt->rt_rmx.rmx_mtu == 0)) {
        !          1149:                if (mtu < IN6_LINKMTU(rt->rt_ifp)) {
        !          1150:                        icmp6stat.icp6s_pmtuchg++;
        !          1151:                        rt->rt_rmx.rmx_mtu = mtu;
        !          1152:                }
        !          1153:        }
        !          1154:        if (rt) { /* XXX: need braces to avoid conflict with else in RTFREE. */
        !          1155:                RTFREE(rt);
        !          1156:        }
        !          1157:
        !          1158:        /*
        !          1159:         * Notify protocols that the MTU for this destination
        !          1160:         * has changed.
        !          1161:         */
        !          1162:        for (mc = LIST_FIRST(&icmp6_mtudisc_callbacks); mc != NULL;
        !          1163:             mc = LIST_NEXT(mc, mc_list))
        !          1164:                (*mc->mc_func)(&sin6.sin6_addr);
        !          1165: }
        !          1166:
        !          1167: /*
        !          1168:  * Process a Node Information Query packet, based on
        !          1169:  * draft-ietf-ipngwg-icmp-name-lookups-07.
        !          1170:  *
        !          1171:  * Spec incompatibilities:
        !          1172:  * - IPv6 Subject address handling
        !          1173:  * - IPv4 Subject address handling support missing
        !          1174:  * - Proxy reply (answer even if it's not for me)
        !          1175:  * - joins NI group address at in6_ifattach() time only, does not cope
        !          1176:  *   with hostname changes by sethostname(3)
        !          1177:  */
        !          1178: #ifndef offsetof               /* XXX */
        !          1179: #define        offsetof(type, member)  ((size_t)(&((type *)0)->member))
        !          1180: #endif
        !          1181: static struct mbuf *
        !          1182: ni6_input(m, off)
        !          1183:        struct mbuf *m;
        !          1184:        int off;
        !          1185: {
        !          1186:        struct icmp6_nodeinfo *ni6, *nni6;
        !          1187:        struct mbuf *n = NULL;
        !          1188:        u_int16_t qtype;
        !          1189:        int subjlen;
        !          1190:        int replylen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo);
        !          1191:        struct ni_reply_fqdn *fqdn;
        !          1192:        int addrs;              /* for NI_QTYPE_NODEADDR */
        !          1193:        struct ifnet *ifp = NULL; /* for NI_QTYPE_NODEADDR */
        !          1194:        struct sockaddr_in6 sin6; /* double meaning; ip6_dst and subjectaddr */
        !          1195:        struct ip6_hdr *ip6;
        !          1196:        int oldfqdn = 0;        /* if 1, return pascal string (03 draft) */
        !          1197:        char *subj = NULL;
        !          1198:
        !          1199:        ip6 = mtod(m, struct ip6_hdr *);
        !          1200:        IP6_EXTHDR_GET(ni6, struct icmp6_nodeinfo *, m, off, sizeof(*ni6));
        !          1201:        if (ni6 == NULL) {
        !          1202:                /* m is already reclaimed */
        !          1203:                return NULL;
        !          1204:        }
        !          1205:
        !          1206:        /*
        !          1207:         * Validate IPv6 destination address.
        !          1208:         *
        !          1209:         * The Responder must discard the Query without further processing
        !          1210:         * unless it is one of the Responder's unicast or anycast addresses, or
        !          1211:         * a link-local scope multicast address which the Responder has joined.
        !          1212:         * [icmp-name-lookups-07, Section 4.]
        !          1213:         */
        !          1214:        bzero(&sin6, sizeof(sin6));
        !          1215:        sin6.sin6_family = AF_INET6;
        !          1216:        sin6.sin6_len = sizeof(struct sockaddr_in6);
        !          1217:        bcopy(&ip6->ip6_dst, &sin6.sin6_addr, sizeof(sin6.sin6_addr));
        !          1218:        /* XXX scopeid */
        !          1219:        if (ifa_ifwithaddr((struct sockaddr *)&sin6))
        !          1220:                ; /* unicast/anycast, fine */
        !          1221:        else if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr))
        !          1222:                ; /* link-local multicast, fine */
        !          1223:        else
        !          1224:                goto bad;
        !          1225:
        !          1226:        /* validate query Subject field. */
        !          1227:        qtype = ntohs(ni6->ni_qtype);
        !          1228:        subjlen = m->m_pkthdr.len - off - sizeof(struct icmp6_nodeinfo);
        !          1229:        switch (qtype) {
        !          1230:        case NI_QTYPE_NOOP:
        !          1231:        case NI_QTYPE_SUPTYPES:
        !          1232:                /* 07 draft */
        !          1233:                if (ni6->ni_code == ICMP6_NI_SUBJ_FQDN && subjlen == 0)
        !          1234:                        break;
        !          1235:                /* FALLTHROUGH */
        !          1236:        case NI_QTYPE_FQDN:
        !          1237:        case NI_QTYPE_NODEADDR:
        !          1238:                switch (ni6->ni_code) {
        !          1239:                case ICMP6_NI_SUBJ_IPV6:
        !          1240: #if ICMP6_NI_SUBJ_IPV6 != 0
        !          1241:                case 0:
        !          1242: #endif
        !          1243:                        /*
        !          1244:                         * backward compatibility - try to accept 03 draft
        !          1245:                         * format, where no Subject is present.
        !          1246:                         */
        !          1247:                        if (qtype == NI_QTYPE_FQDN && ni6->ni_code == 0 &&
        !          1248:                            subjlen == 0) {
        !          1249:                                oldfqdn++;
        !          1250:                                break;
        !          1251:                        }
        !          1252: #if ICMP6_NI_SUBJ_IPV6 != 0
        !          1253:                        if (ni6->ni_code != ICMP6_NI_SUBJ_IPV6)
        !          1254:                                goto bad;
        !          1255: #endif
        !          1256:
        !          1257:                        if (subjlen != sizeof(sin6.sin6_addr))
        !          1258:                                goto bad;
        !          1259:
        !          1260:                        /*
        !          1261:                         * Validate Subject address.
        !          1262:                         *
        !          1263:                         * Not sure what exactly "address belongs to the node"
        !          1264:                         * means in the spec, is it just unicast, or what?
        !          1265:                         *
        !          1266:                         * At this moment we consider Subject address as
        !          1267:                         * "belong to the node" if the Subject address equals
        !          1268:                         * to the IPv6 destination address; validation for
        !          1269:                         * IPv6 destination address should have done enough
        !          1270:                         * check for us.
        !          1271:                         *
        !          1272:                         * We do not do proxy at this moment.
        !          1273:                         */
        !          1274:                        /* m_pulldown instead of copy? */
        !          1275:                        m_copydata(m, off + sizeof(struct icmp6_nodeinfo),
        !          1276:                            subjlen, (caddr_t)&sin6.sin6_addr);
        !          1277:                        /* XXX kame scope hack */
        !          1278:                        if (IN6_IS_SCOPE_EMBED(&sin6.sin6_addr)) {
        !          1279:                                if ((m->m_flags & M_PKTHDR) != 0 &&
        !          1280:                                    m->m_pkthdr.rcvif) {
        !          1281:                                        sin6.sin6_addr.s6_addr16[1] =
        !          1282:                                            htons(m->m_pkthdr.rcvif->if_index);
        !          1283:                                }
        !          1284:                        }
        !          1285:                        subj = (char *)&sin6;
        !          1286:                        if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &sin6.sin6_addr))
        !          1287:                                break;
        !          1288:
        !          1289:                        /*
        !          1290:                         * XXX if we are to allow other cases, we should really
        !          1291:                         * be careful about scope here.
        !          1292:                         * basically, we should disallow queries toward IPv6
        !          1293:                         * destination X with subject Y, if scope(X) > scope(Y).
        !          1294:                         * if we allow scope(X) > scope(Y), it will result in
        !          1295:                         * information leakage across scope boundary.
        !          1296:                         */
        !          1297:                        goto bad;
        !          1298:
        !          1299:                case ICMP6_NI_SUBJ_FQDN:
        !          1300:                        /*
        !          1301:                         * Validate Subject name with gethostname(3).
        !          1302:                         *
        !          1303:                         * The behavior may need some debate, since:
        !          1304:                         * - we are not sure if the node has FQDN as
        !          1305:                         *   hostname (returned by gethostname(3)).
        !          1306:                         * - the code does wildcard match for truncated names.
        !          1307:                         *   however, we are not sure if we want to perform
        !          1308:                         *   wildcard match, if gethostname(3) side has
        !          1309:                         *   truncated hostname.
        !          1310:                         */
        !          1311:                        n = ni6_nametodns(hostname, hostnamelen, 0);
        !          1312:                        if (!n || n->m_next || n->m_len == 0)
        !          1313:                                goto bad;
        !          1314:                        IP6_EXTHDR_GET(subj, char *, m,
        !          1315:                            off + sizeof(struct icmp6_nodeinfo), subjlen);
        !          1316:                        if (subj == NULL)
        !          1317:                                goto bad;
        !          1318:                        if (!ni6_dnsmatch(subj, subjlen, mtod(n, const char *),
        !          1319:                                        n->m_len)) {
        !          1320:                                goto bad;
        !          1321:                        }
        !          1322:                        m_freem(n);
        !          1323:                        n = NULL;
        !          1324:                        break;
        !          1325:
        !          1326:                case ICMP6_NI_SUBJ_IPV4:        /* XXX: to be implemented? */
        !          1327:                default:
        !          1328:                        goto bad;
        !          1329:                }
        !          1330:                break;
        !          1331:        }
        !          1332:
        !          1333:        /* refuse based on configuration.  XXX ICMP6_NI_REFUSED? */
        !          1334:        switch (qtype) {
        !          1335:        case NI_QTYPE_FQDN:
        !          1336:                if ((icmp6_nodeinfo & 1) == 0)
        !          1337:                        goto bad;
        !          1338:                break;
        !          1339:        case NI_QTYPE_NODEADDR:
        !          1340:                if ((icmp6_nodeinfo & 2) == 0)
        !          1341:                        goto bad;
        !          1342:                break;
        !          1343:        }
        !          1344:
        !          1345:        /* guess reply length */
        !          1346:        switch (qtype) {
        !          1347:        case NI_QTYPE_NOOP:
        !          1348:                break;          /* no reply data */
        !          1349:        case NI_QTYPE_SUPTYPES:
        !          1350:                replylen += sizeof(u_int32_t);
        !          1351:                break;
        !          1352:        case NI_QTYPE_FQDN:
        !          1353:                /* XXX will append an mbuf */
        !          1354:                replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
        !          1355:                break;
        !          1356:        case NI_QTYPE_NODEADDR:
        !          1357:                addrs = ni6_addrs(ni6, m, &ifp, subj);
        !          1358:                if ((replylen += addrs * (sizeof(struct in6_addr) +
        !          1359:                                          sizeof(u_int32_t))) > MCLBYTES)
        !          1360:                        replylen = MCLBYTES; /* XXX: will truncate pkt later */
        !          1361:                break;
        !          1362:        default:
        !          1363:                /*
        !          1364:                 * XXX: We must return a reply with the ICMP6 code
        !          1365:                 * `unknown Qtype' in this case.  However we regard the case
        !          1366:                 * as an FQDN query for backward compatibility.
        !          1367:                 * Older versions set a random value to this field,
        !          1368:                 * so it rarely varies in the defined qtypes.
        !          1369:                 * But the mechanism is not reliable...
        !          1370:                 * maybe we should obsolete older versions.
        !          1371:                 */
        !          1372:                qtype = NI_QTYPE_FQDN;
        !          1373:                /* XXX will append an mbuf */
        !          1374:                replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
        !          1375:                oldfqdn++;
        !          1376:                break;
        !          1377:        }
        !          1378:
        !          1379:        /* allocate an mbuf to reply. */
        !          1380:        MGETHDR(n, M_DONTWAIT, m->m_type);
        !          1381:        if (n == NULL) {
        !          1382:                m_freem(m);
        !          1383:                return (NULL);
        !          1384:        }
        !          1385:        M_DUP_PKTHDR(n, m); /* just for rcvif */
        !          1386:        if (replylen > MHLEN) {
        !          1387:                if (replylen > MCLBYTES) {
        !          1388:                        /*
        !          1389:                         * XXX: should we try to allocate more? But MCLBYTES
        !          1390:                         * is probably much larger than IPV6_MMTU...
        !          1391:                         */
        !          1392:                        goto bad;
        !          1393:                }
        !          1394:                MCLGET(n, M_DONTWAIT);
        !          1395:                if ((n->m_flags & M_EXT) == 0) {
        !          1396:                        goto bad;
        !          1397:                }
        !          1398:        }
        !          1399:        n->m_pkthdr.len = n->m_len = replylen;
        !          1400:
        !          1401:        /* copy mbuf header and IPv6 + Node Information base headers */
        !          1402:        bcopy(mtod(m, caddr_t), mtod(n, caddr_t), sizeof(struct ip6_hdr));
        !          1403:        nni6 = (struct icmp6_nodeinfo *)(mtod(n, struct ip6_hdr *) + 1);
        !          1404:        bcopy((caddr_t)ni6, (caddr_t)nni6, sizeof(struct icmp6_nodeinfo));
        !          1405:
        !          1406:        /* qtype dependent procedure */
        !          1407:        switch (qtype) {
        !          1408:        case NI_QTYPE_NOOP:
        !          1409:                nni6->ni_code = ICMP6_NI_SUCCESS;
        !          1410:                nni6->ni_flags = 0;
        !          1411:                break;
        !          1412:        case NI_QTYPE_SUPTYPES:
        !          1413:        {
        !          1414:                u_int32_t v;
        !          1415:                nni6->ni_code = ICMP6_NI_SUCCESS;
        !          1416:                nni6->ni_flags = htons(0x0000); /* raw bitmap */
        !          1417:                /* supports NOOP, SUPTYPES, FQDN, and NODEADDR */
        !          1418:                v = (u_int32_t)htonl(0x0000000f);
        !          1419:                bcopy(&v, nni6 + 1, sizeof(u_int32_t));
        !          1420:                break;
        !          1421:        }
        !          1422:        case NI_QTYPE_FQDN:
        !          1423:                nni6->ni_code = ICMP6_NI_SUCCESS;
        !          1424:                fqdn = (struct ni_reply_fqdn *)(mtod(n, caddr_t) +
        !          1425:                                                sizeof(struct ip6_hdr) +
        !          1426:                                                sizeof(struct icmp6_nodeinfo));
        !          1427:                nni6->ni_flags = 0; /* XXX: meaningless TTL */
        !          1428:                fqdn->ni_fqdn_ttl = 0;  /* ditto. */
        !          1429:                /*
        !          1430:                 * XXX do we really have FQDN in variable "hostname"?
        !          1431:                 */
        !          1432:                n->m_next = ni6_nametodns(hostname, hostnamelen, oldfqdn);
        !          1433:                if (n->m_next == NULL)
        !          1434:                        goto bad;
        !          1435:                /* XXX we assume that n->m_next is not a chain */
        !          1436:                if (n->m_next->m_next != NULL)
        !          1437:                        goto bad;
        !          1438:                n->m_pkthdr.len += n->m_next->m_len;
        !          1439:                break;
        !          1440:        case NI_QTYPE_NODEADDR:
        !          1441:        {
        !          1442:                int lenlim, copied;
        !          1443:
        !          1444:                nni6->ni_code = ICMP6_NI_SUCCESS;
        !          1445:                n->m_pkthdr.len = n->m_len =
        !          1446:                    sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo);
        !          1447:                lenlim = M_TRAILINGSPACE(n);
        !          1448:                copied = ni6_store_addrs(ni6, nni6, ifp, lenlim);
        !          1449:                /* XXX: reset mbuf length */
        !          1450:                n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
        !          1451:                        sizeof(struct icmp6_nodeinfo) + copied;
        !          1452:                break;
        !          1453:        }
        !          1454:        default:
        !          1455:                break;          /* XXX impossible! */
        !          1456:        }
        !          1457:
        !          1458:        nni6->ni_type = ICMP6_NI_REPLY;
        !          1459:        m_freem(m);
        !          1460:        return (n);
        !          1461:
        !          1462:   bad:
        !          1463:        m_freem(m);
        !          1464:        if (n)
        !          1465:                m_freem(n);
        !          1466:        return (NULL);
        !          1467: }
        !          1468: #undef hostnamelen
        !          1469:
        !          1470: #define isupper(x) ('A' <= (x) && (x) <= 'Z')
        !          1471: #define isalpha(x) (('A' <= (x) && (x) <= 'Z') || ('a' <= (x) && (x) <= 'z'))
        !          1472: #define isalnum(x) (isalpha(x) || ('0' <= (x) && (x) <= '9'))
        !          1473: #define tolower(x) (isupper(x) ? (x) + 'a' - 'A' : (x))
        !          1474:
        !          1475: /*
        !          1476:  * make a mbuf with DNS-encoded string.  no compression support.
        !          1477:  *
        !          1478:  * XXX names with less than 2 dots (like "foo" or "foo.section") will be
        !          1479:  * treated as truncated name (two \0 at the end).  this is a wild guess.
        !          1480:  */
        !          1481: static struct mbuf *
        !          1482: ni6_nametodns(name, namelen, old)
        !          1483:        const char *name;
        !          1484:        int namelen;
        !          1485:        int old;        /* return pascal string if non-zero */
        !          1486: {
        !          1487:        struct mbuf *m;
        !          1488:        char *cp, *ep;
        !          1489:        const char *p, *q;
        !          1490:        int i, len, nterm;
        !          1491:
        !          1492:        if (old)
        !          1493:                len = namelen + 1;
        !          1494:        else
        !          1495:                len = MCLBYTES;
        !          1496:
        !          1497:        /* because MAXHOSTNAMELEN is usually 256, we use cluster mbuf */
        !          1498:        MGET(m, M_DONTWAIT, MT_DATA);
        !          1499:        if (m && len > MLEN) {
        !          1500:                MCLGET(m, M_DONTWAIT);
        !          1501:                if ((m->m_flags & M_EXT) == 0)
        !          1502:                        goto fail;
        !          1503:        }
        !          1504:        if (!m)
        !          1505:                goto fail;
        !          1506:        m->m_next = NULL;
        !          1507:
        !          1508:        if (old) {
        !          1509:                m->m_len = len;
        !          1510:                *mtod(m, char *) = namelen;
        !          1511:                bcopy(name, mtod(m, char *) + 1, namelen);
        !          1512:                return m;
        !          1513:        } else {
        !          1514:                m->m_len = 0;
        !          1515:                cp = mtod(m, char *);
        !          1516:                ep = mtod(m, char *) + M_TRAILINGSPACE(m);
        !          1517:
        !          1518:                /* if not certain about my name, return empty buffer */
        !          1519:                if (namelen == 0)
        !          1520:                        return m;
        !          1521:
        !          1522:                /*
        !          1523:                 * guess if it looks like shortened hostname, or FQDN.
        !          1524:                 * shortened hostname needs two trailing "\0".
        !          1525:                 */
        !          1526:                i = 0;
        !          1527:                for (p = name; p < name + namelen; p++) {
        !          1528:                        if (*p && *p == '.')
        !          1529:                                i++;
        !          1530:                }
        !          1531:                if (i < 2)
        !          1532:                        nterm = 2;
        !          1533:                else
        !          1534:                        nterm = 1;
        !          1535:
        !          1536:                p = name;
        !          1537:                while (cp < ep && p < name + namelen) {
        !          1538:                        i = 0;
        !          1539:                        for (q = p; q < name + namelen && *q && *q != '.'; q++)
        !          1540:                                i++;
        !          1541:                        /* result does not fit into mbuf */
        !          1542:                        if (cp + i + 1 >= ep)
        !          1543:                                goto fail;
        !          1544:                        /*
        !          1545:                         * DNS label length restriction, RFC1035 page 8.
        !          1546:                         * "i == 0" case is included here to avoid returning
        !          1547:                         * 0-length label on "foo..bar".
        !          1548:                         */
        !          1549:                        if (i <= 0 || i >= 64)
        !          1550:                                goto fail;
        !          1551:                        *cp++ = i;
        !          1552:                        if (!isalpha(p[0]) || !isalnum(p[i - 1]))
        !          1553:                                goto fail;
        !          1554:                        while (i > 0) {
        !          1555:                                if (!isalnum(*p) && *p != '-')
        !          1556:                                        goto fail;
        !          1557:                                if (isupper(*p)) {
        !          1558:                                        *cp++ = tolower(*p);
        !          1559:                                        p++;
        !          1560:                                } else
        !          1561:                                        *cp++ = *p++;
        !          1562:                                i--;
        !          1563:                        }
        !          1564:                        p = q;
        !          1565:                        if (p < name + namelen && *p == '.')
        !          1566:                                p++;
        !          1567:                }
        !          1568:                /* termination */
        !          1569:                if (cp + nterm >= ep)
        !          1570:                        goto fail;
        !          1571:                while (nterm-- > 0)
        !          1572:                        *cp++ = '\0';
        !          1573:                m->m_len = cp - mtod(m, char *);
        !          1574:                return m;
        !          1575:        }
        !          1576:
        !          1577:        panic("should not reach here");
        !          1578:        /* NOTREACHED */
        !          1579:
        !          1580:  fail:
        !          1581:        if (m)
        !          1582:                m_freem(m);
        !          1583:        return NULL;
        !          1584: }
        !          1585:
        !          1586: /*
        !          1587:  * check if two DNS-encoded string matches.  takes care of truncated
        !          1588:  * form (with \0\0 at the end).  no compression support.
        !          1589:  * XXX upper/lowercase match (see RFC2065)
        !          1590:  */
        !          1591: static int
        !          1592: ni6_dnsmatch(a, alen, b, blen)
        !          1593:        const char *a;
        !          1594:        int alen;
        !          1595:        const char *b;
        !          1596:        int blen;
        !          1597: {
        !          1598:        const char *a0, *b0;
        !          1599:        int l;
        !          1600:
        !          1601:        /* simplest case - need validation? */
        !          1602:        if (alen == blen && bcmp(a, b, alen) == 0)
        !          1603:                return 1;
        !          1604:
        !          1605:        a0 = a;
        !          1606:        b0 = b;
        !          1607:
        !          1608:        /* termination is mandatory */
        !          1609:        if (alen < 2 || blen < 2)
        !          1610:                return 0;
        !          1611:        if (a0[alen - 1] != '\0' || b0[blen - 1] != '\0')
        !          1612:                return 0;
        !          1613:        alen--;
        !          1614:        blen--;
        !          1615:
        !          1616:        while (a - a0 < alen && b - b0 < blen) {
        !          1617:                if (a - a0 + 1 > alen || b - b0 + 1 > blen)
        !          1618:                        return 0;
        !          1619:
        !          1620:                if ((signed char)a[0] < 0 || (signed char)b[0] < 0)
        !          1621:                        return 0;
        !          1622:                /* we don't support compression yet */
        !          1623:                if (a[0] >= 64 || b[0] >= 64)
        !          1624:                        return 0;
        !          1625:
        !          1626:                /* truncated case */
        !          1627:                if (a[0] == 0 && a - a0 == alen - 1)
        !          1628:                        return 1;
        !          1629:                if (b[0] == 0 && b - b0 == blen - 1)
        !          1630:                        return 1;
        !          1631:                if (a[0] == 0 || b[0] == 0)
        !          1632:                        return 0;
        !          1633:
        !          1634:                if (a[0] != b[0])
        !          1635:                        return 0;
        !          1636:                l = a[0];
        !          1637:                if (a - a0 + 1 + l > alen || b - b0 + 1 + l > blen)
        !          1638:                        return 0;
        !          1639:                if (bcmp(a + 1, b + 1, l) != 0)
        !          1640:                        return 0;
        !          1641:
        !          1642:                a += 1 + l;
        !          1643:                b += 1 + l;
        !          1644:        }
        !          1645:
        !          1646:        if (a - a0 == alen && b - b0 == blen)
        !          1647:                return 1;
        !          1648:        else
        !          1649:                return 0;
        !          1650: }
        !          1651:
        !          1652: /*
        !          1653:  * calculate the number of addresses to be returned in the node info reply.
        !          1654:  */
        !          1655: static int
        !          1656: ni6_addrs(ni6, m, ifpp, subj)
        !          1657:        struct icmp6_nodeinfo *ni6;
        !          1658:        struct mbuf *m;
        !          1659:        struct ifnet **ifpp;
        !          1660:        char *subj;
        !          1661: {
        !          1662:        struct ifnet *ifp;
        !          1663:        struct in6_ifaddr *ifa6;
        !          1664:        struct ifaddr *ifa;
        !          1665:        struct sockaddr_in6 *subj_ip6 = NULL; /* XXX pedant */
        !          1666:        int addrs = 0, addrsofif, iffound = 0;
        !          1667:        int niflags = ni6->ni_flags;
        !          1668:
        !          1669:        if ((niflags & NI_NODEADDR_FLAG_ALL) == 0) {
        !          1670:                switch (ni6->ni_code) {
        !          1671:                case ICMP6_NI_SUBJ_IPV6:
        !          1672:                        if (subj == NULL) /* must be impossible... */
        !          1673:                                return (0);
        !          1674:                        subj_ip6 = (struct sockaddr_in6 *)subj;
        !          1675:                        break;
        !          1676:                default:
        !          1677:                        /*
        !          1678:                         * XXX: we only support IPv6 subject address for
        !          1679:                         * this Qtype.
        !          1680:                         */
        !          1681:                        return (0);
        !          1682:                }
        !          1683:        }
        !          1684:
        !          1685:        TAILQ_FOREACH(ifp, &ifnet, if_list) {
        !          1686:                addrsofif = 0;
        !          1687:                TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
        !          1688:                        if (ifa->ifa_addr->sa_family != AF_INET6)
        !          1689:                                continue;
        !          1690:                        ifa6 = (struct in6_ifaddr *)ifa;
        !          1691:
        !          1692:                        if ((niflags & NI_NODEADDR_FLAG_ALL) == 0 &&
        !          1693:                            IN6_ARE_ADDR_EQUAL(&subj_ip6->sin6_addr,
        !          1694:                                               &ifa6->ia_addr.sin6_addr))
        !          1695:                                iffound = 1;
        !          1696:
        !          1697:                        /*
        !          1698:                         * IPv4-mapped addresses can only be returned by a
        !          1699:                         * Node Information proxy, since they represent
        !          1700:                         * addresses of IPv4-only nodes, which perforce do
        !          1701:                         * not implement this protocol.
        !          1702:                         * [icmp-name-lookups-07, Section 5.4]
        !          1703:                         * So we don't support NI_NODEADDR_FLAG_COMPAT in
        !          1704:                         * this function at this moment.
        !          1705:                         */
        !          1706:
        !          1707:                        /* What do we have to do about ::1? */
        !          1708:                        switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
        !          1709:                        case IPV6_ADDR_SCOPE_LINKLOCAL:
        !          1710:                                if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0)
        !          1711:                                        continue;
        !          1712:                                break;
        !          1713:                        case IPV6_ADDR_SCOPE_SITELOCAL:
        !          1714:                                if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0)
        !          1715:                                        continue;
        !          1716:                                break;
        !          1717:                        case IPV6_ADDR_SCOPE_GLOBAL:
        !          1718:                                if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0)
        !          1719:                                        continue;
        !          1720:                                break;
        !          1721:                        default:
        !          1722:                                continue;
        !          1723:                        }
        !          1724:
        !          1725:                        /*
        !          1726:                         * check if anycast is okay.
        !          1727:                         * XXX: just experimental.  not in the spec.
        !          1728:                         */
        !          1729:                        if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 &&
        !          1730:                            (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0)
        !          1731:                                continue; /* we need only unicast addresses */
        !          1732:
        !          1733:                        addrsofif++; /* count the address */
        !          1734:                }
        !          1735:                if (iffound) {
        !          1736:                        *ifpp = ifp;
        !          1737:                        return (addrsofif);
        !          1738:                }
        !          1739:
        !          1740:                addrs += addrsofif;
        !          1741:        }
        !          1742:
        !          1743:        return (addrs);
        !          1744: }
        !          1745:
        !          1746: static int
        !          1747: ni6_store_addrs(ni6, nni6, ifp0, resid)
        !          1748:        struct icmp6_nodeinfo *ni6, *nni6;
        !          1749:        struct ifnet *ifp0;
        !          1750:        int resid;
        !          1751: {
        !          1752:        struct ifnet *ifp = ifp0 ? ifp0 : TAILQ_FIRST(&ifnet);
        !          1753:        struct in6_ifaddr *ifa6;
        !          1754:        struct ifaddr *ifa;
        !          1755:        struct ifnet *ifp_dep = NULL;
        !          1756:        int copied = 0, allow_deprecated = 0;
        !          1757:        u_char *cp = (u_char *)(nni6 + 1);
        !          1758:        int niflags = ni6->ni_flags;
        !          1759:        u_int32_t ltime;
        !          1760:
        !          1761:        if (ifp0 == NULL && !(niflags & NI_NODEADDR_FLAG_ALL))
        !          1762:                return (0);     /* needless to copy */
        !          1763:
        !          1764:   again:
        !          1765:
        !          1766:        for (; ifp != TAILQ_END(&ifnet); ifp = TAILQ_NEXT(ifp, if_list)) {
        !          1767:                TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
        !          1768:                        if (ifa->ifa_addr->sa_family != AF_INET6)
        !          1769:                                continue;
        !          1770:                        ifa6 = (struct in6_ifaddr *)ifa;
        !          1771:
        !          1772:                        if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) != 0 &&
        !          1773:                            allow_deprecated == 0) {
        !          1774:                                /*
        !          1775:                                 * prefererred address should be put before
        !          1776:                                 * deprecated addresses.
        !          1777:                                 */
        !          1778:
        !          1779:                                /* record the interface for later search */
        !          1780:                                if (ifp_dep == NULL)
        !          1781:                                        ifp_dep = ifp;
        !          1782:
        !          1783:                                continue;
        !          1784:                        }
        !          1785:                        else if ((ifa6->ia6_flags & IN6_IFF_DEPRECATED) == 0 &&
        !          1786:                                 allow_deprecated != 0)
        !          1787:                                continue; /* we now collect deprecated addrs */
        !          1788:
        !          1789:                        /* What do we have to do about ::1? */
        !          1790:                        switch (in6_addrscope(&ifa6->ia_addr.sin6_addr)) {
        !          1791:                        case IPV6_ADDR_SCOPE_LINKLOCAL:
        !          1792:                                if ((niflags & NI_NODEADDR_FLAG_LINKLOCAL) == 0)
        !          1793:                                        continue;
        !          1794:                                break;
        !          1795:                        case IPV6_ADDR_SCOPE_SITELOCAL:
        !          1796:                                if ((niflags & NI_NODEADDR_FLAG_SITELOCAL) == 0)
        !          1797:                                        continue;
        !          1798:                                break;
        !          1799:                        case IPV6_ADDR_SCOPE_GLOBAL:
        !          1800:                                if ((niflags & NI_NODEADDR_FLAG_GLOBAL) == 0)
        !          1801:                                        continue;
        !          1802:                                break;
        !          1803:                        default:
        !          1804:                                continue;
        !          1805:                        }
        !          1806:
        !          1807:                        /*
        !          1808:                         * check if anycast is okay.
        !          1809:                         * XXX: just experimental.  not in the spec.
        !          1810:                         */
        !          1811:                        if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0 &&
        !          1812:                            (niflags & NI_NODEADDR_FLAG_ANYCAST) == 0)
        !          1813:                                continue;
        !          1814:
        !          1815:                        /* now we can copy the address */
        !          1816:                        if (resid < sizeof(struct in6_addr) +
        !          1817:                            sizeof(u_int32_t)) {
        !          1818:                                /*
        !          1819:                                 * We give up much more copy.
        !          1820:                                 * Set the truncate flag and return.
        !          1821:                                 */
        !          1822:                                nni6->ni_flags |=
        !          1823:                                        NI_NODEADDR_FLAG_TRUNCATE;
        !          1824:                                return (copied);
        !          1825:                        }
        !          1826:
        !          1827:                        /*
        !          1828:                         * Set the TTL of the address.
        !          1829:                         * The TTL value should be one of the following
        !          1830:                         * according to the specification:
        !          1831:                         *
        !          1832:                         * 1. The remaining lifetime of a DHCP lease on the
        !          1833:                         *    address, or
        !          1834:                         * 2. The remaining Valid Lifetime of a prefix from
        !          1835:                         *    which the address was derived through Stateless
        !          1836:                         *    Autoconfiguration.
        !          1837:                         *
        !          1838:                         * Note that we currently do not support stateful
        !          1839:                         * address configuration by DHCPv6, so the former
        !          1840:                         * case can't happen.
        !          1841:                         *
        !          1842:                         * TTL must be 2^31 > TTL >= 0.
        !          1843:                         */
        !          1844:                        if (ifa6->ia6_lifetime.ia6t_expire == 0)
        !          1845:                                ltime = ND6_INFINITE_LIFETIME;
        !          1846:                        else {
        !          1847:                                if (ifa6->ia6_lifetime.ia6t_expire >
        !          1848:                                    time_second)
        !          1849:                                        ltime = htonl(ifa6->ia6_lifetime.ia6t_expire - time_second);
        !          1850:                                else
        !          1851:                                        ltime = 0;
        !          1852:                        }
        !          1853:
        !          1854:                        bcopy(&ltime, cp, sizeof(u_int32_t));
        !          1855:                        cp += sizeof(u_int32_t);
        !          1856:
        !          1857:                        /* copy the address itself */
        !          1858:                        bcopy(&ifa6->ia_addr.sin6_addr, cp,
        !          1859:                              sizeof(struct in6_addr));
        !          1860:                        /* XXX: KAME link-local hack; remove ifindex */
        !          1861:                        if (IN6_IS_ADDR_LINKLOCAL(&ifa6->ia_addr.sin6_addr))
        !          1862:                                ((struct in6_addr *)cp)->s6_addr16[1] = 0;
        !          1863:                        cp += sizeof(struct in6_addr);
        !          1864:
        !          1865:                        resid -= (sizeof(struct in6_addr) + sizeof(u_int32_t));
        !          1866:                        copied += (sizeof(struct in6_addr) +
        !          1867:                                   sizeof(u_int32_t));
        !          1868:                }
        !          1869:                if (ifp0)       /* we need search only on the specified IF */
        !          1870:                        break;
        !          1871:        }
        !          1872:
        !          1873:        if (allow_deprecated == 0 && ifp_dep != NULL) {
        !          1874:                ifp = ifp_dep;
        !          1875:                allow_deprecated = 1;
        !          1876:
        !          1877:                goto again;
        !          1878:        }
        !          1879:
        !          1880:        return (copied);
        !          1881: }
        !          1882:
        !          1883: /*
        !          1884:  * XXX almost dup'ed code with rip6_input.
        !          1885:  */
        !          1886: static int
        !          1887: icmp6_rip6_input(mp, off)
        !          1888:        struct  mbuf **mp;
        !          1889:        int     off;
        !          1890: {
        !          1891:        struct mbuf *m = *mp;
        !          1892:        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
        !          1893:        struct in6pcb *in6p;
        !          1894:        struct in6pcb *last = NULL;
        !          1895:        struct sockaddr_in6 rip6src;
        !          1896:        struct icmp6_hdr *icmp6;
        !          1897:        struct mbuf *opts = NULL;
        !          1898:
        !          1899:        IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
        !          1900:        if (icmp6 == NULL) {
        !          1901:                /* m is already reclaimed */
        !          1902:                return IPPROTO_DONE;
        !          1903:        }
        !          1904:
        !          1905:        bzero(&rip6src, sizeof(rip6src));
        !          1906:        rip6src.sin6_len = sizeof(struct sockaddr_in6);
        !          1907:        rip6src.sin6_family = AF_INET6;
        !          1908:        /* KAME hack: recover scopeid */
        !          1909:        (void)in6_recoverscope(&rip6src, &ip6->ip6_src, m->m_pkthdr.rcvif);
        !          1910:
        !          1911:        CIRCLEQ_FOREACH(in6p, &rawin6pcbtable.inpt_queue, inp_queue) {
        !          1912:                if (!(in6p->in6p_flags & INP_IPV6))
        !          1913:                        continue;
        !          1914:                if (in6p->in6p_ip6_nxt != IPPROTO_ICMPV6)
        !          1915:                        continue;
        !          1916:                if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
        !          1917:                   !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
        !          1918:                        continue;
        !          1919:                if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
        !          1920:                   !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
        !          1921:                        continue;
        !          1922:                if (in6p->in6p_icmp6filt
        !          1923:                    && ICMP6_FILTER_WILLBLOCK(icmp6->icmp6_type,
        !          1924:                                 in6p->in6p_icmp6filt))
        !          1925:                        continue;
        !          1926:                if (last) {
        !          1927:                        struct  mbuf *n;
        !          1928:                        if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
        !          1929:                                if (last->in6p_flags & IN6P_CONTROLOPTS)
        !          1930:                                        ip6_savecontrol(last, n, &opts);
        !          1931:                                /* strip intermediate headers */
        !          1932:                                m_adj(n, off);
        !          1933:                                if (sbappendaddr(&last->in6p_socket->so_rcv,
        !          1934:                                                 (struct sockaddr *)&rip6src,
        !          1935:                                                 n, opts) == 0) {
        !          1936:                                        /* should notify about lost packet */
        !          1937:                                        m_freem(n);
        !          1938:                                        if (opts)
        !          1939:                                                m_freem(opts);
        !          1940:                                } else
        !          1941:                                        sorwakeup(last->in6p_socket);
        !          1942:                                opts = NULL;
        !          1943:                        }
        !          1944:                }
        !          1945:                last = in6p;
        !          1946:        }
        !          1947:        if (last) {
        !          1948:                if (last->in6p_flags & IN6P_CONTROLOPTS)
        !          1949:                        ip6_savecontrol(last, m, &opts);
        !          1950:                /* strip intermediate headers */
        !          1951:                m_adj(m, off);
        !          1952:                if (sbappendaddr(&last->in6p_socket->so_rcv,
        !          1953:                                 (struct sockaddr *)&rip6src,
        !          1954:                                 m, opts) == 0) {
        !          1955:                        m_freem(m);
        !          1956:                        if (opts)
        !          1957:                                m_freem(opts);
        !          1958:                } else
        !          1959:                        sorwakeup(last->in6p_socket);
        !          1960:        } else {
        !          1961:                m_freem(m);
        !          1962:                ip6stat.ip6s_delivered--;
        !          1963:        }
        !          1964:        return IPPROTO_DONE;
        !          1965: }
        !          1966:
        !          1967: /*
        !          1968:  * Reflect the ip6 packet back to the source.
        !          1969:  * OFF points to the icmp6 header, counted from the top of the mbuf.
        !          1970:  *
        !          1971:  * Note: RFC 1885 required that an echo reply should be truncated if it
        !          1972:  * did not fit in with (return) path MTU, and KAME code supported the
        !          1973:  * behavior.  However, as a clarification after the RFC, this limitation
        !          1974:  * was removed in a revised version of the spec, RFC 2463.  We had kept the
        !          1975:  * old behavior, with a (non-default) ifdef block, while the new version of
        !          1976:  * the spec was an internet-draft status, and even after the new RFC was
        !          1977:  * published.  But it would rather make sense to clean the obsoleted part
        !          1978:  * up, and to make the code simpler at this stage.
        !          1979:  */
        !          1980: void
        !          1981: icmp6_reflect(m, off)
        !          1982:        struct  mbuf *m;
        !          1983:        size_t off;
        !          1984: {
        !          1985:        struct ip6_hdr *ip6;
        !          1986:        struct icmp6_hdr *icmp6;
        !          1987:        struct in6_ifaddr *ia;
        !          1988:        struct in6_addr t, *src = 0;
        !          1989:        int plen;
        !          1990:        int type, code;
        !          1991:        struct ifnet *outif = NULL;
        !          1992:        struct sockaddr_in6 sa6_src, sa6_dst;
        !          1993:
        !          1994:        /* too short to reflect */
        !          1995:        if (off < sizeof(struct ip6_hdr)) {
        !          1996:                nd6log((LOG_DEBUG,
        !          1997:                    "sanity fail: off=%lx, sizeof(ip6)=%lx in %s:%d\n",
        !          1998:                    (u_long)off, (u_long)sizeof(struct ip6_hdr),
        !          1999:                    __FILE__, __LINE__));
        !          2000:                goto bad;
        !          2001:        }
        !          2002:
        !          2003:        /*
        !          2004:         * If there are extra headers between IPv6 and ICMPv6, strip
        !          2005:         * off that header first.
        !          2006:         */
        !          2007: #ifdef DIAGNOSTIC
        !          2008:        if (sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) > MHLEN)
        !          2009:                panic("assumption failed in icmp6_reflect");
        !          2010: #endif
        !          2011:        if (off > sizeof(struct ip6_hdr)) {
        !          2012:                size_t l;
        !          2013:                struct ip6_hdr nip6;
        !          2014:
        !          2015:                l = off - sizeof(struct ip6_hdr);
        !          2016:                m_copydata(m, 0, sizeof(nip6), (caddr_t)&nip6);
        !          2017:                m_adj(m, l);
        !          2018:                l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
        !          2019:                if (m->m_len < l) {
        !          2020:                        if ((m = m_pullup(m, l)) == NULL)
        !          2021:                                return;
        !          2022:                }
        !          2023:                bcopy((caddr_t)&nip6, mtod(m, caddr_t), sizeof(nip6));
        !          2024:        } else /* off == sizeof(struct ip6_hdr) */ {
        !          2025:                size_t l;
        !          2026:                l = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
        !          2027:                if (m->m_len < l) {
        !          2028:                        if ((m = m_pullup(m, l)) == NULL)
        !          2029:                                return;
        !          2030:                }
        !          2031:        }
        !          2032:        plen = m->m_pkthdr.len - sizeof(struct ip6_hdr);
        !          2033:        ip6 = mtod(m, struct ip6_hdr *);
        !          2034:        ip6->ip6_nxt = IPPROTO_ICMPV6;
        !          2035:        icmp6 = (struct icmp6_hdr *)(ip6 + 1);
        !          2036:        type = icmp6->icmp6_type; /* keep type for statistics */
        !          2037:        code = icmp6->icmp6_code; /* ditto. */
        !          2038:
        !          2039:        t = ip6->ip6_dst;
        !          2040:        /*
        !          2041:         * ip6_input() drops a packet if its src is multicast.
        !          2042:         * So, the src is never multicast.
        !          2043:         */
        !          2044:        ip6->ip6_dst = ip6->ip6_src;
        !          2045:
        !          2046:        /*
        !          2047:         * XXX: make sure to embed scope zone information, using
        !          2048:         * already embedded IDs or the received interface (if any).
        !          2049:         * Note that rcvif may be NULL.
        !          2050:         * TODO: scoped routing case (XXX).
        !          2051:         */
        !          2052:        bzero(&sa6_src, sizeof(sa6_src));
        !          2053:        sa6_src.sin6_family = AF_INET6;
        !          2054:        sa6_src.sin6_len = sizeof(sa6_src);
        !          2055:        sa6_src.sin6_addr = ip6->ip6_dst;
        !          2056:        in6_recoverscope(&sa6_src, &ip6->ip6_dst, m->m_pkthdr.rcvif);
        !          2057:        in6_embedscope(&ip6->ip6_dst, &sa6_src, NULL, NULL);
        !          2058:        bzero(&sa6_dst, sizeof(sa6_dst));
        !          2059:        sa6_dst.sin6_family = AF_INET6;
        !          2060:        sa6_dst.sin6_len = sizeof(sa6_dst);
        !          2061:        sa6_dst.sin6_addr = t;
        !          2062:        in6_recoverscope(&sa6_dst, &t, m->m_pkthdr.rcvif);
        !          2063:        in6_embedscope(&t, &sa6_dst, NULL, NULL);
        !          2064:
        !          2065:        /*
        !          2066:         * If the incoming packet was addressed directly to us (i.e. unicast),
        !          2067:         * use dst as the src for the reply.
        !          2068:         * The IN6_IFF_NOTREADY case would be VERY rare, but is possible
        !          2069:         * (for example) when we encounter an error while forwarding procedure
        !          2070:         * destined to a duplicated address of ours.
        !          2071:         */
        !          2072:        for (ia = in6_ifaddr; ia; ia = ia->ia_next)
        !          2073:                if (IN6_ARE_ADDR_EQUAL(&t, &ia->ia_addr.sin6_addr) &&
        !          2074:                    (ia->ia6_flags & (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0) {
        !          2075:                        src = &t;
        !          2076:                        break;
        !          2077:                }
        !          2078:        if (ia == NULL && IN6_IS_ADDR_LINKLOCAL(&t) && (m->m_flags & M_LOOP)) {
        !          2079:                /*
        !          2080:                 * This is the case if the dst is our link-local address
        !          2081:                 * and the sender is also ourselves.
        !          2082:                 */
        !          2083:                src = &t;
        !          2084:        }
        !          2085:
        !          2086:        if (src == 0) {
        !          2087:                int e;
        !          2088:                struct route_in6 ro;
        !          2089:
        !          2090:                /*
        !          2091:                 * This case matches to multicasts, our anycast, or unicasts
        !          2092:                 * that we do not own.  Select a source address based on the
        !          2093:                 * source address of the erroneous packet.
        !          2094:                 */
        !          2095:                bzero(&ro, sizeof(ro));
        !          2096:                src = in6_selectsrc(&sa6_src, NULL, NULL, &ro, NULL, &e);
        !          2097:                if (ro.ro_rt) { /* XXX: see comments in icmp6_mtudisc_update */
        !          2098:                        RTFREE(ro.ro_rt); /* XXX: we could use this */
        !          2099:                }
        !          2100:                if (src == NULL) {
        !          2101:                        nd6log((LOG_DEBUG,
        !          2102:                            "icmp6_reflect: source can't be determined: "
        !          2103:                            "dst=%s, error=%d\n",
        !          2104:                            ip6_sprintf(&sa6_src.sin6_addr), e));
        !          2105:                        goto bad;
        !          2106:                }
        !          2107:        }
        !          2108:
        !          2109:        ip6->ip6_src = *src;
        !          2110:
        !          2111:        ip6->ip6_flow = 0;
        !          2112:        ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
        !          2113:        ip6->ip6_vfc |= IPV6_VERSION;
        !          2114:        ip6->ip6_nxt = IPPROTO_ICMPV6;
        !          2115:        if (m->m_pkthdr.rcvif) {
        !          2116:                /* XXX: This may not be the outgoing interface */
        !          2117:                ip6->ip6_hlim = ND_IFINFO(m->m_pkthdr.rcvif)->chlim;
        !          2118:        } else
        !          2119:                ip6->ip6_hlim = ip6_defhlim;
        !          2120:
        !          2121:        icmp6->icmp6_cksum = 0;
        !          2122:        icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6,
        !          2123:                                        sizeof(struct ip6_hdr), plen);
        !          2124:
        !          2125:        /*
        !          2126:         * XXX option handling
        !          2127:         */
        !          2128:
        !          2129:        m->m_flags &= ~(M_BCAST|M_MCAST);
        !          2130:
        !          2131:        /*
        !          2132:         * To avoid a "too big" situation at an intermediate router
        !          2133:         * and the path MTU discovery process, specify the IPV6_MINMTU flag.
        !          2134:         * Note that only echo and node information replies are affected,
        !          2135:         * since the length of ICMP6 errors is limited to the minimum MTU.
        !          2136:         */
        !          2137:        if (ip6_output(m, NULL, NULL, IPV6_MINMTU, NULL, &outif, NULL) != 0 &&
        !          2138:            outif)
        !          2139:                icmp6_ifstat_inc(outif, ifs6_out_error);
        !          2140:
        !          2141:        if (outif)
        !          2142:                icmp6_ifoutstat_inc(outif, type, code);
        !          2143:
        !          2144:        return;
        !          2145:
        !          2146:  bad:
        !          2147:        m_freem(m);
        !          2148:        return;
        !          2149: }
        !          2150:
        !          2151: void
        !          2152: icmp6_fasttimo()
        !          2153: {
        !          2154:
        !          2155:        mld6_fasttimeo();
        !          2156: }
        !          2157:
        !          2158: static const char *
        !          2159: icmp6_redirect_diag(src6, dst6, tgt6)
        !          2160:        struct in6_addr *src6;
        !          2161:        struct in6_addr *dst6;
        !          2162:        struct in6_addr *tgt6;
        !          2163: {
        !          2164:        static char buf[1024];
        !          2165:        snprintf(buf, sizeof(buf), "(src=%s dst=%s tgt=%s)",
        !          2166:                 ip6_sprintf(src6), ip6_sprintf(dst6), ip6_sprintf(tgt6));
        !          2167:        return buf;
        !          2168: }
        !          2169:
        !          2170: void
        !          2171: icmp6_redirect_input(m, off)
        !          2172:        struct mbuf *m;
        !          2173:        int off;
        !          2174: {
        !          2175:        struct ifnet *ifp = m->m_pkthdr.rcvif;
        !          2176:        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
        !          2177:        struct nd_redirect *nd_rd;
        !          2178:        int icmp6len = ntohs(ip6->ip6_plen);
        !          2179:        char *lladdr = NULL;
        !          2180:        int lladdrlen = 0;
        !          2181:        u_char *redirhdr = NULL;
        !          2182:        int redirhdrlen = 0;
        !          2183:        struct rtentry *rt = NULL;
        !          2184:        int is_router;
        !          2185:        int is_onlink;
        !          2186:        struct in6_addr src6 = ip6->ip6_src;
        !          2187:        struct in6_addr redtgt6;
        !          2188:        struct in6_addr reddst6;
        !          2189:        union nd_opts ndopts;
        !          2190:
        !          2191:        if (!ifp)
        !          2192:                return;
        !          2193:
        !          2194:        /* XXX if we are router, we don't update route by icmp6 redirect */
        !          2195:        if (ip6_forwarding)
        !          2196:                goto freeit;
        !          2197:        if (!icmp6_rediraccept)
        !          2198:                goto freeit;
        !          2199:
        !          2200:        IP6_EXTHDR_GET(nd_rd, struct nd_redirect *, m, off, icmp6len);
        !          2201:        if (nd_rd == NULL) {
        !          2202:                icmp6stat.icp6s_tooshort++;
        !          2203:                return;
        !          2204:        }
        !          2205:        redtgt6 = nd_rd->nd_rd_target;
        !          2206:        reddst6 = nd_rd->nd_rd_dst;
        !          2207:
        !          2208:        if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
        !          2209:                redtgt6.s6_addr16[1] = htons(ifp->if_index);
        !          2210:        if (IN6_IS_ADDR_LINKLOCAL(&reddst6))
        !          2211:                reddst6.s6_addr16[1] = htons(ifp->if_index);
        !          2212:
        !          2213:        /* validation */
        !          2214:        if (!IN6_IS_ADDR_LINKLOCAL(&src6)) {
        !          2215:                nd6log((LOG_ERR,
        !          2216:                        "ICMP6 redirect sent from %s rejected; "
        !          2217:                        "must be from linklocal\n", ip6_sprintf(&src6)));
        !          2218:                goto bad;
        !          2219:        }
        !          2220:        if (ip6->ip6_hlim != 255) {
        !          2221:                nd6log((LOG_ERR,
        !          2222:                        "ICMP6 redirect sent from %s rejected; "
        !          2223:                        "hlim=%d (must be 255)\n",
        !          2224:                        ip6_sprintf(&src6), ip6->ip6_hlim));
        !          2225:                goto bad;
        !          2226:        }
        !          2227:     {
        !          2228:        /* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */
        !          2229:        struct sockaddr_in6 sin6;
        !          2230:        struct in6_addr *gw6;
        !          2231:
        !          2232:        bzero(&sin6, sizeof(sin6));
        !          2233:        sin6.sin6_family = AF_INET6;
        !          2234:        sin6.sin6_len = sizeof(struct sockaddr_in6);
        !          2235:        bcopy(&reddst6, &sin6.sin6_addr, sizeof(reddst6));
        !          2236:        rt = rtalloc1((struct sockaddr *)&sin6, 0, 0);
        !          2237:        if (rt) {
        !          2238:                if (rt->rt_gateway == NULL ||
        !          2239:                    rt->rt_gateway->sa_family != AF_INET6) {
        !          2240:                        nd6log((LOG_ERR,
        !          2241:                            "ICMP6 redirect rejected; no route "
        !          2242:                            "with inet6 gateway found for redirect dst: %s\n",
        !          2243:                            icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
        !          2244:                        RTFREE(rt);
        !          2245:                        goto bad;
        !          2246:                }
        !          2247:
        !          2248:                gw6 = &(((struct sockaddr_in6 *)rt->rt_gateway)->sin6_addr);
        !          2249:                if (bcmp(&src6, gw6, sizeof(struct in6_addr)) != 0) {
        !          2250:                        nd6log((LOG_ERR,
        !          2251:                                "ICMP6 redirect rejected; "
        !          2252:                                "not equal to gw-for-src=%s (must be same): "
        !          2253:                                "%s\n",
        !          2254:                                ip6_sprintf(gw6),
        !          2255:                                icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
        !          2256:                        RTFREE(rt);
        !          2257:                        goto bad;
        !          2258:                }
        !          2259:        } else {
        !          2260:                nd6log((LOG_ERR,
        !          2261:                        "ICMP6 redirect rejected; "
        !          2262:                        "no route found for redirect dst: %s\n",
        !          2263:                        icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
        !          2264:                goto bad;
        !          2265:        }
        !          2266:        RTFREE(rt);
        !          2267:        rt = NULL;
        !          2268:     }
        !          2269:        if (IN6_IS_ADDR_MULTICAST(&reddst6)) {
        !          2270:                nd6log((LOG_ERR,
        !          2271:                        "ICMP6 redirect rejected; "
        !          2272:                        "redirect dst must be unicast: %s\n",
        !          2273:                        icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
        !          2274:                goto bad;
        !          2275:        }
        !          2276:
        !          2277:        is_router = is_onlink = 0;
        !          2278:        if (IN6_IS_ADDR_LINKLOCAL(&redtgt6))
        !          2279:                is_router = 1;  /* router case */
        !          2280:        if (bcmp(&redtgt6, &reddst6, sizeof(redtgt6)) == 0)
        !          2281:                is_onlink = 1;  /* on-link destination case */
        !          2282:        if (!is_router && !is_onlink) {
        !          2283:                nd6log((LOG_ERR,
        !          2284:                        "ICMP6 redirect rejected; "
        !          2285:                        "neither router case nor onlink case: %s\n",
        !          2286:                        icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
        !          2287:                goto bad;
        !          2288:        }
        !          2289:        /* validation passed */
        !          2290:
        !          2291:        icmp6len -= sizeof(*nd_rd);
        !          2292:        nd6_option_init(nd_rd + 1, icmp6len, &ndopts);
        !          2293:        if (nd6_options(&ndopts) < 0) {
        !          2294:                nd6log((LOG_INFO, "icmp6_redirect_input: "
        !          2295:                        "invalid ND option, rejected: %s\n",
        !          2296:                        icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
        !          2297:                /* nd6_options have incremented stats */
        !          2298:                goto freeit;
        !          2299:        }
        !          2300:
        !          2301:        if (ndopts.nd_opts_tgt_lladdr) {
        !          2302:                lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
        !          2303:                lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
        !          2304:        }
        !          2305:
        !          2306:        if (ndopts.nd_opts_rh) {
        !          2307:                redirhdrlen = ndopts.nd_opts_rh->nd_opt_rh_len;
        !          2308:                redirhdr = (u_char *)(ndopts.nd_opts_rh + 1); /* xxx */
        !          2309:        }
        !          2310:
        !          2311:        if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
        !          2312:                nd6log((LOG_INFO,
        !          2313:                        "icmp6_redirect_input: lladdrlen mismatch for %s "
        !          2314:                        "(if %d, icmp6 packet %d): %s\n",
        !          2315:                        ip6_sprintf(&redtgt6), ifp->if_addrlen, lladdrlen - 2,
        !          2316:                        icmp6_redirect_diag(&src6, &reddst6, &redtgt6)));
        !          2317:                goto bad;
        !          2318:        }
        !          2319:
        !          2320:        /* RFC 2461 8.3 */
        !          2321:        nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT,
        !          2322:                         is_onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER);
        !          2323:
        !          2324:        if (!is_onlink) {       /* better router case.  perform rtredirect. */
        !          2325:                /* perform rtredirect */
        !          2326:                struct sockaddr_in6 sdst;
        !          2327:                struct sockaddr_in6 sgw;
        !          2328:                struct sockaddr_in6 ssrc;
        !          2329:                unsigned long rtcount;
        !          2330:                struct rtentry *newrt = NULL;
        !          2331:
        !          2332:                /*
        !          2333:                 * do not install redirect route, if the number of entries
        !          2334:                 * is too much (> hiwat).  note that, the node (= host) will
        !          2335:                 * work just fine even if we do not install redirect route
        !          2336:                 * (there will be additional hops, though).
        !          2337:                 */
        !          2338:                rtcount = rt_timer_count(icmp6_redirect_timeout_q);
        !          2339:                if (0 <= icmp6_redirect_hiwat && rtcount > icmp6_redirect_hiwat)
        !          2340:                        return;
        !          2341:                else if (0 <= icmp6_redirect_lowat &&
        !          2342:                    rtcount > icmp6_redirect_lowat) {
        !          2343:                        /*
        !          2344:                         * XXX nuke a victim, install the new one.
        !          2345:                         */
        !          2346:                }
        !          2347:
        !          2348:                bzero(&sdst, sizeof(sdst));
        !          2349:                bzero(&sgw, sizeof(sgw));
        !          2350:                bzero(&ssrc, sizeof(ssrc));
        !          2351:                sdst.sin6_family = sgw.sin6_family = ssrc.sin6_family = AF_INET6;
        !          2352:                sdst.sin6_len = sgw.sin6_len = ssrc.sin6_len =
        !          2353:                        sizeof(struct sockaddr_in6);
        !          2354:                bcopy(&redtgt6, &sgw.sin6_addr, sizeof(struct in6_addr));
        !          2355:                bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
        !          2356:                bcopy(&src6, &ssrc.sin6_addr, sizeof(struct in6_addr));
        !          2357:                rtredirect((struct sockaddr *)&sdst, (struct sockaddr *)&sgw,
        !          2358:                           (struct sockaddr *)NULL, RTF_GATEWAY | RTF_HOST,
        !          2359:                           (struct sockaddr *)&ssrc,
        !          2360:                           &newrt);
        !          2361:
        !          2362:                if (newrt) {
        !          2363:                        (void)rt_timer_add(newrt, icmp6_redirect_timeout,
        !          2364:                            icmp6_redirect_timeout_q);
        !          2365:                        rtfree(newrt);
        !          2366:                }
        !          2367:        }
        !          2368:        /* finally update cached route in each socket via pfctlinput */
        !          2369:        {
        !          2370:                struct sockaddr_in6 sdst;
        !          2371:
        !          2372:                bzero(&sdst, sizeof(sdst));
        !          2373:                sdst.sin6_family = AF_INET6;
        !          2374:                sdst.sin6_len = sizeof(struct sockaddr_in6);
        !          2375:                bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
        !          2376:                pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst);
        !          2377:        }
        !          2378:
        !          2379:  freeit:
        !          2380:        m_freem(m);
        !          2381:        return;
        !          2382:
        !          2383:  bad:
        !          2384:        icmp6stat.icp6s_badredirect++;
        !          2385:        m_freem(m);
        !          2386: }
        !          2387:
        !          2388: void
        !          2389: icmp6_redirect_output(m0, rt)
        !          2390:        struct mbuf *m0;
        !          2391:        struct rtentry *rt;
        !          2392: {
        !          2393:        struct ifnet *ifp;      /* my outgoing interface */
        !          2394:        struct in6_addr *ifp_ll6;
        !          2395:        struct in6_addr *nexthop;
        !          2396:        struct ip6_hdr *sip6;   /* m0 as struct ip6_hdr */
        !          2397:        struct mbuf *m = NULL;  /* newly allocated one */
        !          2398:        struct ip6_hdr *ip6;    /* m as struct ip6_hdr */
        !          2399:        struct nd_redirect *nd_rd;
        !          2400:        size_t maxlen;
        !          2401:        u_char *p;
        !          2402:        struct sockaddr_in6 src_sa;
        !          2403:
        !          2404:        icmp6_errcount(&icmp6stat.icp6s_outerrhist, ND_REDIRECT, 0);
        !          2405:
        !          2406:        /* if we are not router, we don't send icmp6 redirect */
        !          2407:        if (!ip6_forwarding)
        !          2408:                goto fail;
        !          2409:
        !          2410:        /* sanity check */
        !          2411:        if (!m0 || !rt || !(rt->rt_flags & RTF_UP) || !(ifp = rt->rt_ifp))
        !          2412:                goto fail;
        !          2413:
        !          2414:        /*
        !          2415:         * Address check:
        !          2416:         *  the source address must identify a neighbor, and
        !          2417:         *  the destination address must not be a multicast address
        !          2418:         *  [RFC 2461, sec 8.2]
        !          2419:         */
        !          2420:        sip6 = mtod(m0, struct ip6_hdr *);
        !          2421:        bzero(&src_sa, sizeof(src_sa));
        !          2422:        src_sa.sin6_family = AF_INET6;
        !          2423:        src_sa.sin6_len = sizeof(src_sa);
        !          2424:        src_sa.sin6_addr = sip6->ip6_src;
        !          2425:        /* we don't currently use sin6_scope_id, but eventually use it */
        !          2426:        src_sa.sin6_scope_id = in6_addr2scopeid(ifp, &sip6->ip6_src);
        !          2427:        if (nd6_is_addr_neighbor(&src_sa, ifp) == 0)
        !          2428:                goto fail;
        !          2429:        if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst))
        !          2430:                goto fail;      /* what should we do here? */
        !          2431:
        !          2432:        /* rate limit */
        !          2433:        if (icmp6_ratelimit(&sip6->ip6_src, ND_REDIRECT, 0))
        !          2434:                goto fail;
        !          2435:
        !          2436:        /*
        !          2437:         * Since we are going to append up to 1280 bytes (= IPV6_MMTU),
        !          2438:         * we almost always ask for an mbuf cluster for simplicity.
        !          2439:         * (MHLEN < IPV6_MMTU is almost always true)
        !          2440:         */
        !          2441: #if IPV6_MMTU >= MCLBYTES
        !          2442: # error assumption failed about IPV6_MMTU and MCLBYTES
        !          2443: #endif
        !          2444:        MGETHDR(m, M_DONTWAIT, MT_HEADER);
        !          2445:        if (m && IPV6_MMTU >= MHLEN)
        !          2446:                MCLGET(m, M_DONTWAIT);
        !          2447:        if (!m)
        !          2448:                goto fail;
        !          2449:        m->m_pkthdr.rcvif = NULL;
        !          2450:        m->m_len = 0;
        !          2451:        maxlen = M_TRAILINGSPACE(m);
        !          2452:        maxlen = min(IPV6_MMTU, maxlen);
        !          2453:        /* just for safety */
        !          2454:        if (maxlen < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) +
        !          2455:            ((sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7)) {
        !          2456:                goto fail;
        !          2457:        }
        !          2458:
        !          2459:        {
        !          2460:                /* get ip6 linklocal address for ifp(my outgoing interface). */
        !          2461:                struct in6_ifaddr *ia;
        !          2462:                if ((ia = in6ifa_ifpforlinklocal(ifp,
        !          2463:                                                 IN6_IFF_NOTREADY|
        !          2464:                                                 IN6_IFF_ANYCAST)) == NULL)
        !          2465:                        goto fail;
        !          2466:                ifp_ll6 = &ia->ia_addr.sin6_addr;
        !          2467:        }
        !          2468:
        !          2469:        /* get ip6 linklocal address for the router. */
        !          2470:        if (rt->rt_gateway && (rt->rt_flags & RTF_GATEWAY)) {
        !          2471:                struct sockaddr_in6 *sin6;
        !          2472:                sin6 = (struct sockaddr_in6 *)rt->rt_gateway;
        !          2473:                nexthop = &sin6->sin6_addr;
        !          2474:                if (!IN6_IS_ADDR_LINKLOCAL(nexthop))
        !          2475:                        nexthop = NULL;
        !          2476:        } else
        !          2477:                nexthop = NULL;
        !          2478:
        !          2479:        /* ip6 */
        !          2480:        ip6 = mtod(m, struct ip6_hdr *);
        !          2481:        ip6->ip6_flow = 0;
        !          2482:        ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
        !          2483:        ip6->ip6_vfc |= IPV6_VERSION;
        !          2484:        /* ip6->ip6_plen will be set later */
        !          2485:        ip6->ip6_nxt = IPPROTO_ICMPV6;
        !          2486:        ip6->ip6_hlim = 255;
        !          2487:        /* ip6->ip6_src must be linklocal addr for my outgoing if. */
        !          2488:        bcopy(ifp_ll6, &ip6->ip6_src, sizeof(struct in6_addr));
        !          2489:        bcopy(&sip6->ip6_src, &ip6->ip6_dst, sizeof(struct in6_addr));
        !          2490:
        !          2491:        /* ND Redirect */
        !          2492:        nd_rd = (struct nd_redirect *)(ip6 + 1);
        !          2493:        nd_rd->nd_rd_type = ND_REDIRECT;
        !          2494:        nd_rd->nd_rd_code = 0;
        !          2495:        nd_rd->nd_rd_reserved = 0;
        !          2496:        if (rt->rt_flags & RTF_GATEWAY) {
        !          2497:                /*
        !          2498:                 * nd_rd->nd_rd_target must be a link-local address in
        !          2499:                 * better router cases.
        !          2500:                 */
        !          2501:                if (!nexthop)
        !          2502:                        goto fail;
        !          2503:                bcopy(nexthop, &nd_rd->nd_rd_target,
        !          2504:                      sizeof(nd_rd->nd_rd_target));
        !          2505:                bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
        !          2506:                      sizeof(nd_rd->nd_rd_dst));
        !          2507:        } else {
        !          2508:                /* make sure redtgt == reddst */
        !          2509:                nexthop = &sip6->ip6_dst;
        !          2510:                bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_target,
        !          2511:                      sizeof(nd_rd->nd_rd_target));
        !          2512:                bcopy(&sip6->ip6_dst, &nd_rd->nd_rd_dst,
        !          2513:                      sizeof(nd_rd->nd_rd_dst));
        !          2514:        }
        !          2515:
        !          2516:        p = (u_char *)(nd_rd + 1);
        !          2517:
        !          2518:        {
        !          2519:                /* target lladdr option */
        !          2520:                struct rtentry *rt_nexthop = NULL;
        !          2521:                int len;
        !          2522:                struct sockaddr_dl *sdl;
        !          2523:                struct nd_opt_hdr *nd_opt;
        !          2524:                char *lladdr;
        !          2525:
        !          2526:                rt_nexthop = nd6_lookup(nexthop, 0, ifp);
        !          2527:                if (!rt_nexthop)
        !          2528:                        goto nolladdropt;
        !          2529:                len = sizeof(*nd_opt) + ifp->if_addrlen;
        !          2530:                len = (len + 7) & ~7;   /* round by 8 */
        !          2531:                /* safety check */
        !          2532:                if (len + (p - (u_char *)ip6) > maxlen)
        !          2533:                        goto nolladdropt;
        !          2534:                if (!(rt_nexthop->rt_flags & RTF_GATEWAY) &&
        !          2535:                    (rt_nexthop->rt_flags & RTF_LLINFO) &&
        !          2536:                    (rt_nexthop->rt_gateway->sa_family == AF_LINK) &&
        !          2537:                    (sdl = (struct sockaddr_dl *)rt_nexthop->rt_gateway) &&
        !          2538:                    sdl->sdl_alen) {
        !          2539:                        nd_opt = (struct nd_opt_hdr *)p;
        !          2540:                        nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
        !          2541:                        nd_opt->nd_opt_len = len >> 3;
        !          2542:                        lladdr = (char *)(nd_opt + 1);
        !          2543:                        bcopy(LLADDR(sdl), lladdr, ifp->if_addrlen);
        !          2544:                        p += len;
        !          2545:                }
        !          2546:        }
        !          2547:   nolladdropt:;
        !          2548:
        !          2549:        m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
        !          2550:
        !          2551:        /* just to be safe */
        !          2552:        if (p - (u_char *)ip6 > maxlen)
        !          2553:                goto noredhdropt;
        !          2554:
        !          2555:        {
        !          2556:                /* redirected header option */
        !          2557:                int len;
        !          2558:                struct nd_opt_rd_hdr *nd_opt_rh;
        !          2559:
        !          2560:                /*
        !          2561:                 * compute the maximum size for icmp6 redirect header option.
        !          2562:                 * XXX room for auth header?
        !          2563:                 */
        !          2564:                len = maxlen - (p - (u_char *)ip6);
        !          2565:                len &= ~7;
        !          2566:
        !          2567:                /*
        !          2568:                 * Redirected header option spec (RFC2461 4.6.3) talks nothing
        !          2569:                 * about padding/truncate rule for the original IP packet.
        !          2570:                 * From the discussion on IPv6imp in Feb 1999,
        !          2571:                 * the consensus was:
        !          2572:                 * - "attach as much as possible" is the goal
        !          2573:                 * - pad if not aligned (original size can be guessed by
        !          2574:                 *   original ip6 header)
        !          2575:                 * Following code adds the padding if it is simple enough,
        !          2576:                 * and truncates if not.
        !          2577:                 */
        !          2578:                if (len - sizeof(*nd_opt_rh) < m0->m_pkthdr.len) {
        !          2579:                        /* not enough room, truncate */
        !          2580:                        m_adj(m0, (len - sizeof(*nd_opt_rh)) -
        !          2581:                            m0->m_pkthdr.len);
        !          2582:                } else {
        !          2583:                        /*
        !          2584:                         * enough room, truncate if not aligned.
        !          2585:                         * we don't pad here for simplicity.
        !          2586:                         */
        !          2587:                        size_t extra;
        !          2588:
        !          2589:                        extra = m0->m_pkthdr.len % 8;
        !          2590:                        if (extra) {
        !          2591:                                /* truncate */
        !          2592:                                m_adj(m0, -extra);
        !          2593:                        }
        !          2594:                        len = m0->m_pkthdr.len + sizeof(*nd_opt_rh);
        !          2595:                }
        !          2596:
        !          2597:                nd_opt_rh = (struct nd_opt_rd_hdr *)p;
        !          2598:                bzero(nd_opt_rh, sizeof(*nd_opt_rh));
        !          2599:                nd_opt_rh->nd_opt_rh_type = ND_OPT_REDIRECTED_HEADER;
        !          2600:                nd_opt_rh->nd_opt_rh_len = len >> 3;
        !          2601:                p += sizeof(*nd_opt_rh);
        !          2602:                m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
        !          2603:
        !          2604:                /* connect m0 to m */
        !          2605:                m->m_pkthdr.len += m0->m_pkthdr.len;
        !          2606:                m_cat(m, m0);
        !          2607:                m0 = NULL;
        !          2608:        }
        !          2609: noredhdropt:
        !          2610:        if (m0) {
        !          2611:                m_freem(m0);
        !          2612:                m0 = NULL;
        !          2613:        }
        !          2614:
        !          2615:        sip6 = mtod(m, struct ip6_hdr *);
        !          2616:        if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_src))
        !          2617:                sip6->ip6_src.s6_addr16[1] = 0;
        !          2618:        if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_dst))
        !          2619:                sip6->ip6_dst.s6_addr16[1] = 0;
        !          2620: #if 0
        !          2621:        if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src))
        !          2622:                ip6->ip6_src.s6_addr16[1] = 0;
        !          2623:        if (IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst))
        !          2624:                ip6->ip6_dst.s6_addr16[1] = 0;
        !          2625: #endif
        !          2626:        if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_target))
        !          2627:                nd_rd->nd_rd_target.s6_addr16[1] = 0;
        !          2628:        if (IN6_IS_ADDR_LINKLOCAL(&nd_rd->nd_rd_dst))
        !          2629:                nd_rd->nd_rd_dst.s6_addr16[1] = 0;
        !          2630:
        !          2631:        ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
        !          2632:
        !          2633:        nd_rd->nd_rd_cksum = 0;
        !          2634:        nd_rd->nd_rd_cksum
        !          2635:                = in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), ntohs(ip6->ip6_plen));
        !          2636:
        !          2637:        /* send the packet to outside... */
        !          2638:        if (ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL) != 0)
        !          2639:                icmp6_ifstat_inc(ifp, ifs6_out_error);
        !          2640:
        !          2641:        icmp6_ifstat_inc(ifp, ifs6_out_msg);
        !          2642:        icmp6_ifstat_inc(ifp, ifs6_out_redirect);
        !          2643:        icmp6stat.icp6s_outhist[ND_REDIRECT]++;
        !          2644:
        !          2645:        return;
        !          2646:
        !          2647: fail:
        !          2648:        if (m)
        !          2649:                m_freem(m);
        !          2650:        if (m0)
        !          2651:                m_freem(m0);
        !          2652: }
        !          2653:
        !          2654: /* NRL PCB */
        !          2655: #define sotoin6pcb     sotoinpcb
        !          2656: #define in6pcb         inpcb
        !          2657: #define in6p_icmp6filt inp_icmp6filt
        !          2658:
        !          2659: /*
        !          2660:  * ICMPv6 socket option processing.
        !          2661:  */
        !          2662: int
        !          2663: icmp6_ctloutput(op, so, level, optname, mp)
        !          2664:        int op;
        !          2665:        struct socket *so;
        !          2666:        int level, optname;
        !          2667:        struct mbuf **mp;
        !          2668: {
        !          2669:        int error = 0;
        !          2670:        int optlen;
        !          2671:        struct in6pcb *in6p = sotoin6pcb(so);
        !          2672:        struct mbuf *m = *mp;
        !          2673:
        !          2674:        optlen = m ? m->m_len : 0;
        !          2675:
        !          2676:        if (level != IPPROTO_ICMPV6) {
        !          2677:                if (op == PRCO_SETOPT && m)
        !          2678:                        (void)m_free(m);
        !          2679:                return EINVAL;
        !          2680:        }
        !          2681:
        !          2682:        switch (op) {
        !          2683:        case PRCO_SETOPT:
        !          2684:                switch (optname) {
        !          2685:                case ICMP6_FILTER:
        !          2686:                    {
        !          2687:                        struct icmp6_filter *p;
        !          2688:
        !          2689:                        if (optlen != sizeof(*p)) {
        !          2690:                                error = EMSGSIZE;
        !          2691:                                break;
        !          2692:                        }
        !          2693:                        p = mtod(m, struct icmp6_filter *);
        !          2694:                        if (!p || !in6p->in6p_icmp6filt) {
        !          2695:                                error = EINVAL;
        !          2696:                                break;
        !          2697:                        }
        !          2698:                        bcopy(p, in6p->in6p_icmp6filt,
        !          2699:                                sizeof(struct icmp6_filter));
        !          2700:                        error = 0;
        !          2701:                        break;
        !          2702:                    }
        !          2703:
        !          2704:                default:
        !          2705:                        error = ENOPROTOOPT;
        !          2706:                        break;
        !          2707:                }
        !          2708:                if (m)
        !          2709:                        (void)m_freem(m);
        !          2710:                break;
        !          2711:
        !          2712:        case PRCO_GETOPT:
        !          2713:                switch (optname) {
        !          2714:                case ICMP6_FILTER:
        !          2715:                    {
        !          2716:                        struct icmp6_filter *p;
        !          2717:
        !          2718:                        if (!in6p->in6p_icmp6filt) {
        !          2719:                                error = EINVAL;
        !          2720:                                break;
        !          2721:                        }
        !          2722:                        *mp = m = m_get(M_WAIT, MT_SOOPTS);
        !          2723:                        m->m_len = sizeof(struct icmp6_filter);
        !          2724:                        p = mtod(m, struct icmp6_filter *);
        !          2725:                        bcopy(in6p->in6p_icmp6filt, p,
        !          2726:                                sizeof(struct icmp6_filter));
        !          2727:                        error = 0;
        !          2728:                        break;
        !          2729:                    }
        !          2730:
        !          2731:                default:
        !          2732:                        error = ENOPROTOOPT;
        !          2733:                        break;
        !          2734:                }
        !          2735:                break;
        !          2736:        }
        !          2737:
        !          2738:        return (error);
        !          2739: }
        !          2740:
        !          2741: /* NRL PCB */
        !          2742: #undef sotoin6pcb
        !          2743: #undef in6pcb
        !          2744: #undef in6p_icmp6filt
        !          2745:
        !          2746: /*
        !          2747:  * Perform rate limit check.
        !          2748:  * Returns 0 if it is okay to send the icmp6 packet.
        !          2749:  * Returns 1 if the router SHOULD NOT send this icmp6 packet due to rate
        !          2750:  * limitation.
        !          2751:  *
        !          2752:  * XXX per-destination/type check necessary?
        !          2753:  */
        !          2754: static int
        !          2755: icmp6_ratelimit(dst, type, code)
        !          2756:        const struct in6_addr *dst;     /* not used at this moment */
        !          2757:        const int type;                 /* not used at this moment */
        !          2758:        const int code;                 /* not used at this moment */
        !          2759: {
        !          2760:        int ret;
        !          2761:
        !          2762:        ret = 0;        /* okay to send */
        !          2763:
        !          2764:        /* PPS limit */
        !          2765:        if (!ppsratecheck(&icmp6errppslim_last, &icmp6errpps_count,
        !          2766:            icmp6errppslim)) {
        !          2767:                /* The packet is subject to rate limit */
        !          2768:                ret++;
        !          2769:        }
        !          2770:
        !          2771:        return ret;
        !          2772: }
        !          2773:
        !          2774: static struct rtentry *
        !          2775: icmp6_mtudisc_clone(dst)
        !          2776:        struct sockaddr *dst;
        !          2777: {
        !          2778:        struct rtentry *rt;
        !          2779:        int    error;
        !          2780:
        !          2781:        rt = rtalloc1(dst, 1, 0);
        !          2782:        if (rt == 0)
        !          2783:                return NULL;
        !          2784:
        !          2785:        /* If we didn't get a host route, allocate one */
        !          2786:        if ((rt->rt_flags & RTF_HOST) == 0) {
        !          2787:                struct rtentry *nrt;
        !          2788:
        !          2789:                error = rtrequest((int) RTM_ADD, dst,
        !          2790:                    (struct sockaddr *) rt->rt_gateway,
        !          2791:                    (struct sockaddr *) 0,
        !          2792:                    RTF_GATEWAY | RTF_HOST | RTF_DYNAMIC, &nrt, 0);
        !          2793:                if (error) {
        !          2794:                        rtfree(rt);
        !          2795:                        return NULL;
        !          2796:                }
        !          2797:                nrt->rt_rmx = rt->rt_rmx;
        !          2798:                rtfree(rt);
        !          2799:                rt = nrt;
        !          2800:        }
        !          2801:        error = rt_timer_add(rt, icmp6_mtudisc_timeout,
        !          2802:                        icmp6_mtudisc_timeout_q);
        !          2803:        if (error) {
        !          2804:                rtfree(rt);
        !          2805:                return NULL;
        !          2806:        }
        !          2807:
        !          2808:        return rt;      /* caller need to call rtfree() */
        !          2809: }
        !          2810:
        !          2811: static void
        !          2812: icmp6_mtudisc_timeout(rt, r)
        !          2813:        struct rtentry *rt;
        !          2814:        struct rttimer *r;
        !          2815: {
        !          2816:        if (rt == NULL)
        !          2817:                panic("icmp6_mtudisc_timeout: bad route to timeout");
        !          2818:        if ((rt->rt_flags & (RTF_DYNAMIC | RTF_HOST)) ==
        !          2819:            (RTF_DYNAMIC | RTF_HOST)) {
        !          2820:                rtrequest((int) RTM_DELETE, (struct sockaddr *)rt_key(rt),
        !          2821:                    rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0, 0);
        !          2822:        } else {
        !          2823:                if (!(rt->rt_rmx.rmx_locks & RTV_MTU))
        !          2824:                        rt->rt_rmx.rmx_mtu = 0;
        !          2825:        }
        !          2826: }
        !          2827:
        !          2828: static void
        !          2829: icmp6_redirect_timeout(rt, r)
        !          2830:        struct rtentry *rt;
        !          2831:        struct rttimer *r;
        !          2832: {
        !          2833:        if (rt == NULL)
        !          2834:                panic("icmp6_redirect_timeout: bad route to timeout");
        !          2835:        if ((rt->rt_flags & (RTF_GATEWAY | RTF_DYNAMIC | RTF_HOST)) ==
        !          2836:            (RTF_GATEWAY | RTF_DYNAMIC | RTF_HOST)) {
        !          2837:                rtrequest((int) RTM_DELETE, (struct sockaddr *)rt_key(rt),
        !          2838:                    rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0, 0);
        !          2839:        }
        !          2840: }
        !          2841:
        !          2842: #include <uvm/uvm_extern.h>
        !          2843: #include <sys/sysctl.h>
        !          2844:
        !          2845: int *icmpv6ctl_vars[ICMPV6CTL_MAXID] = ICMPV6CTL_VARS;
        !          2846:
        !          2847: int
        !          2848: icmp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
        !          2849:        int *name;
        !          2850:        u_int namelen;
        !          2851:        void *oldp;
        !          2852:        size_t *oldlenp;
        !          2853:        void *newp;
        !          2854:        size_t newlen;
        !          2855: {
        !          2856:
        !          2857:        /* All sysctl names at this level are terminal. */
        !          2858:        if (namelen != 1)
        !          2859:                return ENOTDIR;
        !          2860:
        !          2861:        switch (name[0]) {
        !          2862:
        !          2863:        case ICMPV6CTL_STATS:
        !          2864:                return sysctl_rdstruct(oldp, oldlenp, newp,
        !          2865:                                &icmp6stat, sizeof(icmp6stat));
        !          2866:        case ICMPV6CTL_ND6_DRLIST:
        !          2867:        case ICMPV6CTL_ND6_PRLIST:
        !          2868:                return nd6_sysctl(name[0], oldp, oldlenp, newp, newlen);
        !          2869:        default:
        !          2870:                if (name[0] < ICMPV6CTL_MAXID)
        !          2871:                        return (sysctl_int_arr(icmpv6ctl_vars, name, namelen,
        !          2872:                            oldp, oldlenp, newp, newlen));
        !          2873:                return ENOPROTOOPT;
        !          2874:        }
        !          2875:        /* NOTREACHED */
        !          2876: }

CVSweb