[BACK]Return to icmp6.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / netinet6

Annotation of src/sys/netinet6/icmp6.c, Revision 1.33.2.2

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

CVSweb <webmaster@jp.NetBSD.org>